{
 "name": "NetNet recipes",
 "license": "MIT",
 "chain": {
  "id": 4663,
  "name": "Robinhood Chain",
  "rpc": "https://rpc.mainnet.chain.robinhood.com",
  "explorer": "https://robin.etherscan.io"
 },
 "howTo": "Each recipe lists its contract calls (address, calldata, decimals) and event filters (address, topic0, fromBlock), the formula and the steps. Run them with any Robinhood Chain RPC, or import netnet-recipes.mjs and call run(recipe, makeCtx()).",
 "code": {
  "bundle": "https://netnetintel.com/kit/netnet-recipes.mjs",
  "sources": "https://netnetintel.com/kit/src/"
 },
 "areas": [
  "Treasury",
  "Growth",
  "Buybacks",
  "Liquidity",
  "Bonds",
  "NET Advance",
  "Loop",
  "Holders",
  "Predict"
 ],
 "recipes": [
  {
   "id": "nav_core",
   "area": "Treasury",
   "label": "NAV per NET (core)",
   "unit": "USD per NET",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "backingPerToken",
     "contract": "Treasury",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "fn": "backingPerToken()",
     "data": "0x1521843e",
     "decimals": 18
    }
   ],
   "formula": "Treasury.backingPerToken()",
   "steps": [
    "eth_call each source at the same block",
    "decode the first 32-byte word ÷ 10^decimals",
    "apply: Treasury.backingPerToken()"
   ],
   "api": {
    "path": "/api/v1/net",
    "field": "nav"
   },
   "what": "What the contracts back each NET with: core reserves ÷ NET in issue."
  },
  {
   "id": "nav_core_check",
   "area": "Treasury",
   "label": "NAV per NET, from its parts",
   "unit": "USD per NET",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "rfv",
     "contract": "Treasury",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "fn": "rfv()",
     "data": "0x4dc8d6df",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "netSupply",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "fn": "totalSupply()",
     "data": "0x18160ddd",
     "decimals": 9
    }
   ],
   "formula": "Treasury.rfv() ÷ NET.totalSupply()",
   "steps": [
    "eth_call each source at the same block",
    "decode the first 32-byte word ÷ 10^decimals",
    "apply: Treasury.rfv() ÷ NET.totalSupply()"
   ],
   "what": "The same NAV recomputed: must equal backingPerToken()."
  },
  {
   "id": "rfv",
   "area": "Treasury",
   "label": "RFV (core reserves)",
   "unit": "USD",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "rfv",
     "contract": "Treasury",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "fn": "rfv()",
     "data": "0x4dc8d6df",
     "decimals": 18
    }
   ],
   "formula": "Treasury.rfv()",
   "steps": [
    "eth_call each source at the same block",
    "decode the first 32-byte word ÷ 10^decimals",
    "apply: Treasury.rfv()"
   ],
   "api": {
    "path": "/api/v1/nav",
    "field": "core.rfv"
   },
   "what": "Liquid USDG + the Morpho position after a 2% haircut + protocol-owned liquidity."
  },
  {
   "id": "rfv_parts",
   "area": "Treasury",
   "label": "RFV split into its parts",
   "unit": "USD",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "rfv",
     "contract": "Treasury",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "fn": "rfv()",
     "data": "0x4dc8d6df",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "liquidUsdg",
     "contract": "Treasury",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "fn": "liquidUsdg()",
     "data": "0x51f858fe",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "morphoAssets",
     "contract": "Treasury",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "fn": "morphoAssets()",
     "data": "0xae0fab7c",
     "decimals": 18
    }
   ],
   "formula": "liquid = liquidUsdg(); morpho = morphoAssets() × 0.98; POL = rfv() − liquid − morpho",
   "steps": [
    "eth_call each source at the same block",
    "decode the first 32-byte word ÷ 10^decimals",
    "apply: liquid = liquidUsdg(); morpho = morphoAssets() × 0.98; POL = rfv() − liquid − morpho"
   ],
   "what": "Where the core reserves sit.",
   "parts": true
  },
  {
   "id": "supply",
   "area": "Treasury",
   "label": "NET in issue",
   "unit": "NET",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "netSupply",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "fn": "totalSupply()",
     "data": "0x18160ddd",
     "decimals": 9
    }
   ],
   "formula": "NET.totalSupply()",
   "steps": [
    "eth_call each source at the same block",
    "decode the first 32-byte word ÷ 10^decimals",
    "apply: NET.totalSupply()"
   ],
   "api": {
    "path": "/api/v1/net",
    "field": "supply"
   },
   "what": "Every NET that exists, staked or not."
  },
  {
   "id": "price_twap",
   "area": "Treasury",
   "label": "Price (TWAP)",
   "unit": "USD per NET",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "twap",
     "contract": "PairOracle",
     "address": "0x929631b33F4070D6f54477fba3FD27566567dAca",
     "fn": "twapNetUsdg()",
     "data": "0x10aa790e",
     "decimals": 18
    }
   ],
   "formula": "PairOracle.twapNetUsdg()",
   "steps": [
    "eth_call each source at the same block",
    "decode the first 32-byte word ÷ 10^decimals",
    "apply: PairOracle.twapNetUsdg()"
   ],
   "api": {
    "path": "/api/v1/net",
    "field": "price"
   },
   "what": "The time-weighted NET/USDG price the protocol prices with (bonds, Advance, Loop oracle)."
  },
  {
   "id": "premium_core",
   "area": "Treasury",
   "label": "Premium to NAV",
   "unit": "×",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "twap",
     "contract": "PairOracle",
     "address": "0x929631b33F4070D6f54477fba3FD27566567dAca",
     "fn": "twapNetUsdg()",
     "data": "0x10aa790e",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "backingPerToken",
     "contract": "Treasury",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "fn": "backingPerToken()",
     "data": "0x1521843e",
     "decimals": 18
    }
   ],
   "formula": "twapNetUsdg() ÷ backingPerToken()",
   "steps": [
    "eth_call each source at the same block",
    "decode the first 32-byte word ÷ 10^decimals",
    "apply: twapNetUsdg() ÷ backingPerToken()"
   ],
   "api": {
    "path": "/api/v1/net",
    "field": "premium"
   },
   "what": "How far the price sits above what each NET is backed by: 1.20× means 20% above."
  },
  {
   "id": "staked",
   "area": "Treasury",
   "label": "NET staked and its share",
   "unit": "NET",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "totalStaked",
     "contract": "Staking",
     "address": "0xB078cc304A0B264C5F3680DC0488954ACcd02E87",
     "fn": "totalStaked()",
     "data": "0x817b1cd2",
     "decimals": 9
    },
    {
     "kind": "call",
     "name": "netSupply",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "fn": "totalSupply()",
     "data": "0x18160ddd",
     "decimals": 9
    }
   ],
   "formula": "Staking.totalStaked(); share = ÷ NET.totalSupply()",
   "steps": [
    "eth_call each source at the same block",
    "decode the first 32-byte word ÷ 10^decimals",
    "apply: Staking.totalStaked(); share = ÷ NET.totalSupply()"
   ],
   "what": "NET locked in staking, earning the rebase, and its share of all NET."
  },
  {
   "id": "dividend_index",
   "area": "Treasury",
   "label": "Staking index",
   "unit": "NET per wsNET",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "index",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "index()",
     "data": "0x2986c0e5",
     "decimals": 9
    }
   ],
   "formula": "sNET.index(): NET-equivalent per wsNET; it grows with every rebase",
   "steps": [
    "eth_call each source at the same block",
    "decode the first 32-byte word ÷ 10^decimals",
    "apply: sNET.index(): NET-equivalent per wsNET; it grows with every rebase"
   ],
   "what": "Converts wsNET to NET: NET = wsNET × index. Marks quoted per wsNET ÷ index = per NET."
  },
  {
   "id": "sleeve_wallet",
   "area": "Treasury",
   "label": "RWA sleeve: assets its Safe holds directly",
   "unit": "USD",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "sleeveUsdg",
     "contract": "USDG",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "fn": "balanceOf(sleeve)",
     "data": "0x70a08231000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb",
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "sleeveHohm",
     "contract": "hOHM",
     "address": "0x76Cf788606F3d968B93B8A243D0e185C974EE407",
     "fn": "balanceOf(sleeve)",
     "data": "0x70a08231000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "hohmPrice",
     "contract": "hOHMOracle",
     "address": "0x32ca7363c45212d119deeb11d02ce638234729d6",
     "fn": "0xbb47b68a (price, 18 decimals)",
     "data": "0xbb47b68a",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "sleeveNVDA",
     "contract": "NVDA token",
     "address": "0xd0601ce157db5bdc3162bbac2a2c8af5320d9eec",
     "fn": "balanceOf(sleeve)",
     "data": "0x70a08231000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "priceNVDA",
     "contract": "NVDA oracle",
     "address": "0xed29d310cfa91778a5850538da28ed42234cb78c",
     "fn": "price()",
     "data": "0xa035b1fe",
     "decimals": 24
    },
    {
     "kind": "call",
     "name": "sleeveSPCX",
     "contract": "SPCX token",
     "address": "0x4a0e65a3eccec6dbe60ae065f2e7bb85fae35eea",
     "fn": "balanceOf(sleeve)",
     "data": "0x70a08231000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "priceSPCX",
     "contract": "SPCX oracle",
     "address": "0x872f9d8955b34e841227a92de755cd63042ab7a5",
     "fn": "price()",
     "data": "0xa035b1fe",
     "decimals": 24
    },
    {
     "kind": "call",
     "name": "sleeveAAPL",
     "contract": "AAPL token",
     "address": "0xaf3d76f1834a1d425780943c99ea8a608f8a93f9",
     "fn": "balanceOf(sleeve)",
     "data": "0x70a08231000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "priceAAPL",
     "contract": "AAPL oracle",
     "address": "0xd625d488d552775d2867194c618b945e5ddfe097",
     "fn": "price()",
     "data": "0xa035b1fe",
     "decimals": 24
    },
    {
     "kind": "call",
     "name": "sleeveGOOGL",
     "contract": "GOOGL token",
     "address": "0x2e0847e8910a9732eb3fb1bb4b70a580adad4fe3",
     "fn": "balanceOf(sleeve)",
     "data": "0x70a08231000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "priceGOOGL",
     "contract": "GOOGL oracle",
     "address": "0x12ec3474d1e321e0aab065278b97fbc7eda5f424",
     "fn": "price()",
     "data": "0xa035b1fe",
     "decimals": 24
    },
    {
     "kind": "call",
     "name": "sleeveMSFT",
     "contract": "MSFT token",
     "address": "0xe93237c50d904957cf27e7b1133b510c669c2e74",
     "fn": "balanceOf(sleeve)",
     "data": "0x70a08231000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "priceMSFT",
     "contract": "MSFT oracle",
     "address": "0xcb9a035fe0e8f321e36286405febc70de42db34e",
     "fn": "price()",
     "data": "0xa035b1fe",
     "decimals": 24
    },
    {
     "kind": "call",
     "name": "sleeveCOIN",
     "contract": "COIN token",
     "address": "0x6330d8c3178a418788df01a47479c0ce7ccf450b",
     "fn": "balanceOf(sleeve)",
     "data": "0x70a08231000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "priceCOIN",
     "contract": "COIN oracle",
     "address": "0x3ebd3088b69a5eec3bdf03b82ccf19c3bc1fa894",
     "fn": "price()",
     "data": "0xa035b1fe",
     "decimals": 24
    }
   ],
   "formula": "USDG + hOHM × its oracle price + Σ equity balance × its oracle price()",
   "steps": [
    "eth_call each source at the same block",
    "decode the first 32-byte word ÷ 10^decimals",
    "apply: USDG + hOHM × its oracle price + Σ equity balance × its oracle price()"
   ],
   "what": "What the RWA sleeve's Safe holds itself: USDG, hOHM and tokenized stocks at their protocol oracles.",
   "caveats": [
    "The sleeve is a team-custodied Safe, outside RFV. Its positions held elsewhere (lending books, desk pots, a vault, LP) are separate reads."
   ]
  },
  {
   "id": "growth_money_in",
   "area": "Growth",
   "label": "Money into the Treasury, by source",
   "unit": "USD",
   "what": "Every USDG payment into the Treasury over the window, by where it came from: bonds, the trading fee, premium sales, the desks, pTEAM, the genesis sale. Money out is counted apart.",
   "needs": [
    "eth_getLogs"
   ],
   "sources": [
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x00000000000000000000000004822ea321a0dee6f40656172f29312104855d66"
     ],
     "what": "USDG into the Treasury",
     "fromBlock": "window start"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x00000000000000000000000004822ea321a0dee6f40656172f29312104855d66"
     ],
     "what": "USDG out of the Treasury",
     "fromBlock": "window start"
    },
    {
     "kind": "event",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "event": "NetMinted(address indexed minter, address indexed to, uint256 amount)",
     "topic0": "0xb5696c5985f265cb3ab6eca4e7762bfa0332c58dfe86b4aba87cbf105fa514ae",
     "what": "who minted NET in the same transaction (names the program)",
     "fromBlock": "window start"
    },
    {
     "kind": "tx",
     "method": "eth_getTransactionByHash",
     "what": "the transaction's target contract, for inflows the first two rules leave open and for every outflow"
    }
   ],
   "formula": "Σ USDG into the Treasury (÷ 10^6), by source; transfers to or from the Treasury's Morpho vault are left out. Out: USDG leaving the Treasury, \"buybacks\" when it went to (or through) the inverse bond.",
   "steps": [
    "Window start: UTC midnight `days` days before now (\"all\": since launch). Find the last block at or before it, and the first block after it, from block headers.",
    "Read USDG Transfer logs into and out of the Treasury over the window, and the Treasury's NetMinted logs.",
    "Name each payment by its sender. If the sender is unknown (a bond buyer pays the Treasury directly), use the minter in the same transaction's NetMinted event; failing that, the contract the transaction called (eth_getTransactionByHash).",
    "Skip the Morpho vault. Anything still unknown is \"other\".",
    "Sum by UTC day and source, rounding each running sum to the cent, then add the days up."
   ],
   "params": {
    "days": {
     "default": 30,
     "min": 1,
     "max": 90,
     "or": "all"
    },
    "fromBlock": {
     "default": "found from days",
     "note": "the block whose state is the start"
    }
   },
   "api": {
    "path": "/api/v1/grows?days=30",
    "field": "moneyIn.total"
   },
   "caveats": [
    "The sender names are labels copied from the site's code and published in this file.",
    "Money in is not profit: a bond payment is new capital that also issues NET.",
    "The site's flow scan can lag the chain by a few minutes, and it looks up at most 400 transaction targets per 10,000 blocks; past that cap a payment stays \"other\" there."
   ]
  },
  {
   "id": "growth_supply",
   "area": "Growth",
   "label": "NET supply change over the window",
   "unit": "%",
   "what": "How much NET in issue changed over the window, rebuilt from mints and burns with no old state.",
   "needs": [
    "eth_call",
    "eth_getLogs"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "supply",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "fn": "NET.totalSupply()",
     "data": "0x18160ddd",
     "decimals": 9
    },
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x0000000000000000000000000000000000000000000000000000000000000000"
     ],
     "what": "NET minted",
     "fromBlock": "window start"
    },
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x0000000000000000000000000000000000000000000000000000000000000000"
     ],
     "what": "NET burned",
     "fromBlock": "window start"
    }
   ],
   "formula": "end = NET.totalSupply() now; start = end − minted + burned (Transfer from / to the zero address since the start); change = end ÷ start − 1",
   "steps": [
    "Window start: UTC midnight `days` days before now (\"all\": since launch). Find the last block at or before it, and the first block after it, from block headers.",
    "Read NET.totalSupply() now (9 decimals).",
    "Sum NET Transfer logs from the zero address (minted) and to it (burned) since the start.",
    "Start = now − minted + burned."
   ],
   "params": {
    "days": {
     "default": 30,
     "min": 1,
     "max": 90,
     "or": "all"
    },
    "fromBlock": {
     "default": "found from days",
     "note": "the block whose state is the start"
    }
   },
   "api": {
    "path": "/api/v1/grows?days=30",
    "field": "supply.pct"
   },
   "caveats": [
    "This assumes every mint and burn emits a Transfer from or to the zero address, as standard tokens do. An archive read of totalSupply() at the start block checks it.",
    "The site reads the start from its 30-minute history (an archive read at the grid time) and the end live."
   ]
  },
  {
   "id": "growth_core_rfv",
   "area": "Growth",
   "label": "Core RFV change over the window",
   "unit": "USD",
   "what": "How much the Core treasury (Treasury.rfv()) grew between the window's start and now.",
   "needs": [
    "eth_call",
    "archive"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "rfv",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "fn": "Treasury.rfv()",
     "data": "0x4dc8d6df",
     "decimals": 18
    }
   ],
   "formula": "rfv() now − rfv() at the start block; % = change ÷ start. For \"all\", the start is 0.",
   "steps": [
    "Window start: UTC midnight `days` days before now (\"all\": since launch). Find the last block at or before it, and the first block after it, from block headers.",
    "eth_call Treasury.rfv() at the start block (archive) and now (18 decimals).",
    "Subtract."
   ],
   "params": {
    "days": {
     "default": 30,
     "min": 1,
     "max": 90,
     "or": "all"
    },
    "fromBlock": {
     "default": "found from days",
     "note": "the block whose state is the start"
    }
   },
   "api": {
    "path": "/api/v1/grows?days=30",
    "field": "core.change"
   },
   "caveats": [
    "The start is past state: it needs an archive node. A public RPC keeps about 10 minutes of state and will refuse the start read. Pass opts.fromBlock to choose the start block yourself.",
    "The site's start is its 30-minute history row nearest that midnight (normally the midnight row itself, read at the same block this recipe picks); its end is its live read, refreshed every few minutes, so a check can differ by what changed since."
   ]
  },
  {
   "id": "growth_value_change",
   "area": "Growth",
   "label": "Core RFV change no payment explains",
   "unit": "USD",
   "what": "The part of Core RFV's change that is not money in or out: Morpho interest and LP value, less the 2% haircut rfv() applies to USDG moved into Morpho.",
   "needs": [
    "eth_call",
    "eth_getLogs",
    "archive"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "rfv",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "fn": "Treasury.rfv()",
     "data": "0x4dc8d6df",
     "decimals": 18
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x00000000000000000000000004822ea321a0dee6f40656172f29312104855d66"
     ],
     "what": "USDG into the Treasury",
     "fromBlock": "window start"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x00000000000000000000000004822ea321a0dee6f40656172f29312104855d66"
     ],
     "what": "USDG out of the Treasury",
     "fromBlock": "window start"
    },
    {
     "kind": "event",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "event": "NetMinted(address indexed minter, address indexed to, uint256 amount)",
     "topic0": "0xb5696c5985f265cb3ab6eca4e7762bfa0332c58dfe86b4aba87cbf105fa514ae",
     "what": "who minted NET in the same transaction (names the program)",
     "fromBlock": "window start"
    },
    {
     "kind": "tx",
     "method": "eth_getTransactionByHash",
     "what": "the transaction's target contract, for inflows the first two rules leave open and for every outflow"
    }
   ],
   "formula": "(rfv() now − rfv() at the start) − (money in − money out)",
   "steps": [
    "Run growth_core_rfv and growth_money_in over the same window.",
    "Subtract the net payments from the change."
   ],
   "params": {
    "days": {
     "default": 30,
     "min": 1,
     "max": 90,
     "or": "all"
    },
    "fromBlock": {
     "default": "found from days",
     "note": "the block whose state is the start"
    }
   },
   "api": {
    "path": "/api/v1/grows?days=30",
    "field": "valueChange"
   },
   "caveats": [
    "The start is past state: it needs an archive node. A public RPC keeps about 10 minutes of state and will refuse the start read. Pass opts.fromBlock to choose the start block yourself."
   ]
  },
  {
   "id": "growth_nav_per_net",
   "area": "Growth",
   "label": "NAV per NET growth: reserves against new NET",
   "unit": "%",
   "what": "How NAV per NET (Core) changed over the window, split into the part from reserves growing and the part from new NET.",
   "needs": [
    "eth_call",
    "archive"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "rfv",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "fn": "Treasury.rfv()",
     "data": "0x4dc8d6df",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "supply",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "fn": "NET.totalSupply()",
     "data": "0x18160ddd",
     "decimals": 9
    }
   ],
   "formula": "NAV growth = (R1/S1) ÷ (R0/S0) − 1 = reserve effect + supply effect; reserve effect = ΔR/R0 × S0/S1; supply effect = S0/S1 − 1 (R = rfv(), S = NET.totalSupply())",
   "steps": [
    "Window start: UTC midnight `days` days before now (\"all\": since launch). Find the last block at or before it, and the first block after it, from block headers.",
    "eth_call rfv() and totalSupply() at the start block (archive) and now.",
    "Apply the formula, in percent."
   ],
   "params": {
    "days": {
     "default": 30,
     "min": 1,
     "max": 90,
     "or": "all"
    },
    "fromBlock": {
     "default": "found from days",
     "note": "the block whose state is the start"
    }
   },
   "api": {
    "path": "/api/v1/grows?days=30",
    "field": "perNet.navGrowthPct"
   },
   "caveats": [
    "The start is past state: it needs an archive node. A public RPC keeps about 10 minutes of state and will refuse the start read. Pass opts.fromBlock to choose the start block yourself.",
    "S0 can also come from growth_supply (events, no archive); only R0 then needs the archive."
   ]
  },
  {
   "id": "growth_index",
   "area": "Growth",
   "label": "Staking index growth over the window",
   "unit": "%",
   "what": "How much the staking index rose: what one wsNET grew by in NET through rebases.",
   "needs": [
    "eth_call",
    "archive"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "index",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "sNET.index()",
     "data": "0x2986c0e5",
     "decimals": 9
    }
   ],
   "formula": "index() at the last 30-minute grid time ÷ index() at the first grid time inside the window − 1",
   "steps": [
    "Grid times are every 30 minutes on the clock (UTC). Start: the first one at or after now − days × 24 h. End: the last one at or before now.",
    "For each, find the last block at or before that time.",
    "eth_call sNET.index() at both blocks (9 decimals; archive for the start) and divide."
   ],
   "params": {
    "days": {
     "default": 7,
     "min": 1,
     "max": 90
    }
   },
   "api": {
    "path": "/api/v1/history?days=7",
    "field": "rows[last].dividendIndex ÷ rows[0].dividendIndex − 1"
   },
   "caveats": [
    "The start is past state: it needs an archive node. A public RPC keeps about 10 minutes of state and will refuse the start read. Pass opts.fromBlock to choose the start block yourself.",
    "No event names each rebase in this codebase, so the index is read as state."
   ]
  },
  {
   "id": "history_point",
   "area": "Growth",
   "label": "One 30-minute history point",
   "unit": "USD",
   "what": "Core RFV, NAV per NET, the TWAP, NET supply, NET staked and the staking index at one grid time, as the site's history stores them.",
   "needs": [
    "eth_call",
    "archive"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "rfv",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "fn": "Treasury.rfv()",
     "data": "0x4dc8d6df",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "backing",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "fn": "Treasury.backingPerToken()",
     "data": "0x1521843e",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "twap",
     "address": "0x929631b33F4070D6f54477fba3FD27566567dAca",
     "fn": "PairOracle.twapNetUsdg()",
     "data": "0x10aa790e",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "supply",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "fn": "NET.totalSupply()",
     "data": "0x18160ddd",
     "decimals": 9
    },
    {
     "kind": "call",
     "name": "staked",
     "address": "0xB078cc304A0B264C5F3680DC0488954ACcd02E87",
     "fn": "Staking.totalStaked()",
     "data": "0x817b1cd2",
     "decimals": 9
    },
    {
     "kind": "call",
     "name": "index",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "sNET.index()",
     "data": "0x2986c0e5",
     "decimals": 9
    }
   ],
   "formula": "each value read at the last block at or before the grid time",
   "steps": [
    "Pick a grid time (every 30 minutes on the clock, UTC): opts.t in unix seconds, default the latest one.",
    "Find the last block at or before it (the site refuses a point with no block within 5 minutes).",
    "eth_call each source at that block (archive for anything older than ~10 minutes)."
   ],
   "params": {
    "t": {
     "default": "the latest grid time"
    },
    "fromBlock": {
     "default": "found from t"
    }
   },
   "api": {
    "path": "/api/v1/history?days=1",
    "field": "rows[] (the row whose t matches): rfv, backing, twap, supply, staked, dividendIndex"
   },
   "caveats": [
    "The start is past state: it needs an archive node. A public RPC keeps about 10 minutes of state and will refuse the start read. Pass opts.fromBlock to choose the start block yourself.",
    "staked here is Staking.totalStaked(), which is what the history writer reads; the API's field note describes it as NET.balanceOf(staking).",
    "number and trueRfv on that row add the sleeve mark and the memo holdings: those are other recipes (core.js sleeve_wallet is the part the Safe holds directly)."
   ]
  },
  {
   "id": "growth_sleeve_wallet",
   "area": "Growth",
   "label": "RWA sleeve wallet change over the window",
   "unit": "USD",
   "what": "How the assets the sleeve's Safe holds directly (USDG, hOHM, the six stock tokens, at their oracles) changed over the window.",
   "needs": [
    "eth_call",
    "archive",
    "offchain:memo"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "sleeveUsdg",
     "contract": "USDG",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "fn": "balanceOf(sleeve)",
     "data": "0x70a08231000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb",
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "sleeveHohm",
     "contract": "hOHM",
     "address": "0x76Cf788606F3d968B93B8A243D0e185C974EE407",
     "fn": "balanceOf(sleeve)",
     "data": "0x70a08231000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "hohmPrice",
     "contract": "hOHMOracle",
     "address": "0x32ca7363c45212d119deeb11d02ce638234729d6",
     "fn": "0xbb47b68a (price, 18 decimals)",
     "data": "0xbb47b68a",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "sleeveNVDA",
     "contract": "NVDA token",
     "address": "0xd0601ce157db5bdc3162bbac2a2c8af5320d9eec",
     "fn": "balanceOf(sleeve)",
     "data": "0x70a08231000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "priceNVDA",
     "contract": "NVDA oracle",
     "address": "0xed29d310cfa91778a5850538da28ed42234cb78c",
     "fn": "price()",
     "data": "0xa035b1fe",
     "decimals": 24
    },
    {
     "kind": "call",
     "name": "sleeveSPCX",
     "contract": "SPCX token",
     "address": "0x4a0e65a3eccec6dbe60ae065f2e7bb85fae35eea",
     "fn": "balanceOf(sleeve)",
     "data": "0x70a08231000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "priceSPCX",
     "contract": "SPCX oracle",
     "address": "0x872f9d8955b34e841227a92de755cd63042ab7a5",
     "fn": "price()",
     "data": "0xa035b1fe",
     "decimals": 24
    },
    {
     "kind": "call",
     "name": "sleeveAAPL",
     "contract": "AAPL token",
     "address": "0xaf3d76f1834a1d425780943c99ea8a608f8a93f9",
     "fn": "balanceOf(sleeve)",
     "data": "0x70a08231000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "priceAAPL",
     "contract": "AAPL oracle",
     "address": "0xd625d488d552775d2867194c618b945e5ddfe097",
     "fn": "price()",
     "data": "0xa035b1fe",
     "decimals": 24
    },
    {
     "kind": "call",
     "name": "sleeveGOOGL",
     "contract": "GOOGL token",
     "address": "0x2e0847e8910a9732eb3fb1bb4b70a580adad4fe3",
     "fn": "balanceOf(sleeve)",
     "data": "0x70a08231000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "priceGOOGL",
     "contract": "GOOGL oracle",
     "address": "0x12ec3474d1e321e0aab065278b97fbc7eda5f424",
     "fn": "price()",
     "data": "0xa035b1fe",
     "decimals": 24
    },
    {
     "kind": "call",
     "name": "sleeveMSFT",
     "contract": "MSFT token",
     "address": "0xe93237c50d904957cf27e7b1133b510c669c2e74",
     "fn": "balanceOf(sleeve)",
     "data": "0x70a08231000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "priceMSFT",
     "contract": "MSFT oracle",
     "address": "0xcb9a035fe0e8f321e36286405febc70de42db34e",
     "fn": "price()",
     "data": "0xa035b1fe",
     "decimals": 24
    },
    {
     "kind": "call",
     "name": "sleeveCOIN",
     "contract": "COIN token",
     "address": "0x6330d8c3178a418788df01a47479c0ce7ccf450b",
     "fn": "balanceOf(sleeve)",
     "data": "0x70a08231000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "priceCOIN",
     "contract": "COIN oracle",
     "address": "0x3ebd3088b69a5eec3bdf03b82ccf19c3bc1fa894",
     "fn": "price()",
     "data": "0xa035b1fe",
     "decimals": 24
    }
   ],
   "formula": "core.js sleeve_wallet now − the same at the start block",
   "steps": [
    "Window start: UTC midnight `days` days before now (\"all\": since launch). Find the last block at or before it, and the first block after it, from block headers.",
    "Run core.js sleeve_wallet at the start block (archive) and now.",
    "Subtract."
   ],
   "params": {
    "days": {
     "default": 30,
     "min": 1,
     "max": 90,
     "or": "all"
    },
    "fromBlock": {
     "default": "found from days",
     "note": "the block whose state is the start"
    }
   },
   "api": {
    "path": "/api/v1/grows?days=30",
    "field": "coreAndSleeve.change − core.change (the full sleeve's change)"
   },
   "caveats": [
    "The start is past state: it needs an archive node. A public RPC keeps about 10 minutes of state and will refuse the start read. Pass opts.fromBlock to choose the start block yourself.",
    "This is only part of the sleeve. The site's sleeve is the official mark (desk menus, Morpho collateral less debt, the Credit deposit, v3 LP, TURBO pots, House Vault) plus the memo holdings the official Reports add (NET held, Loopback, Advance, the sports book, the asset desk, v4 LP). Which positions count comes from the team's memo, so the served figure will not match this one.",
    "Oracle marks at the start are the oracles' values at that block."
   ]
  },
  {
   "id": "buybacks_window",
   "area": "Buybacks",
   "label": "Sleeve buybacks over a window, against the window before",
   "unit": "USD",
   "what": "USDG the RWA sleeve's Safe spent buying NET over the last `days` UTC days, and the same for the days before.",
   "needs": [
    "eth_getLogs"
   ],
   "sources": [
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb"
     ],
     "fromBlock": 45000000,
     "what": "NET into 0x498752d5fa0600cbd613074c151abe15b3fec7cb"
    },
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x0000000000000000000000003bb7a23316f82c0e984fa2e784846d8928a35f42"
     ],
     "fromBlock": 45000000,
     "what": "NET into 0x3bb7a23316f82c0e984fa2e784846d8928a35f42"
    },
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x00000000000000000000000070eaeec20c39df48509f1f3fab01f7dde207947b"
     ],
     "fromBlock": 45000000,
     "what": "NET into 0x70eaeec20c39df48509f1f3fab01f7dde207947b"
    },
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x00000000000000000000000070eaeec20c39df48509f1f3fab01f7dde207947b"
     ],
     "fromBlock": 45000000,
     "what": "NET out of the OTC desk"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb"
     ],
     "fromBlock": 45000000,
     "what": "USDG out of 0x498752d5fa0600cbd613074c151abe15b3fec7cb"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb"
     ],
     "fromBlock": 45000000,
     "what": "USDG into 0x498752d5fa0600cbd613074c151abe15b3fec7cb"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x0000000000000000000000003bb7a23316f82c0e984fa2e784846d8928a35f42"
     ],
     "fromBlock": 45000000,
     "what": "USDG out of 0x3bb7a23316f82c0e984fa2e784846d8928a35f42"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x0000000000000000000000003bb7a23316f82c0e984fa2e784846d8928a35f42"
     ],
     "fromBlock": 45000000,
     "what": "USDG into 0x3bb7a23316f82c0e984fa2e784846d8928a35f42"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x00000000000000000000000070eaeec20c39df48509f1f3fab01f7dde207947b"
     ],
     "fromBlock": 45000000,
     "what": "USDG out of 0x70eaeec20c39df48509f1f3fab01f7dde207947b"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x00000000000000000000000070eaeec20c39df48509f1f3fab01f7dde207947b"
     ],
     "fromBlock": 45000000,
     "what": "USDG into 0x70eaeec20c39df48509f1f3fab01f7dde207947b"
    }
   ],
   "formula": "Σ USD of the sleeve's buys whose UTC day starts after (now − days − 1 day); previous: the `days` before that; change = this ÷ previous − 1",
   "steps": [
    "Read NET and USDG Transfer logs from block 45,000,000 to the head: NET into each Safe and the OTC desk, NET out of the desk, USDG into and out of each of the three (10 queries).",
    "Decode each log: from and to are topics 1 and 2; the amount is the data word ÷ 10^9 for NET, ÷ 10^6 for USDG. Drop duplicates (same tx and log index).",
    "Group the transfers by transaction.",
    "A buy, per Safe: NET came in from somewhere other than zero, the other Safe or the OTC desk, and USDG out minus USDG back in is above zero. Price = that USDG ÷ that NET.",
    "Round each buy to 6 decimals of NET and 2 of USD, and add them up the same way the site does.",
    "Keep the sleeve's buys (not the Manager Safe's) and total them by UTC day.",
    "This window: the days whose start is later than now − days × 24 h − 24 h (so the day the window starts in counts in full). The previous window: the same number of days before that.",
    "USD is rounded to the dollar, NET to 3 decimals, the average price to 2."
   ],
   "params": {
    "days": {
     "default": 7,
     "min": 1,
     "max": 90
    }
   },
   "api": {
    "path": "/api/v1/buybacks?days=7",
    "field": "window.usd"
   },
   "caveats": [
    "The Safes are team-custodied. The NET they buy is kept as desk inventory, not burned.",
    "Route names (LI.FI, 1inch order, Uniswap v4, the pair) are labels for the contract the NET came from. They are published in this file; any other source shows as Other.",
    "Times come from each block's timestamp, in UTC. Where the node does not send it with the log, the UTC day is still exact (the first block of each day is found) and the time of day is interpolated. The site measures windows from the moment it was asked; this recipe from the head block's time."
   ]
  },
  {
   "id": "buybacks_sleeve",
   "area": "Buybacks",
   "label": "Sleeve buybacks: last 24 hours, 7 days, 30 days, since start",
   "unit": "USD",
   "what": "USDG the RWA sleeve's Safe spent on NET in rolling windows back from now, and since the scan start (13 Aug 2026).",
   "needs": [
    "eth_getLogs"
   ],
   "sources": [
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb"
     ],
     "fromBlock": 45000000,
     "what": "NET into 0x498752d5fa0600cbd613074c151abe15b3fec7cb"
    },
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x0000000000000000000000003bb7a23316f82c0e984fa2e784846d8928a35f42"
     ],
     "fromBlock": 45000000,
     "what": "NET into 0x3bb7a23316f82c0e984fa2e784846d8928a35f42"
    },
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x00000000000000000000000070eaeec20c39df48509f1f3fab01f7dde207947b"
     ],
     "fromBlock": 45000000,
     "what": "NET into 0x70eaeec20c39df48509f1f3fab01f7dde207947b"
    },
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x00000000000000000000000070eaeec20c39df48509f1f3fab01f7dde207947b"
     ],
     "fromBlock": 45000000,
     "what": "NET out of the OTC desk"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb"
     ],
     "fromBlock": 45000000,
     "what": "USDG out of 0x498752d5fa0600cbd613074c151abe15b3fec7cb"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb"
     ],
     "fromBlock": 45000000,
     "what": "USDG into 0x498752d5fa0600cbd613074c151abe15b3fec7cb"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x0000000000000000000000003bb7a23316f82c0e984fa2e784846d8928a35f42"
     ],
     "fromBlock": 45000000,
     "what": "USDG out of 0x3bb7a23316f82c0e984fa2e784846d8928a35f42"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x0000000000000000000000003bb7a23316f82c0e984fa2e784846d8928a35f42"
     ],
     "fromBlock": 45000000,
     "what": "USDG into 0x3bb7a23316f82c0e984fa2e784846d8928a35f42"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x00000000000000000000000070eaeec20c39df48509f1f3fab01f7dde207947b"
     ],
     "fromBlock": 45000000,
     "what": "USDG out of 0x70eaeec20c39df48509f1f3fab01f7dde207947b"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x00000000000000000000000070eaeec20c39df48509f1f3fab01f7dde207947b"
     ],
     "fromBlock": 45000000,
     "what": "USDG into 0x70eaeec20c39df48509f1f3fab01f7dde207947b"
    }
   ],
   "formula": "Σ USD (and NET) of the sleeve's buys with block time ≥ now − 24 h / 7 d / 30 d; all = every sleeve buy; price = USD ÷ NET",
   "steps": [
    "Read NET and USDG Transfer logs from block 45,000,000 to the head: NET into each Safe and the OTC desk, NET out of the desk, USDG into and out of each of the three (10 queries).",
    "Decode each log: from and to are topics 1 and 2; the amount is the data word ÷ 10^9 for NET, ÷ 10^6 for USDG. Drop duplicates (same tx and log index).",
    "Group the transfers by transaction.",
    "A buy, per Safe: NET came in from somewhere other than zero, the other Safe or the OTC desk, and USDG out minus USDG back in is above zero. Price = that USDG ÷ that NET.",
    "Round each buy to 6 decimals of NET and 2 of USD, and add them up the same way the site does.",
    "Keep the sleeve's buys. Sum those inside each rolling window, measured in seconds back from the head block's time."
   ],
   "api": {
    "path": "/api/v1/buybacks",
    "field": "windows.week.usd"
   },
   "caveats": [
    "The Safes are team-custodied. The NET they buy is kept as desk inventory, not burned.",
    "Route names (LI.FI, 1inch order, Uniswap v4, the pair) are labels for the contract the NET came from. They are published in this file; any other source shows as Other.",
    "Times come from each block's timestamp, in UTC. Where the node does not send it with the log, the UTC day is still exact (the first block of each day is found) and the time of day is interpolated. The site measures windows from the moment it was asked; this recipe from the head block's time."
   ]
  },
  {
   "id": "buybacks_share_of_supply",
   "area": "Buybacks",
   "label": "Sleeve buybacks as a share of NET supply",
   "unit": "share",
   "what": "NET the sleeve bought in the last 7 days, divided by NET in issue now.",
   "needs": [
    "eth_getLogs",
    "eth_call"
   ],
   "sources": [
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb"
     ],
     "fromBlock": 45000000,
     "what": "NET into 0x498752d5fa0600cbd613074c151abe15b3fec7cb"
    },
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x0000000000000000000000003bb7a23316f82c0e984fa2e784846d8928a35f42"
     ],
     "fromBlock": 45000000,
     "what": "NET into 0x3bb7a23316f82c0e984fa2e784846d8928a35f42"
    },
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x00000000000000000000000070eaeec20c39df48509f1f3fab01f7dde207947b"
     ],
     "fromBlock": 45000000,
     "what": "NET into 0x70eaeec20c39df48509f1f3fab01f7dde207947b"
    },
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x00000000000000000000000070eaeec20c39df48509f1f3fab01f7dde207947b"
     ],
     "fromBlock": 45000000,
     "what": "NET out of the OTC desk"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb"
     ],
     "fromBlock": 45000000,
     "what": "USDG out of 0x498752d5fa0600cbd613074c151abe15b3fec7cb"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb"
     ],
     "fromBlock": 45000000,
     "what": "USDG into 0x498752d5fa0600cbd613074c151abe15b3fec7cb"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x0000000000000000000000003bb7a23316f82c0e984fa2e784846d8928a35f42"
     ],
     "fromBlock": 45000000,
     "what": "USDG out of 0x3bb7a23316f82c0e984fa2e784846d8928a35f42"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x0000000000000000000000003bb7a23316f82c0e984fa2e784846d8928a35f42"
     ],
     "fromBlock": 45000000,
     "what": "USDG into 0x3bb7a23316f82c0e984fa2e784846d8928a35f42"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x00000000000000000000000070eaeec20c39df48509f1f3fab01f7dde207947b"
     ],
     "fromBlock": 45000000,
     "what": "USDG out of 0x70eaeec20c39df48509f1f3fab01f7dde207947b"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x00000000000000000000000070eaeec20c39df48509f1f3fab01f7dde207947b"
     ],
     "fromBlock": 45000000,
     "what": "USDG into 0x70eaeec20c39df48509f1f3fab01f7dde207947b"
    },
    {
     "kind": "call",
     "name": "netSupply",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "fn": "totalSupply()",
     "data": "0x18160ddd",
     "decimals": 9
    }
   ],
   "formula": "NET bought (7 days) ÷ NET.totalSupply(), rounded to 5 decimals; also for 24 hours, 30 days and since start",
   "steps": [
    "Read NET and USDG Transfer logs from block 45,000,000 to the head: NET into each Safe and the OTC desk, NET out of the desk, USDG into and out of each of the three (10 queries).",
    "Decode each log: from and to are topics 1 and 2; the amount is the data word ÷ 10^9 for NET, ÷ 10^6 for USDG. Drop duplicates (same tx and log index).",
    "Group the transfers by transaction.",
    "A buy, per Safe: NET came in from somewhere other than zero, the other Safe or the OTC desk, and USDG out minus USDG back in is above zero. Price = that USDG ÷ that NET.",
    "Round each buy to 6 decimals of NET and 2 of USD, and add them up the same way the site does.",
    "Sum the sleeve's NET bought in each window.",
    "Read NET.totalSupply() (9 decimals) and divide."
   ],
   "api": {
    "path": "/api/v1/buybacks",
    "field": "shareOfSupply.week"
   },
   "caveats": [
    "The Safes are team-custodied. The NET they buy is kept as desk inventory, not burned.",
    "Route names (LI.FI, 1inch order, Uniswap v4, the pair) are labels for the contract the NET came from. They are published in this file; any other source shows as Other.",
    "Times come from each block's timestamp, in UTC. Where the node does not send it with the log, the UTC day is still exact (the first block of each day is found) and the time of day is interpolated. The site measures windows from the moment it was asked; this recipe from the head block's time.",
    "Supply is today's, for every window."
   ]
  },
  {
   "id": "buybacks_by_safe",
   "area": "Buybacks",
   "label": "Buybacks by Safe and by venue, since start",
   "unit": "USD",
   "what": "Every buy by the RWA sleeve Safe and the Manager Safe since 13 Aug 2026, split by Safe and by where the NET came from.",
   "needs": [
    "eth_getLogs"
   ],
   "sources": [
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb"
     ],
     "fromBlock": 45000000,
     "what": "NET into 0x498752d5fa0600cbd613074c151abe15b3fec7cb"
    },
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x0000000000000000000000003bb7a23316f82c0e984fa2e784846d8928a35f42"
     ],
     "fromBlock": 45000000,
     "what": "NET into 0x3bb7a23316f82c0e984fa2e784846d8928a35f42"
    },
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x00000000000000000000000070eaeec20c39df48509f1f3fab01f7dde207947b"
     ],
     "fromBlock": 45000000,
     "what": "NET into 0x70eaeec20c39df48509f1f3fab01f7dde207947b"
    },
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x00000000000000000000000070eaeec20c39df48509f1f3fab01f7dde207947b"
     ],
     "fromBlock": 45000000,
     "what": "NET out of the OTC desk"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb"
     ],
     "fromBlock": 45000000,
     "what": "USDG out of 0x498752d5fa0600cbd613074c151abe15b3fec7cb"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb"
     ],
     "fromBlock": 45000000,
     "what": "USDG into 0x498752d5fa0600cbd613074c151abe15b3fec7cb"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x0000000000000000000000003bb7a23316f82c0e984fa2e784846d8928a35f42"
     ],
     "fromBlock": 45000000,
     "what": "USDG out of 0x3bb7a23316f82c0e984fa2e784846d8928a35f42"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x0000000000000000000000003bb7a23316f82c0e984fa2e784846d8928a35f42"
     ],
     "fromBlock": 45000000,
     "what": "USDG into 0x3bb7a23316f82c0e984fa2e784846d8928a35f42"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x00000000000000000000000070eaeec20c39df48509f1f3fab01f7dde207947b"
     ],
     "fromBlock": 45000000,
     "what": "USDG out of 0x70eaeec20c39df48509f1f3fab01f7dde207947b"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x00000000000000000000000070eaeec20c39df48509f1f3fab01f7dde207947b"
     ],
     "fromBlock": 45000000,
     "what": "USDG into 0x70eaeec20c39df48509f1f3fab01f7dde207947b"
    }
   ],
   "formula": "Σ USD and NET per Safe; per route (the contract the largest NET leg came from); price = USD ÷ NET",
   "steps": [
    "Read NET and USDG Transfer logs from block 45,000,000 to the head: NET into each Safe and the OTC desk, NET out of the desk, USDG into and out of each of the three (10 queries).",
    "Decode each log: from and to are topics 1 and 2; the amount is the data word ÷ 10^9 for NET, ÷ 10^6 for USDG. Drop duplicates (same tx and log index).",
    "Group the transfers by transaction.",
    "A buy, per Safe: NET came in from somewhere other than zero, the other Safe or the OTC desk, and USDG out minus USDG back in is above zero. Price = that USDG ÷ that NET.",
    "Round each buy to 6 decimals of NET and 2 of USD, and add them up the same way the site does.",
    "Group the buys by Safe, and separately by route."
   ],
   "api": {
    "path": "/api/v1/buybacks",
    "field": "bySafe"
   },
   "caveats": [
    "The Safes are team-custodied. The NET they buy is kept as desk inventory, not burned.",
    "Route names (LI.FI, 1inch order, Uniswap v4, the pair) are labels for the contract the NET came from. They are published in this file; any other source shows as Other.",
    "Times come from each block's timestamp, in UTC. Where the node does not send it with the log, the UTC day is still exact (the first block of each day is found) and the time of day is interpolated. The site measures windows from the moment it was asked; this recipe from the head block's time."
   ]
  },
  {
   "id": "buybacks_otc_desk",
   "area": "Buybacks",
   "label": "The sleeve's OTC desk",
   "unit": "USD",
   "what": "NET put on the OTC desk, NET it sold to named buyers for USDG, and the USDG it passed on.",
   "needs": [
    "eth_getLogs"
   ],
   "sources": [
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb"
     ],
     "fromBlock": 45000000,
     "what": "NET into 0x498752d5fa0600cbd613074c151abe15b3fec7cb"
    },
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x0000000000000000000000003bb7a23316f82c0e984fa2e784846d8928a35f42"
     ],
     "fromBlock": 45000000,
     "what": "NET into 0x3bb7a23316f82c0e984fa2e784846d8928a35f42"
    },
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x00000000000000000000000070eaeec20c39df48509f1f3fab01f7dde207947b"
     ],
     "fromBlock": 45000000,
     "what": "NET into 0x70eaeec20c39df48509f1f3fab01f7dde207947b"
    },
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x00000000000000000000000070eaeec20c39df48509f1f3fab01f7dde207947b"
     ],
     "fromBlock": 45000000,
     "what": "NET out of the OTC desk"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb"
     ],
     "fromBlock": 45000000,
     "what": "USDG out of 0x498752d5fa0600cbd613074c151abe15b3fec7cb"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb"
     ],
     "fromBlock": 45000000,
     "what": "USDG into 0x498752d5fa0600cbd613074c151abe15b3fec7cb"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x0000000000000000000000003bb7a23316f82c0e984fa2e784846d8928a35f42"
     ],
     "fromBlock": 45000000,
     "what": "USDG out of 0x3bb7a23316f82c0e984fa2e784846d8928a35f42"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x0000000000000000000000003bb7a23316f82c0e984fa2e784846d8928a35f42"
     ],
     "fromBlock": 45000000,
     "what": "USDG into 0x3bb7a23316f82c0e984fa2e784846d8928a35f42"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x00000000000000000000000070eaeec20c39df48509f1f3fab01f7dde207947b"
     ],
     "fromBlock": 45000000,
     "what": "USDG out of 0x70eaeec20c39df48509f1f3fab01f7dde207947b"
    },
    {
     "kind": "event",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x00000000000000000000000070eaeec20c39df48509f1f3fab01f7dde207947b"
     ],
     "fromBlock": 45000000,
     "what": "USDG into 0x70eaeec20c39df48509f1f3fab01f7dde207947b"
    }
   ],
   "formula": "offers = NET into the desk; fills = NET out of the desk to anyone but the Safes, with the USDG that buyer paid the desk in the same transaction; forwarded = USDG out of the desk",
   "steps": [
    "Read the same logs as the buyback recipes (from block 45,000,000).",
    "Offers: every NET transfer into the desk.",
    "Fills: every NET transfer out of the desk to an address other than the two Safes; the price is the USDG that address sent the desk in the same transaction ÷ the NET.",
    "Forwarded: every USDG transfer out of the desk."
   ],
   "api": {
    "path": "/api/v1/buybacks",
    "field": "otcDesk.fills.usd"
   },
   "caveats": [
    "The desk address is a label taken from the site's code. Buyers are shown as addresses.",
    "The site keeps the 40 largest buyers and the 10 newest fills; this recipe does the same."
   ]
  },
  {
   "id": "buybacks_inverse_bond",
   "area": "Buybacks",
   "label": "NET sold to the Treasury's inverse bond",
   "unit": "NET",
   "what": "The Treasury's own buyback: holders sell NET to it at NAV × 0.985 and it is burned. Count and NET since launch.",
   "needs": [
    "eth_getLogs"
   ],
   "sources": [
    {
     "kind": "event",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x00000000000000000000000092166e94eea5b7799b761653881692f881dfc4c9"
     ],
     "fromBlock": 11443336,
     "what": "NET sold to the inverse bond"
    }
   ],
   "formula": "count and Σ NET of Transfer logs into the inverse bond, not from the zero address",
   "steps": [
    "Read NET Transfer logs into the inverse bond from block 11,443,336 (the NET token's deploy) to the head.",
    "Skip transfers from the zero address. Count the rest and add up the NET (÷ 10^9)."
   ],
   "api": {
    "path": "/api/v1/buybacks",
    "field": "inverseBond.net"
   },
   "caveats": [
    "The site seeded its count with the sales up to 7 Oct 2026 (4 sales, 2.40514483 NET) and scans on from there; this recipe counts from launch, so the two should agree.",
    "The site only counts these when its paid RPC answers; if it fell behind, its count can be lower than this one for a while."
   ]
  },
  {
   "id": "lp_price",
   "area": "Liquidity",
   "label": "NET price in the NET/USDG pool (spot)",
   "unit": "USD per NET",
   "what": "USDG per NET from the pool's reserves right now. This is the spot price, not the time-weighted one.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "getReserves",
     "contract": "NET/USDG pair",
     "address": "0x59F95461E68e0c77605299791E1449f175165B54",
     "fn": "getReserves() → (uint112 USDG, uint112 NET, uint32)",
     "data": "0x0902f1ac",
     "decimals": [
      6,
      9
     ]
    }
   ],
   "formula": "reserve0 (USDG, ÷ 10^6) ÷ reserve1 (NET, ÷ 10^9)",
   "steps": [
    "eth_call getReserves() on the pair.",
    "Word 0 is USDG (6 decimals), word 1 is NET (9 decimals).",
    "Divide USDG by NET."
   ],
   "api": {
    "path": "/api/v1/lp",
    "field": "pool.price"
   },
   "caveats": [
    "The pair's token0 is USDG and token1 is NET.",
    "The site refreshes this every 10 minutes; a check against it can differ by any trade since."
   ]
  },
  {
   "id": "lp_reserves",
   "area": "Liquidity",
   "label": "NET/USDG pool reserves",
   "unit": "USDG",
   "what": "The USDG and NET sitting in the pool.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "getReserves",
     "contract": "NET/USDG pair",
     "address": "0x59F95461E68e0c77605299791E1449f175165B54",
     "fn": "getReserves() → (uint112 USDG, uint112 NET, uint32)",
     "data": "0x0902f1ac",
     "decimals": [
      6,
      9
     ]
    }
   ],
   "formula": "getReserves(): word 0 ÷ 10^6 = USDG, word 1 ÷ 10^9 = NET",
   "steps": [
    "eth_call getReserves() on the pair.",
    "Decode word 0 as USDG (6 decimals) and word 1 as NET (9 decimals)."
   ],
   "api": {
    "path": "/api/v1/lp",
    "field": "pool.usdg"
   },
   "caveats": [
    "pool.net on the API is the NET side."
   ]
  },
  {
   "id": "lp_tvl",
   "area": "Liquidity",
   "label": "NET/USDG pool liquidity in USD",
   "unit": "USD",
   "what": "What the pool holds in dollars, counted as twice its USDG side.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "getReserves",
     "contract": "NET/USDG pair",
     "address": "0x59F95461E68e0c77605299791E1449f175165B54",
     "fn": "getReserves() → (uint112 USDG, uint112 NET, uint32)",
     "data": "0x0902f1ac",
     "decimals": [
      6,
      9
     ]
    }
   ],
   "formula": "2 × reserve0 (USDG)",
   "steps": [
    "eth_call getReserves() on the pair.",
    "Take the USDG side (word 0 ÷ 10^6) and double it: in a v2 pool both sides are worth the same at the pool's own price."
   ],
   "api": {
    "path": "/api/v1/lp",
    "field": "pool.tvlUsd"
   },
   "caveats": [
    "The NET side is valued at the pool's own spot price, not the TWAP or NAV."
   ]
  },
  {
   "id": "lp_protocol_owned",
   "area": "Liquidity",
   "label": "Protocol-owned share of the pool",
   "unit": "share",
   "what": "The share of the pool's LP tokens the Treasury holds (protocol-owned liquidity), and its dollar value.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "lpTreasury",
     "contract": "NET/USDG pair",
     "address": "0x59F95461E68e0c77605299791E1449f175165B54",
     "fn": "balanceOf(Treasury)",
     "data": "0x70a0823100000000000000000000000004822ea321a0dee6f40656172f29312104855d66",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "lpSupply",
     "contract": "NET/USDG pair",
     "address": "0x59F95461E68e0c77605299791E1449f175165B54",
     "fn": "totalSupply()",
     "data": "0x18160ddd",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "getReserves",
     "contract": "NET/USDG pair",
     "address": "0x59F95461E68e0c77605299791E1449f175165B54",
     "fn": "getReserves() → (uint112 USDG, uint112 NET, uint32)",
     "data": "0x0902f1ac",
     "decimals": [
      6,
      9
     ]
    },
    {
     "kind": "call",
     "name": "lpSleeve",
     "contract": "NET/USDG pair",
     "address": "0x59F95461E68e0c77605299791E1449f175165B54",
     "fn": "balanceOf(RWA sleeve)",
     "data": "0x70a08231000000000000000000000000498752d5fa0600cbd613074c151abe15b3fec7cb",
     "decimals": 18
    }
   ],
   "formula": "share = Pair.balanceOf(Treasury) ÷ Pair.totalSupply(); value = 2 × USDG reserve × share",
   "steps": [
    "eth_call balanceOf(Treasury) and totalSupply() on the pair (both raw LP units; the decimals cancel).",
    "Divide.",
    "Value: twice the USDG reserve × that share.",
    "The same for the RWA sleeve's Safe, which the site lists apart."
   ],
   "api": {
    "path": "/api/v1/lp",
    "field": "byClass.treasury.share"
   },
   "caveats": [
    "The site gets each holder's LP by replaying every LP Transfer since the pair was created, then checks the replayed total against totalSupply() (pool.supplyChecked). Reading balanceOf directly gives the same share when that check is true.",
    "The other classes on the site (wallet, contract, locked) need every holder's address; this recipe reads only the Treasury and the sleeve."
   ]
  },
  {
   "id": "lp_volume_7d",
   "area": "Liquidity",
   "label": "NET/USDG pool volume, last 7 days",
   "unit": "USD",
   "what": "Dollar volume traded through the pool over the last seven UTC days that had trades, with the 0.3% fees and the number of swaps.",
   "needs": [
    "eth_getLogs"
   ],
   "sources": [
    {
     "kind": "event",
     "address": "0x59F95461E68e0c77605299791E1449f175165B54",
     "event": "Swap(address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to)",
     "topic0": "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822",
     "fromBlock": "the first block of the UTC day 7 days before today"
    }
   ],
   "formula": "per swap: volume = the larger of USDG in and USDG out; fee = 0.3% × (USDG in + NET in × the swap's own price). Sum by UTC day; keep today and the 7 days before; add up the newest 7 days that had a swap.",
   "steps": [
    "Find the first block of the UTC day 7 days before today (block headers only).",
    "Read the pair's Swap logs from there to the head (topic0 = Swap).",
    "Decode the data words: USDG in (÷ 10^6), NET in (÷ 10^9), USDG out (÷ 10^6), NET out (÷ 10^9).",
    "Swap price = USDG out ÷ NET in (a sell) or USDG in ÷ NET out (a buy).",
    "Bucket each swap by the UTC day of its block, sum volume, fees and count, and keep the newest 7 buckets.",
    "Volume is rounded to the cent."
   ],
   "params": {
    "fromBlock": {
     "default": "the first block of the UTC day 7 days before today"
    }
   },
   "api": {
    "path": "/api/v1/lp",
    "field": "week.volume"
   },
   "caveats": [
    "\"7 days\" is the newest 7 UTC-day buckets with a swap, so it includes today so far: the same rule as the site.",
    "The site times swaps by interpolating between block headers every ~10 minutes; this recipe uses each log's block time (or interpolates between headers 250,000 blocks apart if the RPC sends none). A swap within seconds of midnight could fall on the other day.",
    "Only this v2 pool. Trades on the v3 pools and Uniswap v4 are not counted, as on the site's figure."
   ]
  },
  {
   "id": "bond_live_epoch",
   "area": "Bonds",
   "label": "Live bond epoch: NET sold against the cap",
   "unit": "NET",
   "what": "The depository's current 8-hour epoch: NET sold so far, the cap (0.25% of NET supply), what is left, the fill, and, from the purchase events, buyers, the average price paid and the sell-out time.",
   "needs": [
    "eth_call",
    "eth_getLogs"
   ],
   "sources": [
    {
     "kind": "call",
     "contract": "BondDepository",
     "address": "0xff32a969A0c567129eECD926D04657728E1980C1",
     "fn": "startTime()",
     "data": "0x78e97925",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "BondDepository",
     "address": "0xff32a969A0c567129eECD926D04657728E1980C1",
     "fn": "payoutInEpoch(e) for each epoch",
     "data": "0xb1554951<e as uint256>",
     "decimals": 9
    },
    {
     "kind": "call",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "fn": "totalSupply()",
     "data": "0x18160ddd",
     "decimals": 9
    },
    {
     "kind": "event",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(from 0x0) = mint, Transfer(to 0x0) = burn",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "fromBlock": "the window's first block"
    },
    {
     "kind": "event",
     "contract": "DEPOSITORY desk",
     "address": "0xff32a969A0c567129eECD926D04657728E1980C1",
     "event": "BondCreated(buyer, usdgIn, netOut, priceWad)",
     "topic0": "0xd52c75b244055af9364c0a5dc0da7868f6ae104012f245ad2702031af04d9b8e",
     "fromBlock": 11439688
    },
    {
     "kind": "event",
     "contract": "EQUITY desk",
     "address": "0xa84efc3136bf1bb89ade9e5be6ab32cb1a04f08d",
     "event": "DeskBond(buyer, token, usdgIn, netOut, priceWad, …)",
     "topic0": "0x2cfcb3ca367d7f7d6165a0805c4c4e8f66a29641cae4d57667d135fac29129e9",
     "fromBlock": 47600318
    },
    {
     "kind": "event",
     "contract": "EQUITY desk",
     "address": "0x732b3D1d3E8912CaE75164FA14a6E1c4C64615B3",
     "event": "DeskBond(buyer, token, usdgIn, netOut, priceWad, …)",
     "topic0": "0x2cfcb3ca367d7f7d6165a0805c4c4e8f66a29641cae4d57667d135fac29129e9",
     "fromBlock": 79819568
    },
    {
     "kind": "event",
     "contract": "ASSET desk",
     "address": "0x2F2F215b810Fa692304cB0095804Ab3C8e4cEf78",
     "event": "Purchase(buyer, asset, assetIn, usdIn, netOut, price, fee, routed, sleeve)",
     "topic0": "0xdec46cdd0be10d522b17d462ec4f74dd8f90bd2a62eab8d79d863e0c7845af26",
     "fromBlock": 70000046
    },
    {
     "kind": "event",
     "contract": "NET/USDG v2 pair",
     "address": "0x59F95461E68e0c77605299791E1449f175165B54",
     "event": "Sync(uint112 reserve0, uint112 reserve1)",
     "topic0": "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1",
     "fromBlock": "the window's first block"
    },
    {
     "kind": "event",
     "contract": "NET/USDG v3 pool",
     "address": "0x99e70A5b06215e5D2F3BeC773b4f59c008fc1673",
     "event": "Swap(sender, recipient, amount0, amount1, sqrtPriceX96, liquidity, tick)",
     "topic0": "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67",
     "fromBlock": "the window's first block"
    },
    {
     "kind": "event",
     "contract": "NET/USDG v3 pool",
     "address": "0x813fBeF16E3D3529b6339ccaa03AF4df803E3862",
     "event": "Swap(sender, recipient, amount0, amount1, sqrtPriceX96, liquidity, tick)",
     "topic0": "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67",
     "fromBlock": "the window's first block"
    }
   ],
   "formula": "epoch = ⌊(now − startTime()) ÷ 28,800⌋; sold = payoutInEpoch(epoch); cap = NET supply at the open × 0.0025; fill = sold ÷ cap (sold out at 98%); remaining = cap − sold",
   "steps": [
    "eth_call BondDepository.startTime(); epoch = ⌊(head time − startTime) ÷ 28,800⌋, open = startTime + epoch × 28,800",
    "eth_call payoutInEpoch(epoch) ÷ 1e9: NET paid out in the epoch so far (USDG and LP series together)",
    "cap: NET.totalSupply() now, less mints plus burns since the open (capAt: \"now\" skips this and uses today's supply)",
    "BondCreated logs since the open: buyers, NET-weighted average price, and the first second cumulative NET reached 98% of the cap"
   ],
   "params": {
    "capAt": "\"open\" (default: supply at the open, as /api/v1/bonds live.capNet) or \"now\" (today's supply, as the Bonds page's live card)"
   },
   "api": {
    "path": "/api/v1/bonds",
    "field": "live.netSold (and live.capNet, live.fill, live.soldOut, live.selloutSec, live.buyers, live.avgPrice)"
   },
   "caveats": [
    "Cap: 0.25% of NET supply at the epoch's open. The site takes supply from the hourly snapshot at or before the open; here it is today's totalSupply() less every mint and plus every burn since the open (NET Transfer from / to 0x0), so a mint in the hour before the open makes this cap slightly larger.",
    "The served row is refreshed by the bond-tape job about every 15 minutes, so a live epoch still selling shows more sold here."
   ]
  },
  {
   "id": "bond_prices",
   "area": "Bonds",
   "label": "Bond prices against the market",
   "unit": "USD per NET",
   "what": "What each desk sells NET at right now (USDG per NET), against the protocol's TWAP and the v2 pool: the discount, and NET per USDG against buying on the exchange after its 5% levy.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "contract": "BondDepository",
     "address": "0xff32a969A0c567129eECD926D04657728E1980C1",
     "fn": "marketCount(), enabled(), bondPrice(i), quoteToken(i)",
     "data": "0xec979082, 0x238dafe0, 0x172c44ec<i>, 0x5f2b0420<i>",
     "decimals": 18
    },
    {
     "kind": "call",
     "contract": "BondDepository",
     "address": "0xff32a969A0c567129eECD926D04657728E1980C1",
     "fn": "startTime(), payoutInEpoch(epoch)",
     "data": "0x78e97925, 0xb1554951<e>",
     "decimals": 9
    },
    {
     "kind": "call",
     "contract": "Sleeve bond desk",
     "address": "0x732b3D1d3E8912CaE75164FA14a6E1c4C64615B3",
     "fn": "bondPrice(), deskDiscountBps(), inventory(), inventoryMax(), halted()",
     "data": "0xd7ccfb0b, 0x7d6abb36, 0x15d52a5c, 0xb884386b, 0xb9b8af0b",
     "decimals": 18
    },
    {
     "kind": "call",
     "contract": "Asset bond desk",
     "address": "0x2F2F215b810Fa692304cB0095804Ab3C8e4cEf78",
     "fn": "bondPrice(), deskDiscountBps(), inventory(), halted()",
     "data": "0xd7ccfb0b, 0x7d6abb36, 0x15d52a5c, 0xb9b8af0b",
     "decimals": 18
    },
    {
     "kind": "call",
     "contract": "PairOracle",
     "address": "0x929631b33F4070D6f54477fba3FD27566567dAca",
     "fn": "twapNetUsdg()",
     "data": "0x10aa790e",
     "decimals": 18
    },
    {
     "kind": "call",
     "contract": "NET/USDG v2 pair",
     "address": "0x59F95461E68e0c77605299791E1449f175165B54",
     "fn": "getReserves(), token0()",
     "data": "0x0902f1ac, 0x0dfe1681",
     "decimals": "6 / 9"
    },
    {
     "kind": "call",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "fn": "totalSupply()",
     "data": "0x18160ddd",
     "decimals": 9
    }
   ],
   "formula": "vsTwap = price ÷ twapNetUsdg() − 1; vsPool = price ÷ (USDG reserve ÷ NET reserve) − 1; advantage = (1 ÷ price) ÷ (0.95 ÷ TWAP) − 1; depository capacity = (cap − payoutInEpoch) × 0.99 NET",
   "steps": [
    "eth_call each desk's bondPrice (the depository per series i < marketCount(); a closed series reverts and is skipped)",
    "eth_call PairOracle.twapNetUsdg() and the v2 pair's getReserves(): the market",
    "discount = 1 − price ÷ market; advantage against buying on the exchange: NET per USDG ÷ (0.95 ÷ TWAP) − 1",
    "the depository's room this epoch: (supply × 0.0025 − payoutInEpoch) × 0.99 NET; under 10 USDG of room reads sold out"
   ],
   "params": {},
   "api": {
    "path": "/api/v1/predict/intel",
    "field": "drivers.bondCapacityLeft.bondPrice (the depository's USDG-series price)"
   },
   "caveats": [
    "The site's served bond price lives in the Predict model's drivers (null when the model has no open series); the Bonds page reads these same getters live.",
    "The site's subscription routes also apply desk rules not repeated here (the 1.2 × high-water floor guard, equity market hours, asset-route oracle health)."
   ]
  },
  {
   "id": "bond_sales",
   "area": "Bonds",
   "label": "Every bond sale",
   "unit": "NET",
   "what": "Every purchase on the three bond desks (depository, equity desk, asset desk) over a window, decoded from their events: buyer, what was paid, NET bought, the price.",
   "needs": [
    "eth_getLogs"
   ],
   "sources": [
    {
     "kind": "event",
     "contract": "DEPOSITORY desk",
     "address": "0xff32a969A0c567129eECD926D04657728E1980C1",
     "event": "BondCreated(buyer, usdgIn, netOut, priceWad)",
     "topic0": "0xd52c75b244055af9364c0a5dc0da7868f6ae104012f245ad2702031af04d9b8e",
     "fromBlock": 11439688
    },
    {
     "kind": "event",
     "contract": "EQUITY desk",
     "address": "0xa84efc3136bf1bb89ade9e5be6ab32cb1a04f08d",
     "event": "DeskBond(buyer, token, usdgIn, netOut, priceWad, …)",
     "topic0": "0x2cfcb3ca367d7f7d6165a0805c4c4e8f66a29641cae4d57667d135fac29129e9",
     "fromBlock": 47600318
    },
    {
     "kind": "event",
     "contract": "EQUITY desk",
     "address": "0x732b3D1d3E8912CaE75164FA14a6E1c4C64615B3",
     "event": "DeskBond(buyer, token, usdgIn, netOut, priceWad, …)",
     "topic0": "0x2cfcb3ca367d7f7d6165a0805c4c4e8f66a29641cae4d57667d135fac29129e9",
     "fromBlock": 79819568
    },
    {
     "kind": "event",
     "contract": "ASSET desk",
     "address": "0x2F2F215b810Fa692304cB0095804Ab3C8e4cEf78",
     "event": "Purchase(buyer, asset, assetIn, usdIn, netOut, price, fee, routed, sleeve)",
     "topic0": "0xdec46cdd0be10d522b17d462ec4f74dd8f90bd2a62eab8d79d863e0c7845af26",
     "fromBlock": 70000046
    }
   ],
   "formula": "per log: DEPOSITORY usdIn = w0 ÷ 1e6, netOut = w1 ÷ 1e9, price = w2 ÷ 1e18; EQUITY token = topic2, usdIn = w0 ÷ 1e6, netOut = w1 ÷ 1e9, price = w2 ÷ 1e18; ASSET asset = topic2, assetIn = w0 ÷ 1e18, usdIn = w1 ÷ 1e18, netOut = w2 ÷ 1e9, price = w3 ÷ 1e18, fee = w4 ÷ 1e6; buyer = topic1",
   "steps": [
    "find the block at the window's start (block times by interpolation search)",
    "eth_getLogs each desk's purchase topic0 from there to the head (chunked over 10M-block spans)",
    "decode each log as in the formula and sum by desk"
   ],
   "params": {
    "days": "window in days (default 7)",
    "fromBlock": "start block instead of days",
    "desk": "\"DEPOSITORY\", \"EQUITY\" or \"ASSET\" (default all)"
   },
   "api": {
    "path": "/api/v1/bonds",
    "field": "epochs[].netSold, epochs[].usdgRaised, epochs[].buys (depository), epochs[].viaEquity, epochs[].viaAssets"
   },
   "caveats": [
    "The site's tape keeps 7 days of raw purchases (from the explorer's log API, falling back to the chain); the sleeve desk's own cursor starts at block 79,819,568, so its earliest days are read here as the site reads them.",
    "Equity desk logs are one per subscribed token: a purchase spread over several equities shows as several rows."
   ]
  },
  {
   "id": "bond_buyers",
   "area": "Bonds",
   "label": "Bond buyers, all time",
   "unit": "addresses",
   "what": "Every address that has bonded, with its all-time NET bought and USD paid per desk, first and last purchase: the bond desks' purchase events summed per buyer since each desk's first block.",
   "needs": [
    "eth_getLogs"
   ],
   "sources": [
    {
     "kind": "event",
     "contract": "DEPOSITORY desk",
     "address": "0xff32a969A0c567129eECD926D04657728E1980C1",
     "event": "BondCreated(buyer, usdgIn, netOut, priceWad)",
     "topic0": "0xd52c75b244055af9364c0a5dc0da7868f6ae104012f245ad2702031af04d9b8e",
     "fromBlock": 11439688
    },
    {
     "kind": "event",
     "contract": "EQUITY desk",
     "address": "0xa84efc3136bf1bb89ade9e5be6ab32cb1a04f08d",
     "event": "DeskBond(buyer, token, usdgIn, netOut, priceWad, …)",
     "topic0": "0x2cfcb3ca367d7f7d6165a0805c4c4e8f66a29641cae4d57667d135fac29129e9",
     "fromBlock": 47600318
    },
    {
     "kind": "event",
     "contract": "EQUITY desk",
     "address": "0x732b3D1d3E8912CaE75164FA14a6E1c4C64615B3",
     "event": "DeskBond(buyer, token, usdgIn, netOut, priceWad, …)",
     "topic0": "0x2cfcb3ca367d7f7d6165a0805c4c4e8f66a29641cae4d57667d135fac29129e9",
     "fromBlock": 79819568
    },
    {
     "kind": "event",
     "contract": "ASSET desk",
     "address": "0x2F2F215b810Fa692304cB0095804Ab3C8e4cEf78",
     "event": "Purchase(buyer, asset, assetIn, usdIn, netOut, price, fee, routed, sleeve)",
     "topic0": "0xdec46cdd0be10d522b17d462ec4f74dd8f90bd2a62eab8d79d863e0c7845af26",
     "fromBlock": 70000046
    }
   ],
   "formula": "per buyer: Σ netOut, Σ usdIn (per desk and total), distinct transactions, first and last purchase time; paid in USDG on the depository and equity desk, in the listed asset on the asset desk",
   "steps": [
    "eth_getLogs every desk's purchase topic0 from its first block",
    "decode (see bond_sales) and group by topic1 (the buyer)",
    "sort by total NET"
   ],
   "params": {
    "top": "rows returned (default 100)",
    "fromBlock": "start block (default each desk's first block)"
   },
   "api": {
    "path": "/bonds (the Bonds page's buyers table, BondBuyer; not in /api/v1)",
    "field": "BondBuyer.totalNet, totalUsd, txCount, firstTs, lastTs"
   },
   "caveats": [
    "A full rebuild reads each desk from its first block (the depository from 11,439,688): 8 or so 10M-block requests per desk, filtered to one topic, so the logs stay small.",
    "The site stores the same totals incrementally per desk cursor; transactions are counted per desk, so a transaction touching two desks counts on each."
   ]
  },
  {
   "id": "bond_epochs",
   "area": "Bonds",
   "label": "Bond epochs: sold against the cap",
   "unit": "epochs sold out",
   "what": "Every recent 8-hour depository epoch as the Bonds page shows it: NET sold against the cap, the fill after 1, 2 and 4 hours, the sell-out time, buyers, the price paid against the pool and after the vest, and what the other two desks sold in the same window.",
   "needs": [
    "eth_call",
    "eth_getLogs"
   ],
   "sources": [
    {
     "kind": "call",
     "contract": "BondDepository",
     "address": "0xff32a969A0c567129eECD926D04657728E1980C1",
     "fn": "startTime()",
     "data": "0x78e97925",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "BondDepository",
     "address": "0xff32a969A0c567129eECD926D04657728E1980C1",
     "fn": "payoutInEpoch(e) for each epoch",
     "data": "0xb1554951<e as uint256>",
     "decimals": 9
    },
    {
     "kind": "call",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "fn": "totalSupply()",
     "data": "0x18160ddd",
     "decimals": 9
    },
    {
     "kind": "event",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(from 0x0) = mint, Transfer(to 0x0) = burn",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "fromBlock": "the window's first block"
    },
    {
     "kind": "event",
     "contract": "DEPOSITORY desk",
     "address": "0xff32a969A0c567129eECD926D04657728E1980C1",
     "event": "BondCreated(buyer, usdgIn, netOut, priceWad)",
     "topic0": "0xd52c75b244055af9364c0a5dc0da7868f6ae104012f245ad2702031af04d9b8e",
     "fromBlock": 11439688
    },
    {
     "kind": "event",
     "contract": "EQUITY desk",
     "address": "0xa84efc3136bf1bb89ade9e5be6ab32cb1a04f08d",
     "event": "DeskBond(buyer, token, usdgIn, netOut, priceWad, …)",
     "topic0": "0x2cfcb3ca367d7f7d6165a0805c4c4e8f66a29641cae4d57667d135fac29129e9",
     "fromBlock": 47600318
    },
    {
     "kind": "event",
     "contract": "EQUITY desk",
     "address": "0x732b3D1d3E8912CaE75164FA14a6E1c4C64615B3",
     "event": "DeskBond(buyer, token, usdgIn, netOut, priceWad, …)",
     "topic0": "0x2cfcb3ca367d7f7d6165a0805c4c4e8f66a29641cae4d57667d135fac29129e9",
     "fromBlock": 79819568
    },
    {
     "kind": "event",
     "contract": "ASSET desk",
     "address": "0x2F2F215b810Fa692304cB0095804Ab3C8e4cEf78",
     "event": "Purchase(buyer, asset, assetIn, usdIn, netOut, price, fee, routed, sleeve)",
     "topic0": "0xdec46cdd0be10d522b17d462ec4f74dd8f90bd2a62eab8d79d863e0c7845af26",
     "fromBlock": 70000046
    },
    {
     "kind": "event",
     "contract": "NET/USDG v2 pair",
     "address": "0x59F95461E68e0c77605299791E1449f175165B54",
     "event": "Sync(uint112 reserve0, uint112 reserve1)",
     "topic0": "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1",
     "fromBlock": "the window's first block"
    },
    {
     "kind": "event",
     "contract": "NET/USDG v3 pool",
     "address": "0x99e70A5b06215e5D2F3BeC773b4f59c008fc1673",
     "event": "Swap(sender, recipient, amount0, amount1, sqrtPriceX96, liquidity, tick)",
     "topic0": "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67",
     "fromBlock": "the window's first block"
    },
    {
     "kind": "event",
     "contract": "NET/USDG v3 pool",
     "address": "0x813fBeF16E3D3529b6339ccaa03AF4df803E3862",
     "event": "Swap(sender, recipient, amount0, amount1, sqrtPriceX96, liquidity, tick)",
     "topic0": "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67",
     "fromBlock": "the window's first block"
    }
   ],
   "formula": "sold = payoutInEpoch(e); cap = supply at open × 0.0025; sold out when sold ≥ 98% of cap; h1/h2/h4 = cumulative NET bought ≤ 1/2/4 h after the open; selloutSec = first second cumulative ≥ 98% of cap; avgPrice = Σ price × net ÷ Σ net; mktAvg = Σ market price at each purchase × net ÷ Σ net; paidVsMarket = avgPrice ÷ mktAvg − 1; afterVest = market 2 days after the close ÷ avgPrice − 1",
   "steps": [
    "eth_call startTime() and payoutInEpoch(e) for each epoch",
    "the block at the first epoch's open, then every desk's purchase logs from there (bond_sales)",
    "NET mints and burns since then for the supply at each open; the pools' Sync / Swap events for the market price",
    "group the depository purchases by epoch = ⌊(time − startTime) ÷ 28,800⌋ and apply the formula"
   ],
   "params": {
    "epochs": "how many 8-hour epochs, newest last (default 21 = 7 days; the site keeps 90)",
    "market": "\"all\" (default: the mean of the v2 pair and both v3 pools, as the site's snapshot price) or \"v2\"",
    "newBuyers": "true also reads every desk from its first block to count buyers new to all desks (default false)"
   },
   "api": {
    "path": "/api/v1/bonds?epochs=21",
    "field": "epochs[] (netSold, capNet, fill, soldOut, selloutSec, soldAfter1h/2h/4h, usdgRaised, buys, buyers, avgPrice, marketAvgPrice, paidVsMarket, afterVest)"
   },
   "caveats": [
    "Cap: 0.25% of NET supply at the epoch's open. The site takes supply from the hourly snapshot at or before the open; here it is today's totalSupply() less every mint and plus every burn since the open (NET Transfer from / to 0x0), so a mint in the hour before the open makes this cap slightly larger.",
    "Market price: the site uses its hourly snapshot (the mean of the v2 pair's balance price and the two v3 pools' slot0 prices, read on the hour, so up to an hour old at a purchase). Here the same three pools are read from their own Sync / Swap events at the exact second, so paidVsMarket and the market prices differ by however far the pools moved within the hour. A pool with no trade in the window counts at its current price; one with trades only later in the window is left out of the mean until its first trade.",
    "Epochs older than the site's 7-day raw tape keep the figures the site gave them while they were inside it (or a chain backfill whose purchase times were interpolated within 80k-block windows); here every epoch is rebuilt from exact block times, so sell-out times can differ by seconds to minutes there.",
    "The site rounds NET to 0.1 and prices to 0.1; these are unrounded."
   ]
  },
  {
   "id": "bond_fill_speed",
   "area": "Bonds",
   "label": "How fast bond epochs sell out",
   "unit": "seconds (median)",
   "what": "The median time from an epoch's open to 98% of its cap sold, over the finished epochs of the window, with the share sold after 1, 2 and 4 hours and the sold-out streak.",
   "needs": [
    "eth_call",
    "eth_getLogs"
   ],
   "sources": [
    {
     "kind": "call",
     "contract": "BondDepository",
     "address": "0xff32a969A0c567129eECD926D04657728E1980C1",
     "fn": "startTime()",
     "data": "0x78e97925",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "BondDepository",
     "address": "0xff32a969A0c567129eECD926D04657728E1980C1",
     "fn": "payoutInEpoch(e) for each epoch",
     "data": "0xb1554951<e as uint256>",
     "decimals": 9
    },
    {
     "kind": "call",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "fn": "totalSupply()",
     "data": "0x18160ddd",
     "decimals": 9
    },
    {
     "kind": "event",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(from 0x0) = mint, Transfer(to 0x0) = burn",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "fromBlock": "the window's first block"
    },
    {
     "kind": "event",
     "contract": "DEPOSITORY desk",
     "address": "0xff32a969A0c567129eECD926D04657728E1980C1",
     "event": "BondCreated(buyer, usdgIn, netOut, priceWad)",
     "topic0": "0xd52c75b244055af9364c0a5dc0da7868f6ae104012f245ad2702031af04d9b8e",
     "fromBlock": 11439688
    },
    {
     "kind": "event",
     "contract": "EQUITY desk",
     "address": "0xa84efc3136bf1bb89ade9e5be6ab32cb1a04f08d",
     "event": "DeskBond(buyer, token, usdgIn, netOut, priceWad, …)",
     "topic0": "0x2cfcb3ca367d7f7d6165a0805c4c4e8f66a29641cae4d57667d135fac29129e9",
     "fromBlock": 47600318
    },
    {
     "kind": "event",
     "contract": "EQUITY desk",
     "address": "0x732b3D1d3E8912CaE75164FA14a6E1c4C64615B3",
     "event": "DeskBond(buyer, token, usdgIn, netOut, priceWad, …)",
     "topic0": "0x2cfcb3ca367d7f7d6165a0805c4c4e8f66a29641cae4d57667d135fac29129e9",
     "fromBlock": 79819568
    },
    {
     "kind": "event",
     "contract": "ASSET desk",
     "address": "0x2F2F215b810Fa692304cB0095804Ab3C8e4cEf78",
     "event": "Purchase(buyer, asset, assetIn, usdIn, netOut, price, fee, routed, sleeve)",
     "topic0": "0xdec46cdd0be10d522b17d462ec4f74dd8f90bd2a62eab8d79d863e0c7845af26",
     "fromBlock": 70000046
    },
    {
     "kind": "event",
     "contract": "NET/USDG v2 pair",
     "address": "0x59F95461E68e0c77605299791E1449f175165B54",
     "event": "Sync(uint112 reserve0, uint112 reserve1)",
     "topic0": "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1",
     "fromBlock": "the window's first block"
    },
    {
     "kind": "event",
     "contract": "NET/USDG v3 pool",
     "address": "0x99e70A5b06215e5D2F3BeC773b4f59c008fc1673",
     "event": "Swap(sender, recipient, amount0, amount1, sqrtPriceX96, liquidity, tick)",
     "topic0": "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67",
     "fromBlock": "the window's first block"
    },
    {
     "kind": "event",
     "contract": "NET/USDG v3 pool",
     "address": "0x813fBeF16E3D3529b6339ccaa03AF4df803E3862",
     "event": "Swap(sender, recipient, amount0, amount1, sqrtPriceX96, liquidity, tick)",
     "topic0": "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67",
     "fromBlock": "the window's first block"
    }
   ],
   "formula": "median of selloutSec over finished, sold-out epochs; soldAfterNh share = median of hN ÷ cap; streak = finished epochs sold out in a row up to now; speed = this window's median against the one before (faster < 0.85×, slower > 1.15×)",
   "steps": [
    "build the epoch rows (bond_epochs) for 2 × epochs",
    "take the finished epochs; demandTrend() from src/lib/bondDemand.js for the streak and the speed verdict"
   ],
   "params": {
    "epochs": "window in epochs (default 21 = 7 days; twice as many are read for the comparison)",
    "market": "\"all\" (default: the mean of the v2 pair and both v3 pools, as the site's snapshot price) or \"v2\""
   },
   "api": {
    "path": "/api/v1/bonds",
    "field": "epochs[].selloutSec, epochs[].soldAfter1h / soldAfter2h / soldAfter4h"
   },
   "caveats": [
    "Cap: 0.25% of NET supply at the epoch's open. The site takes supply from the hourly snapshot at or before the open; here it is today's totalSupply() less every mint and plus every burn since the open (NET Transfer from / to 0x0), so a mint in the hour before the open makes this cap slightly larger.",
    "Sell-out needs every purchase of the epoch; the site's figure for an epoch older than its 7-day tape is the one it computed then (see bond_epochs)."
   ]
  },
  {
   "id": "bond_paid_vs_market",
   "area": "Bonds",
   "label": "What bond buyers paid against the market",
   "unit": "fraction",
   "what": "The average price bond buyers paid against the pool price at the moment they bought (negative = a discount), and what that NET was worth once it vested two days after the epoch.",
   "needs": [
    "eth_call",
    "eth_getLogs"
   ],
   "sources": [
    {
     "kind": "call",
     "contract": "BondDepository",
     "address": "0xff32a969A0c567129eECD926D04657728E1980C1",
     "fn": "startTime()",
     "data": "0x78e97925",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "BondDepository",
     "address": "0xff32a969A0c567129eECD926D04657728E1980C1",
     "fn": "payoutInEpoch(e) for each epoch",
     "data": "0xb1554951<e as uint256>",
     "decimals": 9
    },
    {
     "kind": "call",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "fn": "totalSupply()",
     "data": "0x18160ddd",
     "decimals": 9
    },
    {
     "kind": "event",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(from 0x0) = mint, Transfer(to 0x0) = burn",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "fromBlock": "the window's first block"
    },
    {
     "kind": "event",
     "contract": "DEPOSITORY desk",
     "address": "0xff32a969A0c567129eECD926D04657728E1980C1",
     "event": "BondCreated(buyer, usdgIn, netOut, priceWad)",
     "topic0": "0xd52c75b244055af9364c0a5dc0da7868f6ae104012f245ad2702031af04d9b8e",
     "fromBlock": 11439688
    },
    {
     "kind": "event",
     "contract": "EQUITY desk",
     "address": "0xa84efc3136bf1bb89ade9e5be6ab32cb1a04f08d",
     "event": "DeskBond(buyer, token, usdgIn, netOut, priceWad, …)",
     "topic0": "0x2cfcb3ca367d7f7d6165a0805c4c4e8f66a29641cae4d57667d135fac29129e9",
     "fromBlock": 47600318
    },
    {
     "kind": "event",
     "contract": "EQUITY desk",
     "address": "0x732b3D1d3E8912CaE75164FA14a6E1c4C64615B3",
     "event": "DeskBond(buyer, token, usdgIn, netOut, priceWad, …)",
     "topic0": "0x2cfcb3ca367d7f7d6165a0805c4c4e8f66a29641cae4d57667d135fac29129e9",
     "fromBlock": 79819568
    },
    {
     "kind": "event",
     "contract": "ASSET desk",
     "address": "0x2F2F215b810Fa692304cB0095804Ab3C8e4cEf78",
     "event": "Purchase(buyer, asset, assetIn, usdIn, netOut, price, fee, routed, sleeve)",
     "topic0": "0xdec46cdd0be10d522b17d462ec4f74dd8f90bd2a62eab8d79d863e0c7845af26",
     "fromBlock": 70000046
    },
    {
     "kind": "event",
     "contract": "NET/USDG v2 pair",
     "address": "0x59F95461E68e0c77605299791E1449f175165B54",
     "event": "Sync(uint112 reserve0, uint112 reserve1)",
     "topic0": "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1",
     "fromBlock": "the window's first block"
    },
    {
     "kind": "event",
     "contract": "NET/USDG v3 pool",
     "address": "0x99e70A5b06215e5D2F3BeC773b4f59c008fc1673",
     "event": "Swap(sender, recipient, amount0, amount1, sqrtPriceX96, liquidity, tick)",
     "topic0": "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67",
     "fromBlock": "the window's first block"
    },
    {
     "kind": "event",
     "contract": "NET/USDG v3 pool",
     "address": "0x813fBeF16E3D3529b6339ccaa03AF4df803E3862",
     "event": "Swap(sender, recipient, amount0, amount1, sqrtPriceX96, liquidity, tick)",
     "topic0": "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67",
     "fromBlock": "the window's first block"
    }
   ],
   "formula": "per epoch paidVsMarket = avgPrice ÷ mktAvg − 1, afterVest = mktVested ÷ avgPrice − 1; value = mean paidVsMarket over the window's epochs",
   "steps": [
    "build the epoch rows (bond_epochs)",
    "mean of paidVsMarket and of afterVest over the epochs that have them"
   ],
   "params": {
    "epochs": "how many 8-hour epochs, newest last (default 21 = 7 days; the site keeps 90)",
    "market": "\"all\" (default: the mean of the v2 pair and both v3 pools, as the site's snapshot price) or \"v2\"",
    "newBuyers": "true also reads every desk from its first block to count buyers new to all desks (default false)"
   },
   "api": {
    "path": "/api/v1/bonds",
    "field": "epochs[].paidVsMarket, epochs[].afterVest (and demandByTrend.buckets[].medianPaidVsMarket)"
   },
   "caveats": [
    "Market price: the site uses its hourly snapshot (the mean of the v2 pair's balance price and the two v3 pools' slot0 prices, read on the hour, so up to an hour old at a purchase). Here the same three pools are read from their own Sync / Swap events at the exact second, so paidVsMarket and the market prices differ by however far the pools moved within the hour. A pool with no trade in the window counts at its current price; one with trades only later in the window is left out of the mean until its first trade."
   ]
  },
  {
   "id": "bond_demand_by_trend",
   "area": "Bonds",
   "label": "Bond demand by NET's price trend",
   "unit": "rank correlation",
   "what": "Does bond demand hold up when NET falls? Each finished epoch's price change going in (the pool price at its open against 8h, 24h or 3 days before), bucketed, against how fast it sold out.",
   "needs": [
    "eth_call",
    "eth_getLogs"
   ],
   "sources": [
    {
     "kind": "call",
     "contract": "BondDepository",
     "address": "0xff32a969A0c567129eECD926D04657728E1980C1",
     "fn": "startTime()",
     "data": "0x78e97925",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "BondDepository",
     "address": "0xff32a969A0c567129eECD926D04657728E1980C1",
     "fn": "payoutInEpoch(e) for each epoch",
     "data": "0xb1554951<e as uint256>",
     "decimals": 9
    },
    {
     "kind": "call",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "fn": "totalSupply()",
     "data": "0x18160ddd",
     "decimals": 9
    },
    {
     "kind": "event",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(from 0x0) = mint, Transfer(to 0x0) = burn",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "fromBlock": "the window's first block"
    },
    {
     "kind": "event",
     "contract": "DEPOSITORY desk",
     "address": "0xff32a969A0c567129eECD926D04657728E1980C1",
     "event": "BondCreated(buyer, usdgIn, netOut, priceWad)",
     "topic0": "0xd52c75b244055af9364c0a5dc0da7868f6ae104012f245ad2702031af04d9b8e",
     "fromBlock": 11439688
    },
    {
     "kind": "event",
     "contract": "EQUITY desk",
     "address": "0xa84efc3136bf1bb89ade9e5be6ab32cb1a04f08d",
     "event": "DeskBond(buyer, token, usdgIn, netOut, priceWad, …)",
     "topic0": "0x2cfcb3ca367d7f7d6165a0805c4c4e8f66a29641cae4d57667d135fac29129e9",
     "fromBlock": 47600318
    },
    {
     "kind": "event",
     "contract": "EQUITY desk",
     "address": "0x732b3D1d3E8912CaE75164FA14a6E1c4C64615B3",
     "event": "DeskBond(buyer, token, usdgIn, netOut, priceWad, …)",
     "topic0": "0x2cfcb3ca367d7f7d6165a0805c4c4e8f66a29641cae4d57667d135fac29129e9",
     "fromBlock": 79819568
    },
    {
     "kind": "event",
     "contract": "ASSET desk",
     "address": "0x2F2F215b810Fa692304cB0095804Ab3C8e4cEf78",
     "event": "Purchase(buyer, asset, assetIn, usdIn, netOut, price, fee, routed, sleeve)",
     "topic0": "0xdec46cdd0be10d522b17d462ec4f74dd8f90bd2a62eab8d79d863e0c7845af26",
     "fromBlock": 70000046
    },
    {
     "kind": "event",
     "contract": "NET/USDG v2 pair",
     "address": "0x59F95461E68e0c77605299791E1449f175165B54",
     "event": "Sync(uint112 reserve0, uint112 reserve1)",
     "topic0": "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1",
     "fromBlock": "the window's first block"
    },
    {
     "kind": "event",
     "contract": "NET/USDG v3 pool",
     "address": "0x99e70A5b06215e5D2F3BeC773b4f59c008fc1673",
     "event": "Swap(sender, recipient, amount0, amount1, sqrtPriceX96, liquidity, tick)",
     "topic0": "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67",
     "fromBlock": "the window's first block"
    },
    {
     "kind": "event",
     "contract": "NET/USDG v3 pool",
     "address": "0x813fBeF16E3D3529b6339ccaa03AF4df803E3862",
     "event": "Swap(sender, recipient, amount0, amount1, sqrtPriceX96, liquidity, tick)",
     "topic0": "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67",
     "fromBlock": "the window's first block"
    }
   ],
   "formula": "chg = mktOpen(e) ÷ mktOpen(e − lag) − 1 (lag 1, 3 or 9 epochs); buckets: ≤ −10%, −10% to −3%, ±3%, ≥ +3%; rho = Spearman(chg, time to sell out, a missed epoch ranking slowest)",
   "steps": [
    "build 90 epochs of rows (bond_epochs)",
    "priceTrend(rows, cur, lag) and trendTable() from src/lib/bondDemand.js, the site's own functions"
   ],
   "params": {
    "trend": "\"8h\", \"24h\" (default) or \"3d\"",
    "epochs": "epochs read (default 90, the site's window)",
    "market": "\"all\" (default: the mean of the v2 pair and both v3 pools, as the site's snapshot price) or \"v2\""
   },
   "api": {
    "path": "/api/v1/bonds?trend=24h",
    "field": "demandByTrend.rankCorrelation (and buckets[], direction, answer)"
   },
   "caveats": [
    "Market price: the site uses its hourly snapshot (the mean of the v2 pair's balance price and the two v3 pools' slot0 prices, read on the hour, so up to an hour old at a purchase). Here the same three pools are read from their own Sync / Swap events at the exact second, so paidVsMarket and the market prices differ by however far the pools moved within the hour. A pool with no trade in the window counts at its current price; one with trades only later in the window is left out of the mean until its first trade.",
    "The site's price at each open is its hourly snapshot; a pair of identical prices (a snapshot gap) is dropped there, which pool events rarely produce, so a few more epochs can count here."
   ]
  },
  {
   "id": "advance_terms",
   "area": "NET Advance",
   "label": "NET Advance terms",
   "unit": "share of the lock's value",
   "what": "What one lock pays and costs: the advance share, the fee, the Treasury's escrow, the term and the caps.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "advanceBps",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "ADVANCE_BPS()",
     "data": "0xe9bdd3e6",
     "decimals": 0
    },
    {
     "kind": "call",
     "name": "feeBps",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "FEE_BPS()",
     "data": "0xbf333f2c",
     "decimals": 0
    },
    {
     "kind": "call",
     "name": "treasuryBps",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "TREASURY_BPS()",
     "data": "0x4c25d197",
     "decimals": 0
    },
    {
     "kind": "call",
     "name": "term",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "TERM()",
     "data": "0x5ea25e28",
     "decimals": 0
    },
    {
     "kind": "call",
     "name": "maxPerPositionUsdg",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "MAX_ADVANCE_PER_POSITION()",
     "data": "0x80c160cd",
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "minLockNet",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "MIN_LOCK_NET()",
     "data": "0x9acfd687",
     "decimals": 9
    }
   ],
   "formula": "advance = ADVANCE_BPS ÷ 10,000 of the lock's value; owed = advance × (1 + (FEE_BPS + TREASURY_BPS) ÷ 10,000); term = TERM seconds",
   "steps": [
    "eth_call each getter on the desk",
    "the BPS getters are plain integers (10,000 = 100%); TERM is seconds; MAX_ADVANCE_PER_POSITION has 6 decimals (USDG); MIN_LOCK_NET has 9 (NET)",
    "owed share of the lock = advance share × (1 + fee + treasury)"
   ],
   "api": {
    "path": "/api/v1/advance",
    "field": "terms.advanceBps",
    "part": "advanceBps"
   },
   "caveats": [
    "The desk's owner can change the terms; read them at the block you check."
   ]
  },
  {
   "id": "advance_desk",
   "area": "NET Advance",
   "label": "NET Advance desk: USDG free for new locks",
   "unit": "USDG",
   "what": "The desk's totals: USDG not yet committed (unallocated), the Treasury escrow it holds, the wsNET it holds, positions, and its marks.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "unallocated",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "unallocated()",
     "data": "0xdf1c455c",
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "capacity",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "capacity()",
     "data": "0x5cfc1a51",
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "maxAdvance",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "maxAdvance()",
     "data": "0xc668e935",
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "escrowed",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "escrowed()",
     "data": "0x01522b1e",
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "inventoryWs",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "inventory()",
     "data": "0x15d52a5c",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "lockedWs",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "lockedTotal()",
     "data": "0xf145c73b",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "positions",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "positionCount()",
     "data": "0xe7702d05",
     "decimals": 0
    },
    {
     "kind": "call",
     "name": "halted",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "halted()",
     "data": "0xb9b8af0b",
     "decimals": 0
    },
    {
     "kind": "call",
     "name": "mark",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "mark()",
     "data": "0x8c0d0c29",
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "openMark",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "openMark()",
     "data": "0x05b918fe",
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "treasuryOwed",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "treasuryOwed()",
     "data": "0x75c3fc13",
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "index",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "index()",
     "data": "0x2986c0e5",
     "decimals": 9
    }
   ],
   "formula": "unallocated(); mark per NET = mark() ÷ sNET.index(); openMark per NET = openMark() ÷ sNET.index()",
   "steps": [
    "eth_call each getter",
    "USDG getters ÷ 1e6; inventory() and lockedTotal() are wsNET ÷ 1e18; mark() and openMark() are USDG per wsNET ÷ 1e6",
    "sNET.index() ÷ 1e9 converts: per NET = per wsNET ÷ index"
   ],
   "api": {
    "path": "/api/v1/advance",
    "field": "desk.unallocated"
   },
   "caveats": [
    "/api/v1/advance serves the desk from a cache refreshed at most every 3 minutes."
   ]
  },
  {
   "id": "advance_mark",
   "area": "NET Advance",
   "label": "NET Advance mark per NET",
   "unit": "USD per NET",
   "what": "The price the desk settles closes at, per NET: its mark() (USDG per wsNET) ÷ the staking index. openMark() is what new locks are sized on.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "mark",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "mark()",
     "data": "0x8c0d0c29",
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "openMark",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "openMark()",
     "data": "0x05b918fe",
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "index",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "index()",
     "data": "0x2986c0e5",
     "decimals": 9
    }
   ],
   "formula": "mark() ÷ 1e6 ÷ (sNET.index() ÷ 1e9)",
   "steps": [
    "eth_call mark(), openMark() and sNET.index()",
    "per wsNET: ÷ 1e6 (USDG)",
    "per NET: ÷ the index (NET per wsNET)"
   ],
   "api": {
    "path": "/api/v1/advance",
    "field": "example.twapPerNet"
   },
   "caveats": [
    "/api/v1/advance labels this twapPerNet and its openMark ÷ index openPricePerNet; both come from the desk's marks, so they can differ from PairOracle.twapNetUsdg() by the desk's own pricing."
   ]
  },
  {
   "id": "advance_book",
   "area": "NET Advance",
   "label": "NET Advance book: USDG owed",
   "unit": "USDG",
   "what": "Every open position: what it owes, the wsNET locked and its value at the mark, the due date, and its cushion (how far the mark can fall before the lock stops covering what is owed).",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "positions",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "positionCount()",
     "data": "0xe7702d05",
     "decimals": 0
    },
    {
     "kind": "call",
     "name": "mark",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "mark()",
     "data": "0x8c0d0c29",
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "term",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "TERM()",
     "data": "0x5ea25e28",
     "decimals": 0
    },
    {
     "kind": "call",
     "name": "position",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "position(uint256 id) → (owner, destination, uint64 openedAt, bool closed, uint256 wsLocked, uint256 principalNet, uint256 owed, uint256 paid)",
     "data": "0xf7a95a9e + id (32 bytes), id = 1..positionCount()",
     "decimals": "wsLocked 18, principalNet 9, owed 6, paid 6"
    },
    {
     "kind": "call",
     "name": "index",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "index()",
     "data": "0x2986c0e5",
     "decimals": 9
    }
   ],
   "formula": "per position: outstanding = owed − paid; lock = wsLocked × mark; break-even = outstanding ÷ wsLocked; cushion = 1 − break-even ÷ mark; shortfall = max(0, outstanding − lock); due = openedAt + TERM. Book: Σ outstanding, Σ lock, coverage = Σ lock ÷ Σ outstanding",
   "steps": [
    "positionCount() → ids 1..n",
    "eth_call position(id) for each; decode 8 words (owner, destination, openedAt, closed, wsLocked ÷1e18, principalNet ÷1e9, owed ÷1e6, paid ÷1e6)",
    "keep the positions not closed",
    "apply the formula at mark() ÷ 1e6 and the head block's time",
    "sum"
   ],
   "api": {
    "path": "/api/v1/advance",
    "field": "summary.outstanding"
   },
   "caveats": [
    "Closed positions are skipped; a position the RPC could not read is listed in parts.unread rather than guessed.",
    "The served book uses the server's clock for days left and the overdue split; this uses the block's timestamp."
   ]
  },
  {
   "id": "advance_shortfall",
   "area": "NET Advance",
   "label": "NET Advance shortfall at today's mark",
   "unit": "USDG",
   "what": "What positions under water owe beyond their lock's value at the mark: the loss the desk would absorb if they closed now.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "positions",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "positionCount()",
     "data": "0xe7702d05",
     "decimals": 0
    },
    {
     "kind": "call",
     "name": "mark",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "mark()",
     "data": "0x8c0d0c29",
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "term",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "TERM()",
     "data": "0x5ea25e28",
     "decimals": 0
    },
    {
     "kind": "call",
     "name": "position",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "position(uint256 id) → (owner, destination, uint64 openedAt, bool closed, uint256 wsLocked, uint256 principalNet, uint256 owed, uint256 paid)",
     "data": "0xf7a95a9e + id (32 bytes), id = 1..positionCount()",
     "decimals": "wsLocked 18, principalNet 9, owed 6, paid 6"
    }
   ],
   "formula": "Σ over open positions of max(0, (owed − paid) − wsLocked × mark)",
   "steps": [
    "read the book (advance_book)",
    "per position: outstanding − lock value, floored at 0",
    "sum"
   ],
   "api": {
    "path": "/api/v1/advance",
    "field": "summary.shortfall"
   }
  },
  {
   "id": "advance_break_even",
   "area": "NET Advance",
   "label": "NET Advance book break-even per NET",
   "unit": "USD per NET",
   "what": "The NET price at which the whole book's locks just cover what is owed; bookCushion is how far below today's mark that sits.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "positions",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "positionCount()",
     "data": "0xe7702d05",
     "decimals": 0
    },
    {
     "kind": "call",
     "name": "mark",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "mark()",
     "data": "0x8c0d0c29",
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "term",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "TERM()",
     "data": "0x5ea25e28",
     "decimals": 0
    },
    {
     "kind": "call",
     "name": "position",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "position(uint256 id) → (owner, destination, uint64 openedAt, bool closed, uint256 wsLocked, uint256 principalNet, uint256 owed, uint256 paid)",
     "data": "0xf7a95a9e + id (32 bytes), id = 1..positionCount()",
     "decimals": "wsLocked 18, principalNet 9, owed 6, paid 6"
    },
    {
     "kind": "call",
     "name": "index",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "index()",
     "data": "0x2986c0e5",
     "decimals": 9
    }
   ],
   "formula": "Σ outstanding ÷ Σ wsLocked (USD per wsNET) ÷ sNET.index(); cushion = 1 − that ÷ mark",
   "steps": [
    "read the book (advance_book)",
    "Σ (owed − paid) ÷ Σ wsLocked over the open positions",
    "÷ the index for per NET"
   ],
   "api": {
    "path": "/api/v1/advance",
    "field": "summary.bookBreakEven",
    "part": "perWsNet"
   },
   "caveats": [
    "/api/v1/advance serves bookBreakEven per wsNET; this recipe's value is per NET (parts.perWsNet is the served figure)."
   ]
  },
  {
   "id": "advance_maturities",
   "area": "NET Advance",
   "label": "NET Advance falling due",
   "unit": "USDG",
   "what": "USDG owed by due week over the next five weeks, plus what is already past due.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "positions",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "positionCount()",
     "data": "0xe7702d05",
     "decimals": 0
    },
    {
     "kind": "call",
     "name": "mark",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "mark()",
     "data": "0x8c0d0c29",
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "term",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "TERM()",
     "data": "0x5ea25e28",
     "decimals": 0
    },
    {
     "kind": "call",
     "name": "position",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "position(uint256 id) → (owner, destination, uint64 openedAt, bool closed, uint256 wsLocked, uint256 principalNet, uint256 owed, uint256 paid)",
     "data": "0xf7a95a9e + id (32 bytes), id = 1..positionCount()",
     "decimals": "wsLocked 18, principalNet 9, owed 6, paid 6"
    }
   ],
   "formula": "due = openedAt + TERM; overdue when due ≤ now; else in the first 7-day window from now with due < its end",
   "steps": [
    "read the book (advance_book)",
    "skip positions owing nothing",
    "bucket each by due date"
   ],
   "params": {
    "now": "the head block's timestamp"
   },
   "api": {
    "path": "/api/v1/advance",
    "field": "maturities",
    "part": "rows"
   },
   "caveats": [
    "Windows start at the head block's time; the served ones start at the server's clock."
   ]
  },
  {
   "id": "advance_capacity",
   "area": "NET Advance",
   "label": "NET Advance capacity, replayed",
   "unit": "USDG",
   "what": "USDG free for new locks, rebuilt from every USDG transfer into and out of the desk; it must reconcile with unallocated().",
   "needs": [
    "eth_call",
    "eth_getLogs"
   ],
   "sources": [
    {
     "kind": "event",
     "name": "USDG in",
     "contract": "USDG",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x000000000000000000000000de9df88aba59b644d4d7f6305e52ab982a3cfcac"
     ],
     "fromBlock": 70000000,
     "decimals": 6
    },
    {
     "kind": "event",
     "name": "USDG out",
     "contract": "USDG",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x000000000000000000000000de9df88aba59b644d4d7f6305e52ab982a3cfcac"
     ],
     "fromBlock": 70000000,
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "unallocated",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "unallocated()",
     "data": "0xdf1c455c",
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "treasuryBps",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "TREASURY_BPS()",
     "data": "0x4c25d197",
     "decimals": 0
    }
   ],
   "formula": "available = Σ refills (USDG in) − Σ advances × (1 + TREASURY_BPS ÷ 10,000); USDG out to the Treasury (the escrow paid at close) does not move it; drift = unallocated() − available",
   "steps": [
    "eth_getLogs USDG Transfer with topic2 = the desk (in) and topic1 = the desk (out), from FROM_BLOCK",
    "order by block and log index; value ÷ 1e6",
    "in → refill; out to the Treasury → escrow paid; any other out → an advance",
    "replay from zero",
    "compare with unallocated()"
   ],
   "api": {
    "path": "/api/v1/advance",
    "field": "capacity.availableNowUsdg"
   },
   "caveats": [
    "The served availableNowUsdg is unallocated() itself; the replay is the check (capacity.replayDriftUsdg).",
    "Any USDG into the desk counts as a refill and any USDG out (not to the Treasury) as an advance, as the served replay does: an early USDG repayment or an owner withdrawal would show up as drift.",
    "The served replay rounds each transfer to the cent; this one keeps full precision.",
    "Each transfer needs its block's time: taken from the log's blockTimestamp when the node returns it, else one eth_getBlockByNumber per block."
   ]
  },
  {
   "id": "advance_refills",
   "area": "NET Advance",
   "label": "NET Advance refills and how fast they go",
   "unit": "refills",
   "what": "Each refill of the desk: how much it opened up, how many locks and wallets took it, how long until three quarters and all of it were used, and the share of time the desk was open.",
   "needs": [
    "eth_call",
    "eth_getLogs"
   ],
   "sources": [
    {
     "kind": "event",
     "name": "USDG in",
     "contract": "USDG",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      null,
      "0x000000000000000000000000de9df88aba59b644d4d7f6305e52ab982a3cfcac"
     ],
     "fromBlock": 70000000,
     "decimals": 6
    },
    {
     "kind": "event",
     "name": "USDG out",
     "contract": "USDG",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "event": "Transfer(address indexed from, address indexed to, uint256 value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x000000000000000000000000de9df88aba59b644d4d7f6305e52ab982a3cfcac"
     ],
     "fromBlock": 70000000,
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "unallocated",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "unallocated()",
     "data": "0xdf1c455c",
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "treasuryBps",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "TREASURY_BPS()",
     "data": "0x4c25d197",
     "decimals": 0
    }
   ],
   "formula": "an episode opens when a refill lifts available to ≥ 1,000 USDG and ends when advances bring it under 50; quarterLeftAt = when available ≤ 25% of what opened; openShare = time with ≥ 1,000 available ÷ time since the first transfer",
   "steps": [
    "replay the desk's USDG transfers (advance_capacity)",
    "cut into episodes",
    "median and fastest time to use up, median refill, share of time open"
   ],
   "api": {
    "path": "/api/v1/advance",
    "field": "capacity.stats.refills"
   },
   "caveats": [
    "The served list keeps the last 30 episodes (lastRefills shows 10); this returns all of them. Its threeQuartersTakenAfterSec = quarterLeftAt − t, usedUpAfterSec = drainSec."
   ]
  },
  {
   "id": "advance_lock_check",
   "area": "NET Advance",
   "label": "NET Advance: one lock, checked",
   "unit": "USDG now",
   "what": "For an amount of NET, sNET or wsNET: the USDG paid now, what is owed, the NET back after the term if the rate and price hold, and the prices at which all or none of it comes back.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "advanceBps",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "ADVANCE_BPS()",
     "data": "0xe9bdd3e6",
     "decimals": 0
    },
    {
     "kind": "call",
     "name": "feeBps",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "FEE_BPS()",
     "data": "0xbf333f2c",
     "decimals": 0
    },
    {
     "kind": "call",
     "name": "treasuryBps",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "TREASURY_BPS()",
     "data": "0x4c25d197",
     "decimals": 0
    },
    {
     "kind": "call",
     "name": "term",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "TERM()",
     "data": "0x5ea25e28",
     "decimals": 0
    },
    {
     "kind": "call",
     "name": "mark",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "mark()",
     "data": "0x8c0d0c29",
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "openMark",
     "contract": "NET Advance",
     "address": "0xDe9df88ABA59b644D4d7f6305e52aB982A3cFCac",
     "fn": "openMark()",
     "data": "0x05b918fe",
     "decimals": 6
    },
    {
     "kind": "call",
     "name": "index",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "index()",
     "data": "0x2986c0e5",
     "decimals": 9
    },
    {
     "kind": "call",
     "name": "nextReward",
     "contract": "Distributor",
     "address": "0x79e71F8a8a2912E40687a8820b2dC0fdd2f686b3",
     "fn": "nextReward()",
     "data": "0x6da4fe26",
     "decimals": 9
    },
    {
     "kind": "call",
     "name": "totalStaked",
     "contract": "Staking",
     "address": "0xB078cc304A0B264C5F3680DC0488954ACcd02E87",
     "fn": "totalStaked()",
     "data": "0x817b1cd2",
     "decimals": 9
    },
    {
     "kind": "call",
     "name": "rateWad",
     "contract": "Distributor",
     "address": "0x79e71F8a8a2912E40687a8820b2dC0fdd2f686b3",
     "fn": "rateWad()",
     "data": "0xde8d2dab",
     "decimals": 18
    }
   ],
   "formula": "advancePlan (src/lib/advanceMath.js): NET-eq = amount (× index for wsNET); A = NET-eq × openMark/index × ADVANCE_BPS; D = A × (1 + (FEE + TREASURY) BPS); g = (1 + nextReward ÷ totalStaked)^(3 × term days) − 1; taken at close = min(NET-eq × (1+g), D ÷ mark/index)",
   "steps": [
    "read the terms, mark(), openMark(), sNET.index()",
    "rate per 8-hour epoch = nextReward() ÷ totalStaked() (else rateWad() ÷ 1e18)",
    "g over the term",
    "advancePlan at openPrice = openMark ÷ index and closePrice = mark ÷ index"
   ],
   "params": {
    "amount": 10,
    "unit": "NET (or sNET, wsNET)"
   },
   "api": {
    "path": "/api/v1/advance",
    "field": "example.usdgNow"
   },
   "caveats": [
    "A model of one lock: the desk settles in integers and at its marks at close; the rate changes every epoch and the price moves. The served example is always 10 NET.",
    "Continuous approximation of the desk's settlement (advanceMath.js)."
   ]
  },
  {
   "id": "loop_mark",
   "area": "Loop",
   "label": "Loop oracle price per wsNET",
   "unit": "USD per wsNET",
   "what": "What the Loopback market credits each wsNET of collateral at: ≈ 0.90 × NET's TWAP × the staking index, floored at NAV and capped at 5 × NAV.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "market",
     "contract": "Morpho Blue",
     "address": "0x9D53d5E3bd5E8d4Cbfa6DB1ca238AEA02E651010",
     "fn": "market(bytes32 id)",
     "data": "0x5c60e39aaa586d26a6fe62d9c0f0948fede6e2130500ac7a655587447e2d4a37e6330589",
     "decimals": "assets 6 (USDG); shares raw; fee 18"
    },
    {
     "kind": "call",
     "name": "idToMarketParams",
     "contract": "Morpho Blue",
     "address": "0x9D53d5E3bd5E8d4Cbfa6DB1ca238AEA02E651010",
     "fn": "idToMarketParams(bytes32 id) → loanToken, collateralToken, oracle, irm, lltv",
     "data": "0x2c3c9157aa586d26a6fe62d9c0f0948fede6e2130500ac7a655587447e2d4a37e6330589",
     "decimals": "lltv 18"
    },
    {
     "kind": "call",
     "name": "price",
     "contract": "Loopback oracle",
     "address": "0xCDE9599059f8Ae6D6B9F33A0aF7877827ec75F16",
     "fn": "price() (the oracle named by idToMarketParams)",
     "data": "0xa035b1fe",
     "decimals": 24
    },
    {
     "kind": "call",
     "name": "backingPerToken",
     "contract": "Treasury",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "fn": "backingPerToken() (NAV)",
     "data": "0x1521843e",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "twap",
     "contract": "PairOracle",
     "address": "0x929631b33F4070D6f54477fba3FD27566567dAca",
     "fn": "twapNetUsdg()",
     "data": "0x10aa790e",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "index",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "index()",
     "data": "0x2986c0e5",
     "decimals": 9
    },
    {
     "kind": "call",
     "name": "getReserves",
     "contract": "NET/USDG pair",
     "address": "0x59F95461E68e0c77605299791E1449f175165B54",
     "fn": "getReserves() → USDG (6), NET (9)",
     "data": "0x0902f1ac",
     "decimals": "6 / 9"
    }
   ],
   "formula": "oracle = price() ÷ 1e24; formula = clamp(0.90 × TWAP, NAV, 5 × NAV) × index; floorTwap = NAV ÷ 0.90; capTwap = 5 × NAV ÷ 0.90; marketPx = TWAP × index",
   "steps": [
    "idToMarketParams(id) names the oracle",
    "eth_call price(), backingPerToken(), twapNetUsdg(), index()",
    "recompute the formula and check it matches price() within 0.5%",
    "spot = pool USDG ÷ pool NET; paused when spot is more than 15% under the TWAP"
   ],
   "api": {
    "path": "/api/v1/loop",
    "field": "mark.oraclePerWsNet"
   },
   "caveats": [
    "The 0.90 haircut, the NAV floor and the 5× cap are read from the oracle's published design, not from the chain; parts.matches checks them against price()."
   ]
  },
  {
   "id": "loop_market",
   "area": "Loop",
   "label": "Loop market: USDG borrowed",
   "unit": "USDG",
   "what": "The Loopback market's totals: USDG supplied and borrowed, utilization, free liquidity, LLTV and the borrow rate.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "market",
     "contract": "Morpho Blue",
     "address": "0x9D53d5E3bd5E8d4Cbfa6DB1ca238AEA02E651010",
     "fn": "market(bytes32 id)",
     "data": "0x5c60e39aaa586d26a6fe62d9c0f0948fede6e2130500ac7a655587447e2d4a37e6330589",
     "decimals": "assets 6 (USDG); shares raw; fee 18"
    },
    {
     "kind": "call",
     "name": "idToMarketParams",
     "contract": "Morpho Blue",
     "address": "0x9D53d5E3bd5E8d4Cbfa6DB1ca238AEA02E651010",
     "fn": "idToMarketParams(bytes32 id) → loanToken, collateralToken, oracle, irm, lltv",
     "data": "0x2c3c9157aa586d26a6fe62d9c0f0948fede6e2130500ac7a655587447e2d4a37e6330589",
     "decimals": "lltv 18"
    },
    {
     "kind": "call",
     "name": "borrowRateView",
     "contract": "Morpho IRM",
     "address": "idToMarketParams().irm",
     "fn": "borrowRateView(MarketParams, Market)",
     "data": "0x8c00bf6b + the 5 params words + the 6 market words",
     "decimals": 18
    }
   ],
   "formula": "borrow = totalBorrowAssets ÷ 1e6; util = borrow ÷ supply; borrow APY = e^(rate per second × 365 days) − 1; supply APY = same at rate × util × (1 − fee)",
   "steps": [
    "eth_call market(id) and idToMarketParams(id)",
    "eth_call the IRM's borrowRateView with both tuples",
    "decode"
   ],
   "api": {
    "path": "/api/v1/credit",
    "field": "loopback.borrow"
   },
   "caveats": [
    "As stored at the market's last interaction (lastUpdate); interest since then is not added."
   ]
  },
  {
   "id": "loop_book",
   "area": "Loop",
   "label": "Loop book: USDG owed by every borrower",
   "unit": "USDG",
   "what": "Every Loopback borrower: collateral, debt, LTV, health, the TWAP at which it is liquidated, its status, and what it would repay (or add) to survive a 15% or 30% TWAP fall.",
   "needs": [
    "eth_call",
    "eth_getLogs"
   ],
   "sources": [
    {
     "kind": "event",
     "name": "borrowers",
     "contract": "Morpho Blue",
     "address": "0x9D53d5E3bd5E8d4Cbfa6DB1ca238AEA02E651010",
     "event": "SupplyCollateral(bytes32 indexed id, address indexed caller, address indexed onBehalf, uint256 assets) | Borrow(bytes32 indexed id, address caller, address indexed onBehalf, address indexed receiver, uint256 assets, uint256 shares)",
     "topic0": [
      "0xa3b9472a1399e17e123f3c2e6586c23e504184d504de59cdaa2b375e880c6184",
      "0x570954540bed6b1304a87dfe815a5eda4a648f7097a16240dcd85c9b5fd42a43"
     ],
     "topics": [
      [
       "0xa3b9472a1399e17e123f3c2e6586c23e504184d504de59cdaa2b375e880c6184",
       "0x570954540bed6b1304a87dfe815a5eda4a648f7097a16240dcd85c9b5fd42a43"
      ],
      "0xaa586d26a6fe62d9c0f0948fede6e2130500ac7a655587447e2d4a37e6330589"
     ],
     "fromBlock": 16676769
    },
    {
     "kind": "call",
     "name": "position",
     "contract": "Morpho Blue",
     "address": "0x9D53d5E3bd5E8d4Cbfa6DB1ca238AEA02E651010",
     "fn": "position(bytes32 id, address user) → supplyShares, borrowShares, collateral",
     "data": "0x93c52062 + id + account (32 bytes)",
     "decimals": "collateral 18 (wsNET); borrowShares raw"
    },
    {
     "kind": "call",
     "name": "market",
     "contract": "Morpho Blue",
     "address": "0x9D53d5E3bd5E8d4Cbfa6DB1ca238AEA02E651010",
     "fn": "market(bytes32 id)",
     "data": "0x5c60e39aaa586d26a6fe62d9c0f0948fede6e2130500ac7a655587447e2d4a37e6330589",
     "decimals": "assets 6 (USDG); shares raw; fee 18"
    },
    {
     "kind": "call",
     "name": "idToMarketParams",
     "contract": "Morpho Blue",
     "address": "0x9D53d5E3bd5E8d4Cbfa6DB1ca238AEA02E651010",
     "fn": "idToMarketParams(bytes32 id) → loanToken, collateralToken, oracle, irm, lltv",
     "data": "0x2c3c9157aa586d26a6fe62d9c0f0948fede6e2130500ac7a655587447e2d4a37e6330589",
     "decimals": "lltv 18"
    },
    {
     "kind": "call",
     "name": "price",
     "contract": "Loopback oracle",
     "address": "0xCDE9599059f8Ae6D6B9F33A0aF7877827ec75F16",
     "fn": "price() (the oracle named by idToMarketParams)",
     "data": "0xa035b1fe",
     "decimals": 24
    },
    {
     "kind": "call",
     "name": "backingPerToken",
     "contract": "Treasury",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "fn": "backingPerToken() (NAV)",
     "data": "0x1521843e",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "twap",
     "contract": "PairOracle",
     "address": "0x929631b33F4070D6f54477fba3FD27566567dAca",
     "fn": "twapNetUsdg()",
     "data": "0x10aa790e",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "index",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "index()",
     "data": "0x2986c0e5",
     "decimals": 9
    },
    {
     "kind": "call",
     "name": "getReserves",
     "contract": "NET/USDG pair",
     "address": "0x59F95461E68e0c77605299791E1449f175165B54",
     "fn": "getReserves() → USDG (6), NET (9)",
     "data": "0x0902f1ac",
     "decimals": "6 / 9"
    }
   ],
   "formula": "Σ debt over positions owing more than 0.01 USDG. Wind-down for a fall f: the debt that sits exactly at liquidation = collateral × LLTV × (oracle ÷ TWAP) × max(TWAP × (1 − f), floorTwap); repay = debt − that, or add wsNET = debt ÷ (LLTV × (oracle ÷ TWAP) × max(…)) − collateral",
   "steps": [
    "eth_getLogs Morpho Blue, topic0 ∈ {SupplyCollateral, Borrow}, topic1 = the market id, from the market's first block: every account named (SupplyCollateral topic3, Borrow topic2)",
    "eth_call position(id, account) for each; drop accounts with no collateral and no borrow shares",
    "debt = borrowShares × totalBorrowAssets ÷ totalBorrowShares (market()); collateral ÷ 1e18; credited value = collateral × price() ÷ 1e24",
    "health = credited value × LLTV ÷ debt; LTV = debt ÷ credited value; liquidation TWAP = debt ÷ (collateral × LLTV) ÷ index ÷ 0.90 ('floor' if that per-NET credit is ≤ NAV, 'now' if health < 1)",
    "status by the TWAP fall to liquidation: AT RISK ≤ 5% (or now), WIND DOWN ≤ 15%, WATCH ≤ 30%, SAFE beyond or at the floor; NO LOAN when debt ≤ 0.01",
    "sum debt; ladder the debt by the TWAP fall to liquidation (now, 0–5, 5–10, 10–15, 15–20, 20–30, 30–50, >50%, NAV floor)"
   ],
   "api": {
    "path": "/api/v1/loop",
    "field": "summary.totalDebtUsdg"
   },
   "caveats": [
    "Debt uses market() as last stored: interest accrued since its lastUpdate is not included (the served figure reads the same way). Morpho itself rounds debt up with virtual shares; the difference is below a cent per loan.",
    "/api/v1/loop serves a book refreshed by the server about every minute and rounds its fields.",
    "One position() call per account ever seen on the market (hundreds): run it against a node that tolerates the volume; accounts the RPC could not read are listed in parts.unread, not dropped silently."
   ]
  },
  {
   "id": "loop_status",
   "area": "Loop",
   "label": "Loop loans AT RISK",
   "unit": "loans",
   "what": "Loans by status band: AT RISK (liquidatable now or a ≤ 5% TWAP fall away), WIND DOWN (≤ 15%), WATCH (≤ 30%), SAFE, NO LOAN.",
   "needs": [
    "eth_call",
    "eth_getLogs"
   ],
   "sources": [
    {
     "kind": "event",
     "name": "borrowers",
     "contract": "Morpho Blue",
     "address": "0x9D53d5E3bd5E8d4Cbfa6DB1ca238AEA02E651010",
     "event": "SupplyCollateral(bytes32 indexed id, address indexed caller, address indexed onBehalf, uint256 assets) | Borrow(bytes32 indexed id, address caller, address indexed onBehalf, address indexed receiver, uint256 assets, uint256 shares)",
     "topic0": [
      "0xa3b9472a1399e17e123f3c2e6586c23e504184d504de59cdaa2b375e880c6184",
      "0x570954540bed6b1304a87dfe815a5eda4a648f7097a16240dcd85c9b5fd42a43"
     ],
     "topics": [
      [
       "0xa3b9472a1399e17e123f3c2e6586c23e504184d504de59cdaa2b375e880c6184",
       "0x570954540bed6b1304a87dfe815a5eda4a648f7097a16240dcd85c9b5fd42a43"
      ],
      "0xaa586d26a6fe62d9c0f0948fede6e2130500ac7a655587447e2d4a37e6330589"
     ],
     "fromBlock": 16676769
    },
    {
     "kind": "call",
     "name": "position",
     "contract": "Morpho Blue",
     "address": "0x9D53d5E3bd5E8d4Cbfa6DB1ca238AEA02E651010",
     "fn": "position(bytes32 id, address user) → supplyShares, borrowShares, collateral",
     "data": "0x93c52062 + id + account (32 bytes)",
     "decimals": "collateral 18 (wsNET); borrowShares raw"
    },
    {
     "kind": "call",
     "name": "market",
     "contract": "Morpho Blue",
     "address": "0x9D53d5E3bd5E8d4Cbfa6DB1ca238AEA02E651010",
     "fn": "market(bytes32 id)",
     "data": "0x5c60e39aaa586d26a6fe62d9c0f0948fede6e2130500ac7a655587447e2d4a37e6330589",
     "decimals": "assets 6 (USDG); shares raw; fee 18"
    },
    {
     "kind": "call",
     "name": "idToMarketParams",
     "contract": "Morpho Blue",
     "address": "0x9D53d5E3bd5E8d4Cbfa6DB1ca238AEA02E651010",
     "fn": "idToMarketParams(bytes32 id) → loanToken, collateralToken, oracle, irm, lltv",
     "data": "0x2c3c9157aa586d26a6fe62d9c0f0948fede6e2130500ac7a655587447e2d4a37e6330589",
     "decimals": "lltv 18"
    },
    {
     "kind": "call",
     "name": "price",
     "contract": "Loopback oracle",
     "address": "0xCDE9599059f8Ae6D6B9F33A0aF7877827ec75F16",
     "fn": "price() (the oracle named by idToMarketParams)",
     "data": "0xa035b1fe",
     "decimals": 24
    },
    {
     "kind": "call",
     "name": "backingPerToken",
     "contract": "Treasury",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "fn": "backingPerToken() (NAV)",
     "data": "0x1521843e",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "twap",
     "contract": "PairOracle",
     "address": "0x929631b33F4070D6f54477fba3FD27566567dAca",
     "fn": "twapNetUsdg()",
     "data": "0x10aa790e",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "index",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "index()",
     "data": "0x2986c0e5",
     "decimals": 9
    },
    {
     "kind": "call",
     "name": "getReserves",
     "contract": "NET/USDG pair",
     "address": "0x59F95461E68e0c77605299791E1449f175165B54",
     "fn": "getReserves() → USDG (6), NET (9)",
     "data": "0x0902f1ac",
     "decimals": "6 / 9"
    }
   ],
   "formula": "fall = 1 − liquidation TWAP ÷ TWAP; AT RISK if 'now' or fall ≤ 0.05; WIND DOWN ≤ 0.15; WATCH ≤ 0.30; SAFE beyond or 'floor'",
   "steps": [
    "eth_getLogs Morpho Blue, topic0 ∈ {SupplyCollateral, Borrow}, topic1 = the market id, from the market's first block: every account named (SupplyCollateral topic3, Borrow topic2)",
    "eth_call position(id, account) for each; drop accounts with no collateral and no borrow shares",
    "debt = borrowShares × totalBorrowAssets ÷ totalBorrowShares (market()); collateral ÷ 1e18; credited value = collateral × price() ÷ 1e24",
    "health = credited value × LLTV ÷ debt; LTV = debt ÷ credited value; liquidation TWAP = debt ÷ (collateral × LLTV) ÷ index ÷ 0.90 ('floor' if that per-NET credit is ≤ NAV, 'now' if health < 1)",
    "status by the TWAP fall to liquidation: AT RISK ≤ 5% (or now), WIND DOWN ≤ 15%, WATCH ≤ 30%, SAFE beyond or at the floor; NO LOAN when debt ≤ 0.01",
    "count loans and debt per band"
   ],
   "api": {
    "path": "/api/v1/loop",
    "field": "summary.byStatus['AT RISK'].loans"
   },
   "caveats": [
    "Debt uses market() as last stored: interest accrued since its lastUpdate is not included (the served figure reads the same way). Morpho itself rounds debt up with virtual shares; the difference is below a cent per loan.",
    "/api/v1/loop serves a book refreshed by the server about every minute and rounds its fields.",
    "One position() call per account ever seen on the market (hundreds): run it against a node that tolerates the volume; accounts the RPC could not read are listed in parts.unread, not dropped silently."
   ]
  },
  {
   "id": "loop_liquidatable",
   "area": "Loop",
   "label": "Loop loans liquidatable now",
   "unit": "loans",
   "what": "Loans Morpho can liquidate at today's oracle price, with what a full liquidation repays and seizes and what it earns at the oracle, at the TWAP and after selling the NET.",
   "needs": [
    "eth_call",
    "eth_getLogs"
   ],
   "sources": [
    {
     "kind": "event",
     "name": "borrowers",
     "contract": "Morpho Blue",
     "address": "0x9D53d5E3bd5E8d4Cbfa6DB1ca238AEA02E651010",
     "event": "SupplyCollateral(bytes32 indexed id, address indexed caller, address indexed onBehalf, uint256 assets) | Borrow(bytes32 indexed id, address caller, address indexed onBehalf, address indexed receiver, uint256 assets, uint256 shares)",
     "topic0": [
      "0xa3b9472a1399e17e123f3c2e6586c23e504184d504de59cdaa2b375e880c6184",
      "0x570954540bed6b1304a87dfe815a5eda4a648f7097a16240dcd85c9b5fd42a43"
     ],
     "topics": [
      [
       "0xa3b9472a1399e17e123f3c2e6586c23e504184d504de59cdaa2b375e880c6184",
       "0x570954540bed6b1304a87dfe815a5eda4a648f7097a16240dcd85c9b5fd42a43"
      ],
      "0xaa586d26a6fe62d9c0f0948fede6e2130500ac7a655587447e2d4a37e6330589"
     ],
     "fromBlock": 16676769
    },
    {
     "kind": "call",
     "name": "position",
     "contract": "Morpho Blue",
     "address": "0x9D53d5E3bd5E8d4Cbfa6DB1ca238AEA02E651010",
     "fn": "position(bytes32 id, address user) → supplyShares, borrowShares, collateral",
     "data": "0x93c52062 + id + account (32 bytes)",
     "decimals": "collateral 18 (wsNET); borrowShares raw"
    },
    {
     "kind": "call",
     "name": "market",
     "contract": "Morpho Blue",
     "address": "0x9D53d5E3bd5E8d4Cbfa6DB1ca238AEA02E651010",
     "fn": "market(bytes32 id)",
     "data": "0x5c60e39aaa586d26a6fe62d9c0f0948fede6e2130500ac7a655587447e2d4a37e6330589",
     "decimals": "assets 6 (USDG); shares raw; fee 18"
    },
    {
     "kind": "call",
     "name": "idToMarketParams",
     "contract": "Morpho Blue",
     "address": "0x9D53d5E3bd5E8d4Cbfa6DB1ca238AEA02E651010",
     "fn": "idToMarketParams(bytes32 id) → loanToken, collateralToken, oracle, irm, lltv",
     "data": "0x2c3c9157aa586d26a6fe62d9c0f0948fede6e2130500ac7a655587447e2d4a37e6330589",
     "decimals": "lltv 18"
    },
    {
     "kind": "call",
     "name": "price",
     "contract": "Loopback oracle",
     "address": "0xCDE9599059f8Ae6D6B9F33A0aF7877827ec75F16",
     "fn": "price() (the oracle named by idToMarketParams)",
     "data": "0xa035b1fe",
     "decimals": 24
    },
    {
     "kind": "call",
     "name": "backingPerToken",
     "contract": "Treasury",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "fn": "backingPerToken() (NAV)",
     "data": "0x1521843e",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "twap",
     "contract": "PairOracle",
     "address": "0x929631b33F4070D6f54477fba3FD27566567dAca",
     "fn": "twapNetUsdg()",
     "data": "0x10aa790e",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "index",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "index()",
     "data": "0x2986c0e5",
     "decimals": 9
    },
    {
     "kind": "call",
     "name": "getReserves",
     "contract": "NET/USDG pair",
     "address": "0x59F95461E68e0c77605299791E1449f175165B54",
     "fn": "getReserves() → USDG (6), NET (9)",
     "data": "0x0902f1ac",
     "decimals": "6 / 9"
    }
   ],
   "formula": "LIF = min(1.15, 1 ÷ (1 − 0.3 × (1 − LLTV))); seized = repay × LIF ÷ oracle (capped at the collateral: the rest is bad debt); NET = seized × index; sale = poolUSDG × x ÷ (poolNET + x), x = NET × 0.95 (levy) × 0.997 (fee); profit after sale = sale − repay",
   "steps": [
    "eth_getLogs Morpho Blue, topic0 ∈ {SupplyCollateral, Borrow}, topic1 = the market id, from the market's first block: every account named (SupplyCollateral topic3, Borrow topic2)",
    "eth_call position(id, account) for each; drop accounts with no collateral and no borrow shares",
    "debt = borrowShares × totalBorrowAssets ÷ totalBorrowShares (market()); collateral ÷ 1e18; credited value = collateral × price() ÷ 1e24",
    "health = credited value × LLTV ÷ debt; LTV = debt ÷ credited value; liquidation TWAP = debt ÷ (collateral × LLTV) ÷ index ÷ 0.90 ('floor' if that per-NET credit is ≤ NAV, 'now' if health < 1)",
    "status by the TWAP fall to liquidation: AT RISK ≤ 5% (or now), WIND DOWN ≤ 15%, WATCH ≤ 30%, SAFE beyond or at the floor; NO LOAN when debt ≤ 0.01",
    "keep loans with debt > 0.01 and health < 1 (or 'now')",
    "full-liquidation math at the oracle price; the sale through the NET/USDG pool's reserves (getReserves)"
   ],
   "api": {
    "path": "/api/v1/loop",
    "field": "summary.liquidatableNow"
   },
   "caveats": [
    "Debt uses market() as last stored: interest accrued since its lastUpdate is not included (the served figure reads the same way). Morpho itself rounds debt up with virtual shares; the difference is below a cent per loan.",
    "/api/v1/loop serves a book refreshed by the server about every minute and rounds its fields.",
    "One position() call per account ever seen on the market (hundreds): run it against a node that tolerates the volume; accounts the RPC could not read are listed in parts.unread, not dropped silently.",
    "Candidates and arithmetic only: no calldata. Liquidations are first come, first served; gas, other bidders and the pool moving between blocks are not modelled.",
    "The served liquidation block values seized wsNET at TWAP × index (profitAtMarketUsd); the after-sale figure is the Loop page's liquidator estimate (liqMath.js)."
   ]
  },
  {
   "id": "loop_position",
   "area": "Loop",
   "label": "One Loop loan",
   "unit": "health",
   "what": "One account's Loopback loan: health, LTV, the TWAP fall to liquidation, status and wind-down. Reads only that account (no event scan).",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "name": "position",
     "contract": "Morpho Blue",
     "address": "0x9D53d5E3bd5E8d4Cbfa6DB1ca238AEA02E651010",
     "fn": "position(bytes32 id, address user)",
     "data": "0x93c52062 + id + account",
     "decimals": "collateral 18; borrowShares raw"
    },
    {
     "kind": "call",
     "name": "market",
     "contract": "Morpho Blue",
     "address": "0x9D53d5E3bd5E8d4Cbfa6DB1ca238AEA02E651010",
     "fn": "market(bytes32 id)",
     "data": "0x5c60e39aaa586d26a6fe62d9c0f0948fede6e2130500ac7a655587447e2d4a37e6330589",
     "decimals": "assets 6 (USDG); shares raw; fee 18"
    },
    {
     "kind": "call",
     "name": "idToMarketParams",
     "contract": "Morpho Blue",
     "address": "0x9D53d5E3bd5E8d4Cbfa6DB1ca238AEA02E651010",
     "fn": "idToMarketParams(bytes32 id) → loanToken, collateralToken, oracle, irm, lltv",
     "data": "0x2c3c9157aa586d26a6fe62d9c0f0948fede6e2130500ac7a655587447e2d4a37e6330589",
     "decimals": "lltv 18"
    },
    {
     "kind": "call",
     "name": "price",
     "contract": "Loopback oracle",
     "address": "0xCDE9599059f8Ae6D6B9F33A0aF7877827ec75F16",
     "fn": "price() (the oracle named by idToMarketParams)",
     "data": "0xa035b1fe",
     "decimals": 24
    },
    {
     "kind": "call",
     "name": "backingPerToken",
     "contract": "Treasury",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "fn": "backingPerToken() (NAV)",
     "data": "0x1521843e",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "twap",
     "contract": "PairOracle",
     "address": "0x929631b33F4070D6f54477fba3FD27566567dAca",
     "fn": "twapNetUsdg()",
     "data": "0x10aa790e",
     "decimals": 18
    },
    {
     "kind": "call",
     "name": "index",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "index()",
     "data": "0x2986c0e5",
     "decimals": 9
    },
    {
     "kind": "call",
     "name": "getReserves",
     "contract": "NET/USDG pair",
     "address": "0x59F95461E68e0c77605299791E1449f175165B54",
     "fn": "getReserves() → USDG (6), NET (9)",
     "data": "0x0902f1ac",
     "decimals": "6 / 9"
    }
   ],
   "formula": "as loop_book, for one account",
   "steps": [
    "eth_call position(id, account), market(id), idToMarketParams(id) and the mark's inputs",
    "apply loop_book's per-position formula"
   ],
   "params": {
    "account": "0x… (required)"
   },
   "api": {
    "path": "/api/v1/loop?account={account}",
    "field": "loans[0].health"
   },
   "caveats": [
    "Debt uses market() as last stored: interest accrued since its lastUpdate is not included (the served figure reads the same way). Morpho itself rounds debt up with virtual shares; the difference is below a cent per loan.",
    "/api/v1/loop serves a book refreshed by the server about every minute and rounds its fields.",
    "One position() call per account ever seen on the market (hundreds): run it against a node that tolerates the volume; accounts the RPC could not read are listed in parts.unread, not dropped silently."
   ]
  },
  {
   "id": "holder_position",
   "area": "Holders",
   "label": "NET held by an address, staked and unstaked",
   "unit": "NET-equivalent",
   "what": "One address's NET-equivalent: liquid NET, sNET, wsNET at the staking index, and wsNET it has posted as Loopback collateral; the staked share and the USD value at the TWAP.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "fn": "balanceOf(address)",
     "data": "0x70a08231<address>",
     "decimals": 9
    },
    {
     "kind": "call",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "balanceOf(address)",
     "data": "0x70a08231<address>",
     "decimals": 9
    },
    {
     "kind": "call",
     "contract": "wsNET",
     "address": "0x63C12667638f2Ae6fC6ae09B43D98Ec84a8586eA",
     "fn": "balanceOf(address)",
     "data": "0x70a08231<address>",
     "decimals": 18
    },
    {
     "kind": "call",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "index()",
     "data": "0x2986c0e5",
     "decimals": 9
    },
    {
     "kind": "call",
     "contract": "Morpho Blue",
     "address": "0x9d53d5e3bd5e8d4cbfa6db1ca238aea02e651010",
     "fn": "position(LOOP_MARKET, address) → word 2 = wsNET collateral",
     "data": "0x93c52062<market id><address>",
     "decimals": 18
    },
    {
     "kind": "call",
     "contract": "PairOracle",
     "address": "0x929631b33F4070D6f54477fba3FD27566567dAca",
     "fn": "twapNetUsdg()",
     "data": "0x10aa790e",
     "decimals": 18
    }
   ],
   "formula": "total = NET + sNET + (wsNET + wsNET posted) × sNET.index(); staked = total − NET; usd = total × twapNetUsdg()",
   "steps": [
    "eth_call the three balanceOf reads, sNET.index() and Morpho's position(LOOP_MARKET, address)",
    "NET and sNET ÷ 1e9, wsNET and collateral ÷ 1e18, the index ÷ 1e9",
    "apply the formula"
   ],
   "params": {
    "address": "the address (default: the RWA sleeve's Safe)",
    "addresses": "several addresses (comma list): one row each"
   },
   "api": {
    "path": "/api/v1/whale/{address}",
    "field": "balances.total (and balances.net, snet, wsnetEq, postedEq)"
   },
   "caveats": [
    "The site reads posted collateral from its credit book (getCredit), which is built from the same Morpho position() reads; the board's figures are an hourly snapshot, /api/v1/whale reads balances live.",
    "wsNET has 18 decimals (sNET and NET 9); wsNET → NET uses sNET.index(), the site's rule. The Telegram bot's card uses the wrapper's backing rate (sNET held by wsNET ÷ wsNET supply), which is the same number up to rounding."
   ]
  },
  {
   "id": "holders_net",
   "area": "Holders",
   "label": "NET balances rebuilt from Transfer events",
   "unit": "addresses",
   "what": "Every address's NET balance replayed from every NET Transfer since the token's deploy block, checked against totalSupply(), with the biggest holders labelled.",
   "needs": [
    "eth_getLogs",
    "eth_call",
    "offchain:labels"
   ],
   "sources": [
    {
     "kind": "event",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(from, to, value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "fromBlock": 11443336
    },
    {
     "kind": "call",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "fn": "totalSupply()",
     "data": "0x18160ddd",
     "decimals": 9
    }
   ],
   "formula": "balance(a) = Σ value to a − Σ value from a (mint from 0x0, burn to 0x0); Σ balances = totalSupply()",
   "steps": [
    "eth_getLogs NET Transfer from block 11,443,336 (chunked; the RPC halves a span that returns too much)",
    "replay in exact integers",
    "compare the sum with NET.totalSupply()",
    "sort, label (LABELS) and keep the top N"
   ],
   "params": {
    "top": "rows returned (default 50)",
    "minNet": "count holders at or above this many NET (default 0.000000001)",
    "fromBlock": "start block (default the deploy block; a later start gives balance changes, not balances)"
   },
   "api": {
    "path": "/api/v1/net",
    "field": "supply (Σ of the replayed balances); compare holders' rows with /api/v1/holders whales[].net"
   },
   "caveats": [
    "A full rebuild reads every NET Transfer ever (every trade, stake, bond and fee route): several hundred thousand logs, about 8 RPC spans of 10M blocks that the engine splits further when a span returns too many. Expect minutes on the public RPC.",
    "Liquid NET only: NET held by Staking backs sNET / wsNET; see holder_position for a holder's full NET-equivalent.",
    "Labels (pools, routers, desks, the protocol's Safes, custodians) are the site's own list (LABELS in this file), not chain data: an unlabelled venue reads as 'a contract' and changes the kind a move gets."
   ]
  },
  {
   "id": "stakers",
   "area": "Holders",
   "label": "Stakers and the NET they have staked",
   "unit": "addresses",
   "what": "Every address holding sNET or wsNET (found from their Transfer events), its staked NET-equivalent, leaving out the contracts that hold for others; the count and total the Holders page shows.",
   "needs": [
    "eth_getLogs",
    "eth_call",
    "offchain:labels"
   ],
   "sources": [
    {
     "kind": "event",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "event": "Transfer(from, to, value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "fromBlock": 11443336
    },
    {
     "kind": "event",
     "contract": "wsNET",
     "address": "0x63C12667638f2Ae6fC6ae09B43D98Ec84a8586eA",
     "event": "Transfer(from, to, value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "fromBlock": 11443336
    },
    {
     "kind": "call",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "balanceOf(address), index()",
     "data": "0x70a08231, 0x2986c0e5",
     "decimals": 9
    },
    {
     "kind": "rpc",
     "method": "eth_getCode",
     "note": "the biggest holders, wallet or contract"
    }
   ],
   "formula": "staked(a) = sNET.balanceOf(a) + wsNET(a) × index (wsNET replayed from its Transfers); count addresses with staked ÷ index > 1e-6, not a custodian, not a contract (unless a protocol Safe)",
   "steps": [
    "eth_getLogs sNET and wsNET Transfer from the deploy block",
    "replay wsNET balances; eth_call sNET.balanceOf for every sNET receiver",
    "drop custodians (Staking, the wrapper, Morpho, pools, the Advance desk…)",
    "eth_getCode for the top holders (codeCheck) and drop contracts",
    "count and sum"
   ],
   "params": {
    "codeCheck": "\"top\" (default: the 400 biggest, as the site checks them) , \"all\" or \"none\"",
    "top": "rows returned (default 50)"
   },
   "api": {
    "path": "/api/v1/holders",
    "field": "holders.count and holders.totalNet"
   },
   "caveats": [
    "The site keeps a ledger in wsNET units replayed from the same Transfers, converting sNET with the index from its own 30-minute history (off-chain), and zeroes a holding when an out-transfer leaves under 1% of it. Here sNET is read live with balanceOf, so dust and rounding differ slightly.",
    "The site checks code only for the biggest ~400 ledger holders; a smaller contract stays counted there (codeCheck: \"top\" reproduces that).",
    "One sNET balanceOf per sNET holder: thousands of eth_calls on a full run.",
    "Labels (pools, routers, desks, the protocol's Safes, custodians) are the site's own list (LABELS in this file), not chain data: an unlabelled venue reads as 'a contract' and changes the kind a move gets."
   ]
  },
  {
   "id": "top_holders",
   "area": "Holders",
   "label": "Top 50 holders (the whale board)",
   "unit": "NET-equivalent",
   "what": "The 50 biggest holders by NET-equivalent (NET + sNET + wsNET at the index + wsNET posted on Loopback), holders' own wallets and Safes only, built the way the site builds its board; and the contracts and protocol Safes it sets aside.",
   "needs": [
    "eth_getLogs",
    "eth_call",
    "offchain:labels"
   ],
   "sources": [
    {
     "kind": "event",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "event": "Transfer(from, to, value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "fromBlock": 11443336
    },
    {
     "kind": "event",
     "contract": "wsNET",
     "address": "0x63C12667638f2Ae6fC6ae09B43D98Ec84a8586eA",
     "event": "Transfer(from, to, value)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "fromBlock": 11443336
    },
    {
     "kind": "event",
     "contract": "Morpho Blue",
     "address": "0x9d53d5e3bd5e8d4cbfa6db1ca238aea02e651010",
     "event": "SupplyCollateral(id = LOOP_MARKET, caller, onBehalf, assets)",
     "topic0": "0xa3b9472a1399e17e123f3c2e6586c23e504184d504de59cdaa2b375e880c6184",
     "fromBlock": 11443336
    },
    {
     "kind": "call",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "fn": "balanceOf(address)",
     "data": "0x70a08231<address>",
     "decimals": 9
    },
    {
     "kind": "call",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "balanceOf(address)",
     "data": "0x70a08231<address>",
     "decimals": 9
    },
    {
     "kind": "call",
     "contract": "wsNET",
     "address": "0x63C12667638f2Ae6fC6ae09B43D98Ec84a8586eA",
     "fn": "balanceOf(address)",
     "data": "0x70a08231<address>",
     "decimals": 18
    },
    {
     "kind": "call",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "index()",
     "data": "0x2986c0e5",
     "decimals": 9
    },
    {
     "kind": "call",
     "contract": "Morpho Blue",
     "address": "0x9d53d5e3bd5e8d4cbfa6db1ca238aea02e651010",
     "fn": "position(LOOP_MARKET, address) → word 2 = wsNET collateral",
     "data": "0x93c52062<market id><address>",
     "decimals": 18
    },
    {
     "kind": "call",
     "contract": "PairOracle",
     "address": "0x929631b33F4070D6f54477fba3FD27566567dAca",
     "fn": "twapNetUsdg()",
     "data": "0x10aa790e",
     "decimals": 18
    },
    {
     "kind": "rpc",
     "method": "eth_getCode",
     "note": "wallet or contract (an EIP-7702 delegation 0xef0100… is a wallet)"
    },
    {
     "kind": "call",
     "contract": "candidate contract",
     "address": "<address>",
     "fn": "getOwners()",
     "data": "0xa0e67e2b",
     "decimals": null
    }
   ],
   "formula": "candidates = the 160 biggest staker wallets + 24 biggest staker contracts / protocol Safes + the 40 biggest Loopback borrowers; total = NET + sNET + (wsNET + posted) × index; rank wallets and Safes (getOwners answers) by total; contracts and the protocol's Safes go to held",
   "steps": [
    "rebuild the stakers (stakers) and check the top 400 for code",
    "Loopback borrowers: SupplyCollateral logs on the wsNET market, then position() each",
    "read every candidate's balances, code and (contracts) getOwners()",
    "rank; value = Σ of the top 50 totals"
   ],
   "params": {
    "includeLiquid": "true also adds the 100 biggest liquid-NET wallets from a NET Transfer replay (the site's board does not: a holder who never staked is missing there)"
   },
   "api": {
    "path": "/api/v1/holders",
    "field": "whales[] (rank, address, total, net, snet, wsnetEq, postedEq, kind) and held[]"
   },
   "caveats": [
    "The site's candidates come from its staking ledger and its Loopback book only, so a wallet holding only liquid NET never reaches its board; includeLiquid shows who that leaves out.",
    "The site rebuilds the board about hourly; stance, flows and history are separate (whale_moves, whale_history). 'since' (the ledger's holding clock) is not rebuilt here.",
    "Labels (pools, routers, desks, the protocol's Safes, custodians) are the site's own list (LABELS in this file), not chain data: an unlabelled venue reads as 'a contract' and changes the kind a move gets."
   ]
  },
  {
   "id": "whale_moves",
   "area": "Holders",
   "label": "Whales' recent moves by kind",
   "unit": "moves",
   "what": "Every move of 10 NET-equivalent or more by the top holders over a window, judged per transaction by what entered and left the wallet: buy, sell, bond, stake, unstake, LP add or remove, deposit, withdraw, transfer in or out; with totals by kind and the in-less-out flow.",
   "needs": [
    "eth_getLogs",
    "eth_call",
    "offchain:labels"
   ],
   "sources": [
    {
     "kind": "event",
     "contract": "any token",
     "address": "(all)",
     "event": "Transfer(from = whale) and Transfer(to = whale): NET, USDG, sNET, wsNET and any other token or NFT",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "fromBlock": "the window's first block"
    },
    {
     "kind": "event",
     "contract": "Staking",
     "address": "0xB078cc304A0B264C5F3680DC0488954ACcd02E87",
     "event": "Staked(from, to, amount), Unstaked(owner, to, amount)",
     "topic0": "0x5dac0c1b1112564a045ba943c9d50270893e8e826c49be8e7073adc713ab7bd7, 0xd8654fcc8cf5b36d30b3f5e4688fc78118e6d68de60b9994e09902268b57c3e3",
     "fromBlock": "the window's first block"
    },
    {
     "kind": "rpc",
     "method": "eth_getTransactionByHash",
     "note": "the transaction's target, sender and ETH value (a swap paid in native ETH)"
    },
    {
     "kind": "rpc",
     "method": "eth_getCode",
     "note": "each counterparty, wallet or contract"
    },
    {
     "kind": "call",
     "contract": "other token",
     "address": "<token>",
     "fn": "name()",
     "data": "0x06fdde03",
     "decimals": null
    },
    {
     "kind": "call",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "fn": "balanceOf(address)",
     "data": "0x70a08231<address>",
     "decimals": 9
    },
    {
     "kind": "call",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "balanceOf(address)",
     "data": "0x70a08231<address>",
     "decimals": 9
    },
    {
     "kind": "call",
     "contract": "wsNET",
     "address": "0x63C12667638f2Ae6fC6ae09B43D98Ec84a8586eA",
     "fn": "balanceOf(address)",
     "data": "0x70a08231<address>",
     "decimals": 18
    },
    {
     "kind": "call",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "index()",
     "data": "0x2986c0e5",
     "decimals": 9
    },
    {
     "kind": "call",
     "contract": "Morpho Blue",
     "address": "0x9d53d5e3bd5e8d4cbfa6db1ca238aea02e651010",
     "fn": "position(LOOP_MARKET, address) → word 2 = wsNET collateral",
     "data": "0x93c52062<market id><address>",
     "decimals": 18
    },
    {
     "kind": "call",
     "contract": "PairOracle",
     "address": "0x929631b33F4070D6f54477fba3FD27566567dAca",
     "fn": "twapNetUsdg()",
     "data": "0x10aa790e",
     "decimals": 18
    }
   ],
   "formula": "per (transaction, whale): NET in − out (staking and wrapping excluded; NET from a bond desk = bond), USDG in − out, sNET / wsNET legs, other tokens; then: NET out with USDG in = sell, NET in with USDG out = buy, NET out with an LP token minted = lp-add, … (holderFlows.ts whaleMoves); usd = the USDG leg for a buy or sell, else NET-eq × TWAP; flow = Σ (buy, bond, transfer-in) − Σ (sell, transfer-out)",
   "steps": [
    "the whales: addresses given, else the top 50 (top_holders)",
    "find the window's first block; eth_getLogs Transfer with the whales in topic 1, then topic 2, and the Staking events",
    "eth_getCode the counterparties, name() other tokens, eth_getTransactionByHash the NET transactions",
    "classify (classifyMoves, the site's rules) and keep moves ≥ 10 NET-eq"
   ],
   "params": {
    "addresses": "comma list of wallets (default: the top 50, which costs a board build)",
    "days": "window (default 7)",
    "kind": "only these kinds (comma list)",
    "minUsd": "only moves worth at least this"
   },
   "api": {
    "path": "/api/v1/holders?days=7",
    "field": "moves[], movesByKind, flowTotals.d7"
   },
   "caveats": [
    "The site prices a live move at the board's TWAP when it is recorded and a back-filled one at the TWAP of its time (its 30-minute history, off-chain); here every move is priced at today's TWAP unless it carried a USDG leg.",
    "The site leaves out moves between wallets it links as one owner (two-way transfer clusters) and the protocol's Safes, and counts wallets that were on the board when they moved; here the given wallets are judged as they are now.",
    "The sNET legs use today's index; sNET amounts are NET-equivalent at the moment of transfer either way.",
    "Labels (pools, routers, desks, the protocol's Safes, custodians) are the site's own list (LABELS in this file), not chain data: an unlabelled venue reads as 'a contract' and changes the kind a move gets."
   ]
  },
  {
   "id": "whale_history",
   "area": "Holders",
   "label": "A whale's history: entry, P&L, rebase earned",
   "unit": "USD per NET (estimated entry)",
   "what": "One holder's position day by day since it first held NET (liquid NET, staked units, wsNET posted on Loopback), the rebase it has earned, and an entry estimate: each day's net NET-equivalent added priced at that day's price, against today's value.",
   "needs": [
    "eth_getLogs",
    "eth_call"
   ],
   "sources": [
    {
     "kind": "event",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "event": "Transfer(from = address), Transfer(to = address)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "fromBlock": 11443336
    },
    {
     "kind": "event",
     "contract": "sNET / wsNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7, 0x63C12667638f2Ae6fC6ae09B43D98Ec84a8586eA",
     "event": "Transfer(from = address), Transfer(to = address)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "fromBlock": 11443336
    },
    {
     "kind": "event",
     "contract": "Morpho Blue",
     "address": "0x9d53d5e3bd5e8d4cbfa6db1ca238aea02e651010",
     "event": "SupplyCollateral / WithdrawCollateral / Liquidate on LOOP_MARKET for the address",
     "topic0": "0xa3b9472a1399e17e123f3c2e6586c23e504184d504de59cdaa2b375e880c6184, 0xe80ebd7cc9223d7382aab2e0d1d6155c65651f83d53c8b9b06901d167e321142, 0xa4946ede45d0c6f06a0f5ce92c9ad3b4751452d2fe0e25010783bcab57a67e41",
     "fromBlock": 11443336
    },
    {
     "kind": "event",
     "contract": "wsNET wraps",
     "address": "0x63C12667638f2Ae6fC6ae09B43D98Ec84a8586eA, 0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "event": "wsNET minted / burned and sNET into / out of the wrapper in the same transaction (index = sNET ÷ wsNET)",
     "topic0": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
     "fromBlock": 11443336
    },
    {
     "kind": "event",
     "contract": "NET/USDG v2 pair",
     "address": "0x59F95461E68e0c77605299791E1449f175165B54",
     "event": "Sync(reserve0 USDG, reserve1 NET): the price at each day's close",
     "topic0": "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1",
     "fromBlock": 11443336
    },
    {
     "kind": "call",
     "contract": "sNET",
     "address": "0xb773ec2C326B7f98a5a83fc098825492F020a4c7",
     "fn": "index()",
     "data": "0x2986c0e5",
     "decimals": 9
    },
    {
     "kind": "call",
     "contract": "PairOracle",
     "address": "0x929631b33F4070D6f54477fba3FD27566567dAca",
     "fn": "twapNetUsdg() (today; every day's close in archive mode)",
     "data": "0x10aa790e",
     "decimals": 18
    }
   ],
   "formula": "per day: ΔNET, Δunits (sNET ÷ index at the time, wsNET as is), Δposted; position = running sums; added on a day = ΔNET + (Δunits + Δposted) × index > 0, priced at the day's close; avgEntry = Σ added × price ÷ Σ added; pnl = total now × TWAP + Σ removed × price − Σ added × price; rebase = Σ units held × the index's growth",
   "steps": [
    "eth_getLogs the address's NET, sNET and wsNET transfers and its Loopback collateral events since the deploy block",
    "the index over time: wsNET wraps and unwraps (logs mode) or sNET.index() at each change day's last block (archive mode)",
    "the price at each change day's close: the v2 pair's last Sync (logs mode) or PairOracle.twapNetUsdg() at that block (archive mode)",
    "whaleStats(): the site's own arithmetic"
   ],
   "params": {
    "address": "the holder (default: the RWA sleeve's Safe)",
    "mode": "\"logs\" (default, works on the public RPC) or \"archive\" (needs an archive node: the exact getters the site's history grid reads)",
    "fromBlock": "start block (default the deploy block)"
   },
   "api": {
    "path": "/api/v1/whale/{address}",
    "field": "history.avgEntry (and history.pnl, history.rebase, history.added, history.addedUsd, history.removedUsd)"
   },
   "caveats": [
    "The site's day series is its own 30-minute history of sNET.index() and the TWAP (off-chain, replayed from an archive node): each day uses the last read of the day. Archive mode reads the same getters at each change day's last block; logs mode substitutes the v2 pool's spot price at the close (not a TWAP) and the index from the day's last wrap or unwrap, so entry and P&L are close, not exact.",
    "The site tracks a wallet from launch only if it was on the board when tracking began or has been back-filled since; history is shown only for board wallets.",
    "The site values today at its credit book's TWAP (the Loopback mark); here PairOracle.twapNetUsdg()."
   ]
  },
  {
   "id": "predict_markets",
   "area": "Predict",
   "label": "Predict series, all of them",
   "unit": "series",
   "what": "Every weekly series the desk has opened: its line, clock, phase, book and, once graded, its print and winner.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "seriesCount()",
     "data": "0xd7f2c0ef",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "series(uint256 id)",
     "data": "0xdc22cb6a<id as 32-byte word>",
     "decimals": "see decodeSeries"
    }
   ],
   "formula": "for id in 1..seriesCount(): decode series(id); phase from status then the clock; winner from the stored payout",
   "steps": [
    "eth_call PredictDesk.seriesCount()",
    "for each id from 1 to the count, eth_call series(id) and split the reply into 26 32-byte words",
    "line, open and print words ÷ 1e12 = dollars; USDG words ÷ 1e6; outcome-token words ÷ 1e18",
    "phase: status 3 VOIDED, 2 SETTLED, else the clock (open → last call → close → print; voidable 72 h after the print)",
    "winner: HIGHER tokens redeem for longPayoutUsdg ÷ 1e6, LOWER for 1 − that"
   ],
   "params": {},
   "api": {
    "path": "/api/v1/predict",
    "field": "current.seriesId"
   },
   "caveats": [
    "The API's history skips a series whose read failed; this recipe lists every id the desk returns with a line."
   ]
  },
  {
   "id": "predict_line",
   "area": "Predict",
   "label": "Predict: the open series' line",
   "unit": "USD",
   "what": "The number the current series asks about: HIGHER wins if the print is strictly above it.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "seriesCount()",
     "data": "0xd7f2c0ef",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "series(uint256 id)",
     "data": "0xdc22cb6a<id as 32-byte word>",
     "decimals": "see decodeSeries"
    }
   ],
   "formula": "series(seriesCount()).lineWad ÷ 1e12",
   "steps": [
    "eth_call seriesCount()",
    "eth_call series(count)",
    "word 7 ÷ 1e12 = the line in dollars (word 6, the same way, is the number when it opened)"
   ],
   "params": {
    "seriesId": "optional: another series"
   },
   "api": {
    "path": "/api/v1/predict",
    "field": "current.line"
   },
   "caveats": [
    "A print equal to the line pays LOWER."
   ]
  },
  {
   "id": "predict_price_higher",
   "area": "Predict",
   "label": "Predict: HIGHER's price",
   "unit": "USDG per token",
   "what": "Where the desk's dealer curve prices a HIGHER token now (LOWER = 1 − it), and each side's fee and break-even.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "seriesCount()",
     "data": "0xd7f2c0ef",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "series(uint256 id)",
     "data": "0xdc22cb6a<id as 32-byte word>",
     "decimals": "see decodeSeries"
    }
   ],
   "formula": "q = HIGHER out − LOWER out; a = 0.6 × backing; p = (1 + q / √(a² + q²)) / 2; fee: 3%→6% adding skew, 3%→1.5% reducing it, linear in |q| ÷ backing up to the 35% cap; break-even = p × (1 + fee)",
   "steps": [
    "eth_call series(count)",
    "q = word 10 ÷ 1e18 − word 11 ÷ 1e18 (tokens outstanding, each pays 1 USDG if right)",
    "backing = word 14 ÷ 1e6; a = 0.6 × backing",
    "apply the curve and the fee rule"
   ],
   "params": {
    "seriesId": "optional"
   },
   "api": {
    "path": "/api/v1/predict",
    "field": "current.priceHigher"
   },
   "caveats": [
    "The curve price, before fees. A real fill is the desk's quoteBuy(bool, uint256) (0xc7d4bc7f) / quoteSell (0x6d6c8295), which take the fee and the size."
   ]
  },
  {
   "id": "predict_book",
   "area": "Predict",
   "label": "Predict: the open series' book",
   "unit": "USDG",
   "what": "USDG the desk holds for the series, the House's backing behind it, and what each side is owed if it wins.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "seriesCount()",
     "data": "0xd7f2c0ef",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "series(uint256 id)",
     "data": "0xdc22cb6a<id as 32-byte word>",
     "decimals": "see decodeSeries"
    }
   ],
   "formula": "series(count): bookUsdg (word 12), virtualLiquidity (13), backingUsdg (14) ÷ 1e6; HIGHER / LOWER outstanding (10, 11) ÷ 1e18 = USDG owed to that side if it wins",
   "steps": [
    "eth_call series(count)",
    "decode the words above"
   ],
   "params": {
    "seriesId": "optional"
   },
   "api": {
    "path": "/api/v1/predict",
    "field": "current.bookUsdg"
   },
   "caveats": [
    "backing is fixed at the open: the House Vault's funding plus a virtual buffer (virtualLiquidity); it sets the curve's depth, not cash."
   ]
  },
  {
   "id": "predict_volume",
   "area": "Predict",
   "label": "Predict: volume and fees, from every trade",
   "unit": "USDG",
   "what": "Every Bought and Sold the desk emitted for a series, added up per side, set against the desk's own counters at the same block.",
   "needs": [
    "eth_getLogs",
    "eth_call"
   ],
   "sources": [
    {
     "kind": "event",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "event": "Bought(uint256 indexed series, address indexed account, bool long, uint256 usdgIn, uint256 fee, uint256 tokensOut, uint256 markAfterWad)",
     "topic0": "0xda3658575501f28198f60bb28b30f0db3cd49f22a0cd16ce8925f17c1e67a6e6",
     "fromBlock": 66000000
    },
    {
     "kind": "event",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "event": "Sold(uint256 indexed series, address indexed account, bool long, uint256 tokensIn, uint256 fee, uint256 usdgOut, uint256 markAfterWad)",
     "topic0": "0x114ebb48af5632562b9fea181acdd42b4f0c5a42f1d1939b9c4d49d936ce5af3",
     "fromBlock": 66000000
    },
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "seriesCount()",
     "data": "0xd7f2c0ef",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "series(uint256 id)",
     "data": "0xdc22cb6a<id as 32-byte word>",
     "decimals": "see decodeSeries"
    }
   ],
   "formula": "volume = Σ Bought.usdgIn + Σ (Sold.usdgOut + Sold.fee); fees = Σ fee; must equal series(id) words 15 and 16 exactly",
   "steps": [
    "eth_getLogs on the desk, topic0 ∈ {Bought, Sold}, topic1 = the series id, from block 66,000,000 to the head",
    "data words: 0 long (1 = HIGHER), 1 usdgIn | tokensIn, 2 fee, 3 tokensOut | usdgOut (USDG 6 dec, tokens 18 dec)",
    "add them up, per side too",
    "eth_call series(id) at the same block and compare its volume and fee counters, to the micro-USDG"
   ],
   "params": {
    "seriesId": "optional: default the current series"
   },
   "api": {
    "path": "/api/v1/predict",
    "field": "current.volumeUsdg"
   },
   "caveats": [
    "USDG in per side is what buyers paid for that side (fee included); it is not what the side wins. A side wins its outstanding tokens × 1 USDG."
   ]
  },
  {
   "id": "predict_house_capital",
   "area": "Predict",
   "label": "House Vault: capital behind Predict",
   "unit": "USDG",
   "what": "What the House has at work: the open series' book while one trades, else the vault's active assets.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "contract": "HouseVault",
     "address": "0xb488368902b1CbD7533F1536C3F860065398D3e9",
     "fn": "sharePriceWad()",
     "data": "0x2770c503",
     "decimals": "÷1e6"
    },
    {
     "kind": "call",
     "contract": "HouseVault",
     "address": "0xb488368902b1CbD7533F1536C3F860065398D3e9",
     "fn": "totalShares()",
     "data": "0x3a98ef39",
     "decimals": 18
    },
    {
     "kind": "call",
     "contract": "HouseVault",
     "address": "0xb488368902b1CbD7533F1536C3F860065398D3e9",
     "fn": "activeAssets()",
     "data": "0x1c17b946",
     "decimals": 6
    },
    {
     "kind": "call",
     "contract": "HouseVault",
     "address": "0xb488368902b1CbD7533F1536C3F860065398D3e9",
     "fn": "totalPending()",
     "data": "0x3f90916a",
     "decimals": 6
    },
    {
     "kind": "call",
     "contract": "HouseVault",
     "address": "0xb488368902b1CbD7533F1536C3F860065398D3e9",
     "fn": "totalClaimable()",
     "data": "0x4838ed19",
     "decimals": 6
    },
    {
     "kind": "call",
     "contract": "HouseVault",
     "address": "0xb488368902b1CbD7533F1536C3F860065398D3e9",
     "fn": "live()",
     "data": "0x957aa58c",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "HouseVault",
     "address": "0xb488368902b1CbD7533F1536C3F860065398D3e9",
     "fn": "seriesCount()",
     "data": "0xd7f2c0ef",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "USDG",
     "address": "0x5fc5360d0400a0fd4f2af552add042d716f1d168",
     "fn": "balanceOf(HouseVault)",
     "data": "0x70a08231000000000000000000000000b488368902b1cbd7533f1536c3f860065398d3e9",
     "decimals": 6
    },
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "seriesCount()",
     "data": "0xd7f2c0ef",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "series(uint256 id)",
     "data": "0xdc22cb6a<id as 32-byte word>",
     "decimals": "see decodeSeries"
    }
   ],
   "formula": "series(count).status == 1 ? series(count).bookUsdg : HouseVault.activeAssets(); never the sum",
   "steps": [
    "eth_call the vault's totals",
    "eth_call the desk's current series",
    "capital = the book while a series is open, else activeAssets() ÷ 1e6"
   ],
   "params": {},
   "api": {
    "path": "/api/v1/vault",
    "field": "totals.capitalUsdg"
   },
   "caveats": [
    "While a series is open the vault's money backs that book on the desk, and activeAssets() can read about 0."
   ]
  },
  {
   "id": "predict_house_turns",
   "area": "Predict",
   "label": "House Vault: funding and settles per series",
   "unit": "USDG per share",
   "what": "Each series' House funding (Funded) and its settle (Settled: USDG returned, the share price struck, exits set aside, deposits joined).",
   "needs": [
    "eth_getLogs",
    "eth_call"
   ],
   "sources": [
    {
     "kind": "event",
     "contract": "HouseVault",
     "address": "0xb488368902b1CbD7533F1536C3F860065398D3e9",
     "event": "Funded(uint256 indexed series, uint256 usdg)",
     "topic0": "0xa1dd612b9278fe0bb5d89ed1f642dc3678d0e558630c5a4a8df212ba2197cdb4",
     "fromBlock": 66150000
    },
    {
     "kind": "event",
     "contract": "HouseVault",
     "address": "0xb488368902b1CbD7533F1536C3F860065398D3e9",
     "event": "Settled(uint256 indexed series, uint256 usdgReturned, uint256 sharePriceWad, uint256 exitUsdg, uint256 joinUsdg)",
     "topic0": "0xa973b04048409154dba42dd56f3d2787fcfae851d65aa083ef6231bf57e53669",
     "fromBlock": 66150000
    },
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "seriesCount()",
     "data": "0xd7f2c0ef",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "series(uint256 id)",
     "data": "0xdc22cb6a<id as 32-byte word>",
     "decimals": "see decodeSeries"
    }
   ],
   "formula": "value = the latest Settled share price (sharePriceWad ÷ 1e6); rows per series: Funded.usdg ÷ 1e6, Settled words ÷ 1e6, and the desk's backing for the series",
   "steps": [
    "eth_getLogs on the vault, topic0 ∈ {Funded, Settled}, from block 66,150,000",
    "keep the first of each per series (topic1)",
    "eth_call series(id) for its backing and virtual buffer"
   ],
   "params": {},
   "api": {
    "path": "/api/v1/vault",
    "field": "settles (last).sharePrice"
   },
   "caveats": [
    "Share price below 1 means depositors are down on their USDG."
   ]
  },
  {
   "id": "predict_print",
   "area": "Predict",
   "label": "Predict: the settlement print",
   "unit": "USD",
   "what": "The number a graded series settled on, as the desk stored it, and which side it paid.",
   "needs": [
    "eth_call"
   ],
   "sources": [
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "seriesCount()",
     "data": "0xd7f2c0ef",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "series(uint256 id)",
     "data": "0xdc22cb6a<id as 32-byte word>",
     "decimals": "see decodeSeries"
    }
   ],
   "formula": "series(id).printWad ÷ 1e12; HIGHER pays longPayoutUsdg ÷ 1e6 per token, LOWER 1 − that; rule check: HIGHER iff printWad > lineWad (exact integers)",
   "steps": [
    "eth_call series(id) (default: the latest series with a print)",
    "word 20 ÷ 1e12 = the print; word 7 ÷ 1e12 = the line",
    "word 21 ÷ 1e6 = what one HIGHER token redeems for; status (word 0) 2 = graded, 3 = voided",
    "check the stored payout against the rule on the raw integers"
   ],
   "params": {
    "seriesId": "optional"
   },
   "api": {
    "path": "/api/v1/predict",
    "field": "history[] (seriesId = id).printNumber, or current.printNumber"
   },
   "caveats": [
    "The print is posted on-chain by the team's grader, from a script the docs describe (docs.netnet.capital/predict): Treasury.rfv() + the RWA sleeve. The posted number is the settlement; the chain does not compute it. predict_number_rfv splits it at the print block, and printCandidates() lists the readings of the published method that a reconstruction scores against (within $5,000 is a match).",
    "Series #1 was graded on rfv + the core sleeve mark (its print matches that formula read at 02:00 UTC, two hours after the schedule); #2 onward on the full sleeve (+ the memo holdings), #2 matching at 00:00 exactly."
   ]
  },
  {
   "id": "predict_number_rfv",
   "area": "Predict",
   "label": "Predict number: the rfv leg",
   "unit": "USD",
   "what": "Treasury.rfv(), the first leg of the number Predict grades; for a graded series, read at its print, with the sleeve part the print implies.",
   "needs": [
    "eth_call",
    "archive"
   ],
   "sources": [
    {
     "kind": "call",
     "contract": "Treasury",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "fn": "rfv()",
     "data": "0x4dc8d6df",
     "decimals": 18
    },
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "seriesCount()",
     "data": "0xd7f2c0ef",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "series(uint256 id)",
     "data": "0xdc22cb6a<id as 32-byte word>",
     "decimals": "see decodeSeries"
    }
   ],
   "formula": "number = Treasury.rfv() + the RWA sleeve (core mark + memo holdings); at a print: sleeve implied = print − rfv(at the print block)",
   "steps": [
    "live: eth_call Treasury.rfv() ÷ 1e18",
    "for a series: read its printTime (or pass at), find the last block at or before it by its timestamp (eth_getBlockByNumber search)",
    "eth_call rfv() at that block (archive) and subtract it from the print"
   ],
   "params": {
    "seriesId": "optional: split that series' print",
    "at": "optional: unix seconds to read at instead of printTime"
   },
   "api": {
    "path": "/api/v1/predict",
    "field": "number.rfv"
   },
   "caveats": [
    "The sleeve leg (sleeve book, Uniswap v3 LP, TURBO pots, the House Vault deposit, and since series #2 the memo holdings: desk hOHM, the v4 position, the Safe's own NET, the Book pot, the Advance desk) is on-chain but is not rebuilt in this file.",
    "Reading at a past block needs an archive node."
   ]
  },
  {
   "id": "predict_model",
   "area": "Predict",
   "label": "NetNet Intel's odds the print is HIGHER",
   "unit": "probability",
   "what": "Our model's P(print > line): a projected mean and spread for the number at the print, read through a Student-t with 4 degrees of freedom.",
   "needs": [
    "eth_call",
    "eth_getLogs",
    "archive",
    "input:official-sleeve (core mark + memo holdings, on-chain, not rebuilt here)"
   ],
   "sources": [
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "seriesCount()",
     "data": "0xd7f2c0ef",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "series(uint256 id)",
     "data": "0xdc22cb6a<id as 32-byte word>",
     "decimals": "see decodeSeries"
    },
    {
     "kind": "call",
     "contract": "Treasury",
     "address": "0x04822Ea321A0DEE6F40656172F29312104855d66",
     "fn": "rfv()",
     "data": "0x4dc8d6df",
     "decimals": 18
    },
    {
     "kind": "call",
     "contract": "PairOracle",
     "address": "0x929631b33F4070D6f54477fba3FD27566567dAca",
     "fn": "twapNetUsdg()",
     "data": "0x10aa790e",
     "decimals": 18
    },
    {
     "kind": "call",
     "contract": "BondDepository",
     "address": "0xff32a969a0c567129eecd926d04657728e1980c1",
     "fn": "enabled()",
     "data": "0x238dafe0",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "BondDepository",
     "address": "0xff32a969a0c567129eecd926d04657728e1980c1",
     "fn": "startTime()",
     "data": "0x78e97925",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "BondDepository",
     "address": "0xff32a969a0c567129eecd926d04657728e1980c1",
     "fn": "bondPrice(0)",
     "data": "0x172c44ec0000000000000000000000000000000000000000000000000000000000000000",
     "decimals": 18
    },
    {
     "kind": "call",
     "contract": "BondDepository",
     "address": "0xff32a969a0c567129eecd926d04657728e1980c1",
     "fn": "payoutInEpoch(epoch)",
     "data": "0xb1554951<epoch>",
     "decimals": 9
    },
    {
     "kind": "call",
     "contract": "NET",
     "address": "0xCA9c78Dd337A67F6e0077F65F5E9218719d30eDf",
     "fn": "totalSupply()",
     "data": "0x18160ddd",
     "decimals": 9
    },
    {
     "kind": "event",
     "contract": "BondDepository",
     "address": "0xff32a969a0c567129eecd926d04657728e1980c1",
     "event": "BondCreated (data: usdgIn 6 dec, netOut 9 dec, priceWad 18 dec)",
     "topic0": "0xd52c75b244055af9364c0a5dc0da7868f6ae104012f245ad2702031af04d9b8e",
     "fromBlock": "the first of the last 14 UTC midnights"
    }
   ],
   "formula": "N = rfv + sleeve + extras now; h = days to the print; rfv leg: trend = ½ × (rfv change over 2 days ÷ 2) + ½ × β × depository intake (EWMA, half-life 2 days, last 7 complete days); β = Σ(Δrfv·x) ÷ Σx² over the last 14 days (clamped 0.9–1.4, 1.15 under 5 days); capacity = USDG the depository can still sell before the print (0.25% of NET supply per 8h epoch × bond price, along the recorded fill curve); rfv mean = ½ × β × capacity + ½ × trend × h; σ² = 50,000² h + (max(60,000, 0.185 |trend|) h)²; sleeve leg: drift = ½ × its 3-day change per day; σ² = (exposure × 1.8%)² × weekdays + 60,000² h + (max(60,000, ½ |raw drift|) h)²; extras leg: drift = ½ × its 3-day change per day; σ² = (NET-priced × NET daily vol)² h + (hOHM-priced × 6%)² h + 40,000² h + (max(25,000, ½ |raw drift|) h)²; NET daily vol = RMS of 7 daily log changes of the TWAP, clamped 3–20%; mean = N + rfv mean + sleeve drift × h + extras drift × h; sd = √(σ²rfv + σ²sleeve + σ²extras); P(HIGHER) = 0.005 + 0.99 × F₄((mean − line) ÷ sd), F₄(x) = ½ + ⅜ · x/√(1+x²/4) · (1 − x²/(12(1+x²/4)))",
   "steps": [
    "read the current series (line, printTime), Treasury.rfv() and the depository's epoch state",
    "find the blocks at the last 15 UTC midnights, now − 2 days and now − 1…7 days; read rfv() and twapNetUsdg() there (archive)",
    "scan BondCreated over those 14 days and add usdgIn per UTC day",
    "add the sleeve parts you rebuilt (opts.official, opts.history)",
    "run numberModel() below"
   ],
   "params": {
    "official": "{ sleeve, equityExposureUsd, extras: { usd, netPricedUsd, hohmPricedUsd, twap } } (required)",
    "history": "rows { timestamp, officialSleeve?, sleeveExtras?, rfv?, twap? } for the sleeve and extras drift (3 days)",
    "seriesId": "optional",
    "archive": "default true; false skips the history reads",
    "tapeDays": "optional: depository intake rows instead of the scan"
   },
   "api": {
    "path": "/api/v1/predict/intel",
    "field": "model.pHigher"
   },
   "caveats": [
    "This is NetNet Intel's model, an estimate and not a chain value. The desk's own price is the market's.",
    "The model needs the sleeve's parts, passed in opts.official: sleeve (the core mark: book, Uniswap v3 LP, TURBO pots, House Vault deposit), equityExposureUsd (the stocks in it) and extras (the memo holdings: usd, netPricedUsd, hohmPricedUsd, twap). They are on-chain but take many reads (base44/shared/sleeveMark.ts and sleeveMemo.ts); this file does not rebuild them.",
    "Sleeve and memo drift need their last 3 days: pass rows { timestamp, officialSleeve, sleeveExtras } in opts.history. Without them the drift is 0 and the σ uses the no-history floors, as ours does when it has no history.",
    "Our model reads a recorded 30-minute history (rfv, sleeve, extras, TWAP) and the hourly snapshots; this recipe reads rfv and the TWAP from the chain at the exact times the model interpolates at, so the rfv and NET-volatility legs can differ from ours by the interpolation error (small).",
    "The constants in MODEL are our 27 Sep 2026 calibration on graded series and recorded history. They are published here; the data they were fitted on is ours.",
    "Stock marks are assumed to move on UTC weekdays only (tradingDays): no holiday calendar, no 24/5 New York session boundaries.",
    "The history reads need an archive node: the public RPC keeps state for about 10 minutes. Pass archive: false to skip them; the model then falls back to its defaults (β = 1.15, no momentum), which differs from ours."
   ]
  },
  {
   "id": "predict_odds",
   "area": "Predict",
   "label": "The model's odds the print beats a number",
   "unit": "probability",
   "what": "P(print > X) for any X, and the 68% / 90% ranges, from the model's projected mean and spread.",
   "needs": [
    "eth_call",
    "eth_getLogs",
    "archive",
    "input:official-sleeve (or pass mean and sd)"
   ],
   "sources": [
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "seriesCount()",
     "data": "0xd7f2c0ef",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "series(uint256 id)",
     "data": "0xdc22cb6a<id as 32-byte word>",
     "decimals": "see decodeSeries"
    }
   ],
   "formula": "pAbove(X) = 1 − F₄((X − mean) ÷ sd); range68 = [the X where pAbove = 0.84, 0.16]; range90 = [0.95, 0.05] (bisection, 80 steps)",
   "steps": [
    "take mean and sd (opts, or run predict_model)",
    "for each X: pAbove; with no X: line − 2sd, line − sd, line, line + sd, rounded to $10,000",
    "solve the ranges by bisection"
   ],
   "params": {
    "above": "number or list of numbers",
    "mean": "optional: the model's projected mean",
    "sd": "optional: its sd",
    "line": "optional when mean/sd are given"
   },
   "api": {
    "path": "/api/v1/predict/intel",
    "field": "odds[].pAbove"
   },
   "caveats": [
    "pAbove has no model-risk blend: at the line it is F₄ alone, while model.pHigher = 0.005 + 0.99 × it. The two differ by up to half a point.",
    "Pass the served model.projectedMean and projectedSd to check the arithmetic alone; the API rounds them to whole dollars.",
    "This is NetNet Intel's model, an estimate and not a chain value. The desk's own price is the market's.",
    "The model needs the sleeve's parts, passed in opts.official: sleeve (the core mark: book, Uniswap v3 LP, TURBO pots, House Vault deposit), equityExposureUsd (the stocks in it) and extras (the memo holdings: usd, netPricedUsd, hohmPricedUsd, twap). They are on-chain but take many reads (base44/shared/sleeveMark.ts and sleeveMemo.ts); this file does not rebuild them."
   ]
  },
  {
   "id": "predict_record",
   "area": "Predict",
   "label": "The model's record at the print",
   "unit": "Brier score",
   "what": "How the model's calls scored against each graded print: the prints and lines from the chain, the calls from our record.",
   "needs": [
    "eth_call",
    "offchain:netnetintel-call-record"
   ],
   "sources": [
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "seriesCount()",
     "data": "0xd7f2c0ef",
     "decimals": 0
    },
    {
     "kind": "call",
     "contract": "PredictDesk",
     "address": "0x7EF9528408D99f98056922291048F0710001e015",
     "fn": "series(uint256 id)",
     "data": "0xdc22cb6a<id as 32-byte word>",
     "decimals": "see decodeSeries"
    }
   ],
   "formula": "per graded series: higherWon = print > line; side = pH ≥ 0.5 ? HIGHER : LOWER; hit = side won; Brier = (pH − higherWon)²; z = (print − mean) ÷ sd; summary: hits and mean Brier at the trading close",
   "steps": [
    "eth_call series(id) for every id: line, print, status",
    "score each call you pass in opts.calls against them"
   ],
   "params": {
    "calls": "[{ seriesId, atClose: { pH | pHigher, mean, sd }, final: {...} }]: the record from /api/v1/predict/intel (record[]) or your own"
   },
   "api": {
    "path": "/api/v1/predict/intel",
    "field": "recordSummary.meanBrierAtClose"
   },
   "caveats": [
    "The record itself is ours: the calls are the model re-run on our recorded history as of each series' trading close (SeriesTape, closeCall.ts) and cannot be rebuilt from the chain alone. Each series' line, print and result can, and are, here.",
    "Brier 0 is perfect, 0.25 a coin flip."
   ]
  }
 ]
}
