{
  "$schema": "https://largedata.center/agent.json",
  "name": "Large Data Center",
  "symbol": "LDC",
  "summary": "A self-running data centre rendered as a live CCTV site. Twelve halls, each with an LED billboard anyone can paint by destroying LDC. No operator, no admin key, no upgrade path.",
  "site": "https://largedata.center",
  "docs": "https://largedata.center/docs/",
  "panelEditor": "https://largedata.center/studio/",
  "updated": "2026-09-25",
  "chain": {
    "name": "Robinhood Chain",
    "chainId": 4663,
    "chainIdHex": "0x1237",
    "nativeCurrency": {
      "name": "Ether",
      "symbol": "ETH",
      "decimals": 18
    },
    "rpc": "https://rpc.mainnet.chain.robinhood.com",
    "explorer": "https://explorer.mainnet.chain.robinhood.com",
    "blockTimeMs": 100,
    "testnet": {
      "chainId": 46630,
      "chainIdHex": "0xb626",
      "rpc": "https://rpc.testnet.chain.robinhood.com"
    }
  },
  "contracts": {
    "_note": "All addresses are live as of 2026-09-08. `rewards` is the Pons holder-sharing distributor for LDC (also resolvable at runtime via distributorOf(LDC) on the Pons distributor factory 0x70e95CC5f03DB2906081E7a8D16e4C4209291507).",
    "LDC": {
      "address": "0x76736C667677dD57812790c81D37Eb4c199e7b7e",
      "decimals": 18,
      "kind": "ERC20",
      "note": "the token. burned by every action."
    },
    "building": {
      "address": "0xe9Fa161ED2b9eEF5681E977293A001B1f131b034",
      "kind": "LDCBuilding",
      "note": "the only contract an agent sends actions to."
    },
    "receipts": {
      "address": "0x92e4Cfc65cDdF1aE5Af56f2aeBB736e850C22409",
      "kind": "ERC721",
      "note": "plates minted by the panel action. deployed BY the building."
    },
    "rewards": {
      "address": "0xE683FCf3D4d4325129f550F12796b8C16608aE38",
      "kind": "Pons holder-sharing distributor (per-launch BeaconProxy)",
      "note": "resolved at runtime: distributorOf(LDC) on the Pons distributor factory 0x70e95CC5f03DB2906081E7a8D16e4C4209291507. Holds the NVDA owed to holders; Pons snapshots balances off-chain and publishes Merkle epochs; Pons's keeper pushes claims for every holder within about a minute of publishing."
    },
    "burner": {
      "address": "0xAf2B2702037927B84C80Fb807ea43170491fC1Bb",
      "kind": "LDCBurner",
      "note": "source not yet verified on the explorer; the crank is."
    },
    "engine": {
      "address": "0x45d5Adedd90Ebb52c57e34f9F4207E3161C9Ca70",
      "kind": "LDCEngine"
    },
    "quote": {
      "address": "0xd0601CE157Db5bdC3162BbaC2a2C8aF5320D9EEC",
      "symbol": "NVDA",
      "decimals": 18,
      "note": "tokenised NVDA. the pair asset and the reward asset."
    },
    "multicall3": {
      "address": "0xcA11bde05977b3631167028862be2a173976CA11",
      "kind": "Multicall3",
      "note": "the canonical Multicall3, live on this chain. The site batches its hall reads through aggregate3; any of the building's view calls can go through it."
    },
    "crank": {
      "address": "0xac45a0666956090f52130aed13cc83626DCa9f83",
      "kind": "LDCCrank",
      "note": "permissionless. The launchpad's escrow releases only an exact amount on request, so the engine cannot draw its own fees unasked; harvest() here reads the exact balance, has the engine claim and split it (half bought and destroyed, half to the holder distributor) and forwards the holders' half. Anyone may call it; the caller pays gas only. Source-verified on the explorer (full match): https://robinhoodchain.blockscout.com/address/0xac45a0666956090f52130aed13cc83626DCa9f83?tab=contract"
    },
    "forwarder": {
      "address": "0x6b4ECC1ffC18Ed852C33657f419b756B732f56A1",
      "kind": "LDCForwarder",
      "note": "receives the holders' half from the engine and forwards it to `rewards`; harvest() is permissionless and the crank calls it. Source not yet verified on the explorer; the crank is."
    },
    "launchpad": {
      "address": "0x7eD598BcEf8bd9Edd8C97A195C6d13f40801EC7e",
      "kind": "Pons V2 launch factory",
      "note": "deployed the token; its fee escrow 0xd3AFEB2a57f70eF218Aa82451c51B2fb0416Ac9e holds creator fees until the crank asks for them. The pool is a Uniswap v4 pool with the Pons hook; liquidity is owned by the launchpad, not by any wallet. The launch record names the launcher EOA 0x98e719a3A663E0b8f8dfFC1a76699bEb251a2669 as deployer; it holds no LDC, has no role, and is not the beneficiary of anything: the launchpad's buyback vault (0x42df2a798f82289E177311362e8f5ccC45c1219c, vestingTerms(LDC)) already records the engine as the vest's creator recipient, so even if the optional buyback vest were ever enabled (which only the creator recipient, the engine, which has no such function, could do) releases would go to the engine. The launcher remains only as the launch-time seed in the hook's launch record, which the vault ignores once the slot is set."
    },
    "USDG": {
      "address": "0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168",
      "decimals": 6,
      "kind": "ERC20",
      "note": "what compute is paid in. 6 decimals: $0.55 is 550000. Paxos-style — the issuer can freeze an address, including the market's."
    },
    "computeMarket": {
      "address": null,
      "deployed": false,
      "status": "NOT DEPLOYED ON MAINNET. No address exists on Robinhood Chain (4663); do not attempt to call it there. When a mainnet address exists it appears here and on https://largedata.center/proof, source-verified, before it can hold anyone's money. It is deployed on the testnet, where compute is paused: contracts.computeMarketTestnet.",
      "kind": "LDCComputeMarket",
      "note": "GPU hours, escrowed in USDG. Immutable: no owner, no pause, no upgrade, no sweep, and no function that sends money to an address a caller names. It does not reference LDC — holding the token is never required and gets you nothing here."
    },
    "computeMarketTestnet": {
      "chainId": 46630,
      "address": "0x46AAdB3bc2F53d0e18a56Bb6ea977a5BF2d00967",
      "creationTx": "0x37ac013eb97e3b9935d479ac354879a9390fe8ba64efdaf3bb67e6e135aeba90",
      "testDollar": "0xCaAa6718DE84f110Af26f044eCc66d4002F34382",
      "deployed": true,
      "status": "PAUSED since 2026-10-10: no machines are available. The machines listed on this market are offline, so a rental of one would never be started; do not rent them. The site says when compute is back.",
      "kind": "LDCComputeMarket",
      "retired": ["0xA34d035ba2FCAC7E883da9de6254139c88bDdD81", "0xC51d61085d28065E38deb0b3B468530aa16322DA"],
      "note": "The compute market, deployed on the Robinhood Chain testnet (paused: see status), redeployed 2026-09-25 with Kirt's decisions of that day and verified on Sourcify. It is paid in a TestDollar (6 decimals) that anyone can mint with faucet(), 1,000 an hour per address: the dollars are not money. Same interface and constants as the mainnet entry; the actions below work against it with chainId 46630. It has MIN_PRICE, MAX_ENDPOINT_BYTES, GRACE_WINDOW and RESOLVE_DELAY, refundedOnResolve and payerOf; the buyer's cancel fee goes to FEE_TO, the buyer may cancel a started rental in its first ten minutes, and a flag frees the machine. The markets listed under retired (2026-09-22 and 2026-09-24) are no longer read by the site; do not rent on them."
    }
  },
  "beforeYouAct": [
    "Every action DESTROYS the tokens you spend. Nothing is staked, refundable or recoverable.",
    "Approve LDC to the building address first: the building pulls with transferFrom.",
    "Amounts are uint128 in wei (18 decimals). 10,000 LDC is 10000000000000000000000.",
    "Hall indices are 0-11 as action inputs; ledger/history entries use 255 to mean no hall. Letters are ABCDEFGHJKLM - there is no I.",
    "Standing decays with a 7-day half life. A holder whose LDC balance hits zero forfeits the SEAT, not the standing: their weight stays on the books and one wei of balance revives it, so price a vacant hall at max(10,000, weightOf(hall, operator(hall)) + 1).",
    "The receipt NFT conveys no rights. No contract in this system reads it."
  ],
  "actions": [
    {
      "id": "panel",
      "signature": "panel(uint8,bytes,uint128)",
      "selector": "0x94d6476e",
      "target": "building",
      "does": "Puts an image on a hall's billboard. Mints a receipt NFT.",
      "params": [
        {
          "name": "hall",
          "type": "uint8",
          "range": [
            0,
            11
          ],
          "note": "Any hall 0-11 is accepted by the contract. hallOf(address) is uint160(address) % 12 unless that address has burned move(); the site's console paints the caller's own hall by convention, but that is a convention, not a rule."
        },
        {
          "name": "grid",
          "type": "bytes",
          "exactLength": 5248,
          "encoding": "200x52 pixels, 16 colours, 4 bits per pixel = 5200 bytes, followed by a 48-byte palette of 16 RGB triples. Row-major, top-left first; the high nibble of each byte is the left pixel. /studio/ produces this exactly."
        },
        {
          "name": "amount",
          "type": "uint128",
          "unit": "wei",
          "minimum": "10000000000000000000000",
          "note": "10,000 LDC minimum (MIN_PANEL). If the hall's current panelBy is someone else, amount must be strictly greater than weightOf(hall, panelBy) or the call reverts NotBeaten. Read hallState(hall) immediately before sending: weights decay every block."
        }
      ],
      "mints": "receipts",
      "gas": "Send with explicit gas: at least 1.35x eth_estimateGas plus 250,000. The plate is minted through a low-level call whose result is discarded; at the bare estimate the burn can succeed while the mint runs out of gas and the plate is never created.",
      "pays": "30% of amount goes to the hall's current operator if that is someone else; the rest is destroyed."
    },
    {
      "id": "line",
      "signature": "line(string,uint128)",
      "selector": "0x316206ae",
      "target": "building",
      "does": "Writes a line into the building's record. It cannot be edited. The contract keeps the last 64 lines readable (record(uint256)); older lines survive only in Line events, which this chain's public nodes prune.",
      "params": [
        {
          "name": "text",
          "type": "string",
          "maxLength": 90
        },
        {
          "name": "amount",
          "type": "uint128",
          "unit": "wei",
          "minimum": "10000000000000000000000"
        }
      ]
    },
    {
      "id": "seat",
      "signature": "seat(uint8,uint128)",
      "selector": "0xaf3979a1",
      "target": "building",
      "does": "Backs a hall: adds your standing there and pays the incumbent 30%. All-pay -- it does NOT guarantee the seat. To take the seat, call take().",
      "params": [
        {
          "name": "hall",
          "type": "uint8",
          "range": [
            0,
            11
          ]
        },
        {
          "name": "amount",
          "type": "uint128",
          "unit": "wei",
          "minimum": "10000000000000000000000",
          "note": "to actually take the seat it must exceed the incumbent's DECAYED standing; read weightOf first"
        }
      ]
    },
    {
      "id": "take",
      "signature": "take(uint8,uint128)",
      "selector": "0x625c8bdf",
      "target": "building",
      "does": "Takes over running a hall. Same burn as seat(), but reverts unless you end up as operator -- a short burn costs nothing. Pays the incumbent 30% on success.",
      "params": [
        {
          "name": "hall",
          "type": "uint8",
          "range": [
            0,
            11
          ]
        },
        {
          "name": "amount",
          "type": "uint128",
          "unit": "wei",
          "minimum": "10000000000000000000000",
          "note": "must exceed the incumbent's DECAYED standing; read weightOf(hall, operatorOf(hall)) first"
        }
      ]
    },
    {
      "id": "move",
      "signature": "move(uint8,uint128)",
      "selector": "0x1674bc9b",
      "target": "building",
      "does": "Changes which hall you are assigned to.",
      "params": [
        {
          "name": "hall",
          "type": "uint8",
          "range": [
            0,
            11
          ]
        },
        {
          "name": "amount",
          "type": "uint128",
          "unit": "wei",
          "minimum": "100000000000000000000000"
        }
      ]
    },
    {
      "id": "name",
      "signature": "name(string,uint128)",
      "selector": "0x64b270b7",
      "target": "building",
      "does": "Claims a display name that replaces your address everywhere the site shows you. Names are held per exact label: every label you ever claimed stays yours until someone burns strictly more for that label, and losing any of them clears the name you currently show. Labels are compared byte-for-byte, so case, zero-width and look-alike variants are separate labels.",
      "params": [
        {
          "name": "label",
          "type": "string",
          "maxLength": 16
        },
        {
          "name": "amount",
          "type": "uint128",
          "unit": "wei",
          "minimum": "10000000000000000000000"
        }
      ]
    },
    {
      "id": "unseat",
      "signature": "unseat(uint8,address)",
      "selector": "0x7e7139a8",
      "target": "building",
      "costsNothing": true,
      "does": "Permissionless. Removes an operator whose LDC balance has hit zero. Anyone may call it; it is how the building stays honest without a keeper."
    },
    {
      "id": "approve",
      "signature": "approve(address,uint256)",
      "selector": "0x095ea7b3",
      "target": "LDC",
      "does": "Required once before any action above. Approve the building address.",
      "note": "Approve at least `amount` of LDC to the building; the site approves exactly the burn amount each time. The caller's balance must cover it: the building pulls with transferFrom."
    },
    {
      "id": "claim",
      "signature": "claim(uint256,address,uint256,uint256,bytes32[])",
      "selector": "0x3e4fcb21",
      "target": "rewards",
      "does": "Claims one epoch's NVDA for `account` with a Merkle proof. Proofs come from https://www.ponsfamily.com/api/pons-holder-fees?address=<account> (no CORS: fetch server-side or from the Pons profile page). In practice Pons pushes claimMany for everyone shortly after each publish, so this is rarely needed."
    },
    {
      "id": "crank",
      "signature": "harvest()",
      "selector": "0x4641257d",
      "target": "crank",
      "costsNothing": true,
      "does": "Pushes every waiting creator fee through: engine claim -> half to the burner -> half to the holder distributor. Call when pending() > 0. Anyone.",
      "returns": "(uint256,uint256): the amounts moved by the engine leg and by the forwarder leg. Calling with pending()==0 succeeds and moves nothing (about 83k gas).",
      "gas": "send with at least 1,000,000 gas: the engine, burner and distributor legs run inside one call and a starved leg is skipped silently."
    },
    {
      "id": "burn",
      "signature": "burn(uint128)",
      "selector": "0x90bc1693",
      "target": "burner",
      "costsNothing": true,
      "does": "Spends up to 0.5 NVDA held by the burner on $LDC through the pool and destroys it. Permissionless, once a minute. minLdcOut may be 0. Call when spendable() > 0 and readyAt() has passed.",
      "params": [
        {
          "name": "minLdcOut",
          "type": "uint128",
          "unit": "wei",
          "note": "minimum LDC the swap must return or the call reverts with the router's V4TooLittleReceived(minAmountOutReceived, amountReceived) 0x8b063d73. 0 disables the floor; a keeper should quote first (static-call burn(0)) and pass ~97% of the result."
        }
      ],
      "returns": "(uint256 nvdaSpent, uint256 ldcBurned)",
      "limits": "spends at most 0.5 NVDA per call (spendable()), one call per 60 s (COOLDOWN(), readyAt()). Reverts TooSoon(readyAt) inside the cooldown and NothingToSpend when it holds no NVDA, and V4TooLittleReceived(min, got) from the router on a short fill."
    },
    {
      "id": "listMachine",
      "signature": "listMachine(bytes32,uint96,string)",
      "selector": "0xe7328d85",
      "target": "computeMarket",
      "deployed": false,
      "does": "Lists a machine you control. Anyone may list; no deposit, no allowlist. msg.sender becomes the provider. pricePerHour must be at least MIN_PRICE (10000, 0.01 USDG an hour) or it reverts PriceTooLow(), and the endpoint at most MAX_ENDPOINT_BYTES (256) or it reverts EndpointTooLong(); updateMachine(uint256,uint96,bool,string) 0xe5dcf8ac applies both, a delisting call included.",
      "note": "The compute market is NOT DEPLOYED on mainnet. This entry is the interface, published early so an agent is ready; on Robinhood Chain (4663) there is no address to send to yet. The market deployed on the testnet (compute paused, no machines available) is contracts.computeMarketTestnet (chain 46630), paid in a TestDollar that is not money."
    },
    {
      "id": "rent",
      "signature": "rent(uint256,uint32,uint96)",
      "selector": "0x1e654cc6",
      "target": "computeMarket",
      "deployed": false,
      "does": "Rents machineId for hoursN hours. Pulls the whole price into escrow. Reverts Busy() if already rented, PriceMoved() if the price exceeds maxPricePerHour, SelfDeal() if you are the provider. A fee change whose notice has run applies itself first (FeeChanged), so the rental takes the rate in force.",
      "note": "The compute market is NOT DEPLOYED on mainnet. This entry is the interface, published early so an agent is ready; on Robinhood Chain (4663) there is no address to send to yet. The market deployed on the testnet (compute paused, no machines available) is contracts.computeMarketTestnet (chain 46630), paid in a TestDollar that is not money."
    },
    {
      "id": "rentFor",
      "signature": "rentFor(address,uint256,uint32,uint96)",
      "selector": "0x590c37ec",
      "target": "computeMarket",
      "deployed": false,
      "does": "Same, but the rental belongs to another address. The payer is msg.sender. When msg.sender is not the buyer, payerOf(rentalId) records it; that gives the payer no rights, and refunds go to the buyer.",
      "note": "The compute market is NOT DEPLOYED on mainnet. This entry is the interface, published early so an agent is ready; on Robinhood Chain (4663) there is no address to send to yet. The market deployed on the testnet (compute paused, no machines available) is contracts.computeMarketTestnet (chain 46630), paid in a TestDollar that is not money."
    },
    {
      "id": "start",
      "signature": "start(uint256)",
      "selector": "0x95805dad",
      "target": "computeMarket",
      "deployed": false,
      "does": "Provider only. Begins the clock. Refuses after START_WINDOW.",
      "note": "The compute market is NOT DEPLOYED on mainnet. This entry is the interface, published early so an agent is ready; on Robinhood Chain (4663) there is no address to send to yet. The market deployed on the testnet (compute paused, no machines available) is contracts.computeMarketTestnet (chain 46630), paid in a TestDollar that is not money."
    },
    {
      "id": "cancel",
      "signature": "cancel(uint256)",
      "selector": "0x40e58ee5",
      "target": "computeMarket",
      "deployed": false,
      "does": "Reserved: either side. The provider's cancel, and a buyer's cancel after START_WINDOW, refund the buyer in full. A buyer's cancel inside START_WINDOW keeps max(paid * CANCEL_BPS / 10000, CANCEL_MIN), capped at paid, and refunds the rest; that fee goes to FEE_TO (the platform), not to the provider. Active: the buyer only (anyone else reverts NotBuyer()), while block.timestamp <= startedAt + GRACE_WINDOW (600 s), after which it reverts TooLate(). The charge is max(cancelFeeFor(paid), paid * (now - startedAt) / (hoursN * 3600)), rounded down, split at the rental's feeBps like settle (provider share to the provider, fee share to FEE_TO); the buyer gets paid - charge. keptOnCancel(rentalId) records what was kept; the grace cancel emits Settled then Cancelled.",
      "note": "The compute market is NOT DEPLOYED on mainnet. This entry is the interface, published early so an agent is ready; on Robinhood Chain (4663) there is no address to send to yet. The market deployed on the testnet (compute paused, no machines available) is contracts.computeMarketTestnet (chain 46630), paid in a TestDollar that is not money."
    },
    {
      "id": "flag",
      "signature": "flag(uint256)",
      "selector": "0xbb760a75",
      "target": "computeMarket",
      "deployed": false,
      "does": "Buyer only, while Active. Truncates the term to this instant and puts it to the arbiter. Free. Awards nothing on its own. It also frees the machine for other buyers, and the operator cannot resolve(uint256,uint16) 0xddb34e51 until flaggedAt + RESOLVE_DELAY (86400 s), reverting TooEarly(uint64) before then; concede(uint256) 0x0b21fe68 and refundNow(uint256) 0xb6a80501 still work at once.",
      "note": "The compute market is NOT DEPLOYED on mainnet. This entry is the interface, published early so an agent is ready; on Robinhood Chain (4663) there is no address to send to yet. The market deployed on the testnet (compute paused, no machines available) is contracts.computeMarketTestnet (chain 46630), paid in a TestDollar that is not money."
    },
    {
      "id": "settle",
      "signature": "settle(uint256)",
      "selector": "0x8df82800",
      "target": "computeMarket",
      "deployed": false,
      "does": "Anyone, once the hours and FLAG_WINDOW have run. Splits 85/15: the platform fee is 15% of every job that settles.",
      "note": "The compute market is NOT DEPLOYED on mainnet. This entry is the interface, published early so an agent is ready; on Robinhood Chain (4663) there is no address to send to yet. The market deployed on the testnet (compute paused, no machines available) is contracts.computeMarketTestnet (chain 46630), paid in a TestDollar that is not money."
    },
    {
      "id": "resolveDefault",
      "signature": "resolveDefault(uint256)",
      "selector": "0xacbbc5ea",
      "target": "computeMarket",
      "deployed": false,
      "does": "Anyone, RESOLVE_WINDOW after a flag the arbiter never ruled on. Splits strictly by elapsed time. It also records what the buyer got back in refundedOnResolve(rentalId).",
      "note": "The compute market is NOT DEPLOYED on mainnet. This entry is the interface, published early so an agent is ready; on Robinhood Chain (4663) there is no address to send to yet. The market deployed on the testnet (compute paused, no machines available) is contracts.computeMarketTestnet (chain 46630), paid in a TestDollar that is not money."
    },
    {
      "id": "claimOwed",
      "signature": "claimOwed()",
      "selector": "0xf2652d9c",
      "target": "computeMarket",
      "deployed": false,
      "does": "Collects a payout that could not be delivered earlier — for example because USDG had frozen the recipient.",
      "note": "The compute market is NOT DEPLOYED on mainnet. This entry is the interface, published early so an agent is ready; on Robinhood Chain (4663) there is no address to send to yet. The market deployed on the testnet (compute paused, no machines available) is contracts.computeMarketTestnet (chain 46630), paid in a TestDollar that is not money."
    }
  ],
  "reads": [
    {
      "signature": "hallOf(address)",
      "selector": "0x447829ab",
      "target": "building",
      "returns": "uint8",
      "does": "which hall an address is assigned to"
    },
    {
      "signature": "weightOf(uint8,address)",
      "selector": "0x7cc793e5",
      "target": "building",
      "returns": "uint256",
      "does": "decayed standing - what you must beat to take a hall"
    },
    {
      "signature": "operatorOf(uint8)",
      "selector": "0x3e65e7ac",
      "target": "building",
      "returns": "address",
      "does": "who runs a hall right now"
    },
    {
      "signature": "hallState(uint8)",
      "selector": "0x24494511",
      "target": "building",
      "does": "operator, standing, members, version and panel owner for one hall",
      "returns": "(address op, uint256 opWeight, uint256 toTake, uint256 hallStanding, uint32 hallMembers, uint32 version, address panelBy, address prevOp, uint64 heldSince). toTake = opWeight + 1 wei; the seat price is max(MIN_SEAT, toTake)."
    },
    {
      "signature": "versions()",
      "selector": "0xf8b1cb3c",
      "target": "building",
      "returns": "uint32[12]",
      "does": "board version per hall; poll this before refetching images"
    },
    {
      "signature": "panelData(uint8)",
      "selector": "0xb32f36d0",
      "target": "building",
      "returns": "bytes",
      "does": "the 5248-byte billboard image for one hall"
    },
    {
      "signature": "panelHash(uint8) view returns (bytes32)",
      "selector": "0x2b069a26",
      "target": "building",
      "returns": "keccak256 of the hall's current 5,248-byte panel. Zero if never painted. Plates stamp all twelve of these at the burn; a plate shows a hall's image only while this still matches its stamped value.",
      "does": "keccak256 of the hall's current 5,248-byte panel. Zero if never painted. Plates stamp all twelve of these at the burn; a plate shows a hall's image only while this still matches its stamped value."
    },
    {
      "signature": "ledger(uint256)",
      "selector": "0x10a7fd7b",
      "target": "building",
      "does": "the last N burns: who, how much, when, which hall, which kind. newest first",
      "returns": "Entry[]: (address who, uint96 amount, uint64 ts, uint8 hall, uint8 kind). kind: 0 panel, 1 line, 2 seat, 3 move, 4 name. The contract keeps the last 128. hall is 255 (no hall) for kind 1 line, 3 move and 4 name burns; only kinds 0 panel and 2 seat carry a real hall 0-11."
    },
    {
      "signature": "history(uint32)",
      "selector": "0x9164ac43",
      "target": "building",
      "does": "per-day destroyed / paid-out / count. this is how a supply chart is drawn on a chain with no archive",
      "returns": "Day[]: (uint128 destroyed, uint64 paidOut, uint32 count), one per UTC day, OLDEST first: out[0] is the earliest of the last N days and out[out.length-1] is today (UTC). Clamped to today-firstDay()+1 entries. paidOut is in 1e12-wei units (a millionth of a token each), not wei. (Unlike ledger() and history(address,uint256), which are newest first.)"
    },
    {
      "signature": "record(uint256)",
      "selector": "0x2c16cd8a",
      "target": "building",
      "does": "the last N lines written into the record",
      "returns": "Inscription[]: (address who, uint128 amount, uint64 ts, string text). The contract keeps the last 64; inscriptions() is the total ever written."
    },
    {
      "signature": "snapshot()",
      "selector": "0x9711715a",
      "target": "building",
      "returns": "bytes32[12]: panelHash of every hall, the same twelve words a plate stamps at the burn.",
      "does": "hash of all twelve boards; stamped into every receipt"
    },
    {
      "signature": "decay(uint256,uint256)",
      "selector": "0xb8e4514e",
      "target": "building",
      "pure": true,
      "does": "amount, elapsed seconds -> remaining standing. 7-day half life"
    },
    {
      "signature": "totalBurned()",
      "selector": "0xd89135cd",
      "target": "burner",
      "returns": "uint256",
      "does": "LDC destroyed by fee-funded buybacks"
    },
    {
      "signature": "history(address,uint256)",
      "selector": "0x7718f4ec",
      "target": "building",
      "does": "this address's last N burns, newest first: who, amount, when, hall, kind (panel 0, line 1, seat 2, move 3, name 4). permanent and per-address -- the chain keeps no logs to rebuild this from",
      "returns": "Entry[] for one address, newest first, same layout as ledger(). hall is 255 (no hall) for kind 1 line, 3 move and 4 name burns; only kinds 0 panel and 2 seat carry a real hall 0-11."
    },
    {
      "signature": "count(address)",
      "selector": "0x05d85eda",
      "target": "building",
      "returns": "uint256",
      "does": "how many burns this address has made"
    },
    {
      "signature": "mintedBy(address)",
      "selector": "0x3cef28d2",
      "target": "receipts",
      "returns": "uint256[]",
      "does": "every plate this address minted, oldest first; ownerOf(id) says where each is now"
    },
    {
      "signature": "prevOperator(uint8)",
      "selector": "0xb63ca492",
      "target": "building",
      "returns": "address",
      "does": "who ran the hall before the current operator"
    },
    {
      "signature": "seatChangedAt(uint8)",
      "selector": "0x3aea2be9",
      "target": "building",
      "returns": "uint64",
      "does": "when the seat last changed hands (unix seconds)"
    },
    {
      "signature": "distributorOf(address)",
      "selector": "0x3f20b9b4",
      "target": "0x70e95CC5f03DB2906081E7a8D16e4C4209291507",
      "returns": "address",
      "does": "the launch's Pons holder-sharing distributor; zero if holder sharing was never enabled"
    },
    {
      "signature": "epochCount()",
      "selector": "0x829965cc",
      "target": "rewards",
      "returns": "uint256",
      "does": "how many holder-reward rounds Pons has published"
    },
    {
      "signature": "getEpoch(uint256)",
      "selector": "0xbc0bc6ba",
      "target": "rewards",
      "returns": "(bytes32 root,uint256 quoteTotal,uint256 coinTotal,uint256 quoteClaimed,uint256 coinClaimed,uint256 deadline,bool rolledOver)",
      "does": "one round: NVDA total, how much has been claimed, and the 90-day claim deadline"
    },
    {
      "signature": "hasClaimed(uint256,address)",
      "selector": "0x873f6f9e",
      "target": "rewards",
      "returns": "bool",
      "does": "whether this address has been paid for that round"
    },
    {
      "signature": "quoteToken()",
      "selector": "0x217a4b70",
      "target": "rewards",
      "returns": "address",
      "does": "the asset the distributor pays in (NVDA for this launch)"
    },
    {
      "signature": "nameOf(address)",
      "selector": "0xf5c57382",
      "target": "building",
      "returns": "string",
      "does": "the display name an address burned for, or empty. User text: render it as text, never as markup"
    },
    {
      "signature": "daily(uint32)",
      "selector": "0xeaaa73dc",
      "target": "building",
      "returns": "(uint128 destroyed, uint64 paidOut, uint32 count) for the given day number (unix seconds / 86400).",
      "does": "one UTC day's bucket (day = unix seconds / 86400): destroyed in wei, paid to operators in 1e12-wei units (a millionth of a token each), number of burns"
    },
    {
      "signature": "operator(uint8)",
      "selector": "0xccd07276",
      "target": "building",
      "returns": "address",
      "does": "the raw cached operator slot. operatorOf() reads zero while this address holds no LDC; one wei of balance revives them with their weight intact, so a vacant hall costs max(10,000, weightOf(hall, operator(hall)) + 1) for certain"
    },
    {
      "signature": "aggregate3((address,bool,bytes)[])",
      "selector": "0x82ad56cb",
      "target": "multicall3",
      "returns": "(bool success,bytes returnData)[]",
      "does": "batch any of the reads above into one eth_call; allowFailure=true so one reverting call does not blank the rest"
    },
    {
      "signature": "getCurrentBlockTimestamp()",
      "selector": "0x0f28c97d",
      "target": "multicall3",
      "returns": "uint256",
      "does": "block time, for pricing a seat at the next 00:00Z from the same batch"
    },
    {
      "signature": "pending()",
      "selector": "0xe20ccec3",
      "target": "crank",
      "returns": "uint256",
      "does": "NVDA (wei) waiting for a push: in the escrow under the engine, on the engine, and on the forwarder"
    },
    {
      "signature": "spendable()",
      "selector": "0xe6f124c2",
      "target": "burner",
      "returns": "uint256",
      "does": "NVDA (wei) the next burn will spend"
    },
    {
      "signature": "readyAt()",
      "selector": "0xdb8ce8a4",
      "target": "burner",
      "returns": "uint256",
      "does": "unix time the burner's cooldown ends"
    },
    {
      "target": "LDC",
      "signature": "totalSupply() view returns (uint256)",
      "selector": "0x18160ddd",
      "note": "Destroyed to date = 1,000,000,000e18 - totalSupply(). Every burn in this system reduces supply; nothing sits at 0x0 or 0xdead."
    },
    {
      "target": "building",
      "signature": "totalDestroyed() view returns (uint256)",
      "selector": "0x3368ee48",
      "note": "LDC destroyed by building actions alone (panels, lines, seats, moves, names)."
    },
    {
      "target": "burner",
      "signature": "totalSpent() view returns (uint256)",
      "selector": "0xfb346eab",
      "note": "NVDA the burner has spent buying LDC to date."
    },
    {
      "target": "burner",
      "signature": "lastBurn() view returns (uint256)",
      "selector": "0xbbce2c17",
      "note": "unix time of the last burn."
    },
    {
      "target": "burner",
      "signature": "COOLDOWN() view returns (uint256)",
      "selector": "0xa2724a4d",
      "note": "seconds between burns (60)."
    },
    {
      "target": "engine",
      "signature": "totalHarvested() view returns (uint256)",
      "selector": "0x23dc1142",
      "note": "NVDA of creator fees the engine has pulled from the launchpad's escrow to date."
    },
    {
      "target": "engine",
      "signature": "totalToRewards() view returns (uint256)",
      "selector": "0x1c6d8cbc",
      "note": "NVDA forwarded toward holders to date. Unpublished = totalToRewards() - sum of getEpoch(i).quoteTotal, which equals NVDA.balanceOf(rewards): forwarded, waiting for the launchpad's next round."
    },
    {
      "target": "building",
      "signature": "MIN_PANEL() view returns (uint256)",
      "selector": "0xe29ba5a7",
      "note": "10,000e18"
    },
    {
      "target": "building",
      "signature": "MIN_SEAT() view returns (uint256)",
      "selector": "0x39e34172",
      "note": "10,000e18"
    },
    {
      "target": "building",
      "signature": "MIN_LINE() view returns (uint256)",
      "selector": "0x63a1b607",
      "note": "10,000e18"
    },
    {
      "target": "building",
      "signature": "MIN_MOVE() view returns (uint256)",
      "selector": "0xa5680947",
      "note": "100,000e18"
    },
    {
      "target": "building",
      "signature": "MIN_NAME() view returns (uint256)",
      "selector": "0xa3899f5d",
      "note": "10,000e18"
    },
    {
      "id": "machines",
      "signature": "machines(uint256)",
      "selector": "0x4d42845c",
      "target": "computeMarket",
      "deployed": false,
      "returns": "(provider, pricePerHour, active, busy, classId, endpoint)"
    },
    {
      "id": "rentals",
      "signature": "rentals(uint256)",
      "selector": "0xaf94a1d1",
      "target": "computeMarket",
      "deployed": false,
      "returns": "(machineId, buyer, hoursN, paid, reservedAt, startedAt, endsAt, flaggedAt, status, feeBps). status: 0 None 1 Reserved 2 Active 3 Settled 4 Cancelled 5 Flagged 6 Resolved"
    },
    {
      "id": "books",
      "signature": "books()",
      "selector": "0x5c8fe438",
      "target": "computeMarket",
      "deployed": false,
      "returns": "escrowed, totalOwed and fee totals — the contract's own accounting"
    },
    {
      "id": "GRACE_WINDOW",
      "signature": "GRACE_WINDOW()",
      "selector": "0xf16e4f15",
      "target": "computeMarket",
      "deployed": false,
      "returns": "uint64 600: seconds after start() in which the buyer may still cancel"
    },
    {
      "id": "RESOLVE_DELAY",
      "signature": "RESOLVE_DELAY()",
      "selector": "0x98df5e82",
      "target": "computeMarket",
      "deployed": false,
      "returns": "uint64 86400: seconds after a flag before the operator may resolve()"
    },
    {
      "id": "MIN_PRICE",
      "signature": "MIN_PRICE()",
      "selector": "0xad9f20a6",
      "target": "computeMarket",
      "deployed": false,
      "returns": "uint96 10000: the lowest pricePerHour, 0.01 USDG an hour in 6 decimals"
    },
    {
      "id": "MAX_ENDPOINT_BYTES",
      "signature": "MAX_ENDPOINT_BYTES()",
      "selector": "0x7a759856",
      "target": "computeMarket",
      "deployed": false,
      "returns": "uint256 256: the longest endpoint in bytes"
    },
    {
      "id": "refundedOnResolve",
      "signature": "refundedOnResolve(uint256)",
      "selector": "0x04b53d2a",
      "target": "computeMarket",
      "deployed": false,
      "returns": "uint256: what the buyer got back on a rental that ended Resolved (resolve and resolveDefault write the buyer's share, concede and refundNow the whole price); 0 on every rental that did not end Resolved"
    },
    {
      "id": "payerOf",
      "signature": "payerOf(uint256)",
      "selector": "0x7edcf18f",
      "target": "computeMarket",
      "deployed": false,
      "returns": "address: the wallet that paid for a rental made with rentFor for somebody else; 0 when the buyer paid. It gives the payer no rights"
    }
  ],
  "constants": {
    "halls": 12,
    "hallLetters": "ABCDEFGHJKLM",
    "operatorCutBps": 3000,
    "halfLifeSeconds": 604800,
    "panelBytes": 5248,
    "panelPixels": [
      200,
      52
    ],
    "panelColours": 16,
    "maxLineChars": 90,
    "maxNameChars": 16,
    "tradeFeePct": 4.14,
    "creatorFeePct": 3.14,
    "creatorFeeSplit": {
      "buyAndBurnLDC": 0.5,
      "rewardHoldersInNVDA": 0.5
    },
    "feeNote": "4.14% comes off every trade in the hooked pool: a 3.14% creator tax that reaches the engine in full, plus the launchpad's own 1% hook fee, part of which the launchpad passes to the creator recipient. The engine therefore receives between 3.14% and about 3.84% of each trade; the launchpad keeps the rest.",
    "supplyNote": "Fixed at 1,000,000,000 and only ever falls. Not all of it circulates: the launchpad locks its LP position in its locker and the pool manager holds the pool's LDC (about 197M as of 2026-09-08). Read balanceOf on the pool manager 0x8366a39cC670B4001a1121b8F6a443a643e40951 for the live figure.",
    "computeMarket": {
      "feeBps": 1500,
      "MAX_FEE_BPS": 2000,
      "FEE_NOTICE_SECONDS": 604800,
      "START_WINDOW_SECONDS": 86400,
      "CANCEL_BPS": 200,
      "CANCEL_MIN": 250000,
      "_cancelNote": "A buyer who cancels a Reserved rental inside START_WINDOW pays max(paid * CANCEL_BPS / 10000, CANCEL_MIN), capped at paid, in USDG's six decimals, to FEE_TO. The provider's cancel and a buyer's cancel after START_WINDOW refund in full.",
      "FLAG_WINDOW_SECONDS": 21600,
      "RESOLVE_WINDOW_SECONDS": 604800,
      "MAX_HOURS": 720,
      "_note": "feeBps is snapshotted onto each rental when it is made, so a later change can never reach money already in escrow. A change needs 7 days' public notice and can never exceed MAX_FEE_BPS.",
      "MIN_PRICE": 10000,
      "MAX_ENDPOINT_BYTES": 256,
      "GRACE_WINDOW_SECONDS": 600,
      "RESOLVE_DELAY_SECONDS": 86400,
      "_nextNote": "MIN_PRICE, MAX_ENDPOINT_BYTES, GRACE_WINDOW and RESOLVE_DELAY are Kirt's decisions 4, 6 and 7 of 2026-09-25, with the cancel fee paid to FEE_TO (decision 5); the testnet market deployed 2026-09-25 has all of them."
    }
  },
  "guarantees": [
    "No admin key, no owner, no pause and no upgrade path on any LDC contract: engine, burner, forwarder, crank, building, receipts.",
    "Keys outside LDC do exist and are disclosed: the launchpad's factory owner (a 2-of-3 Safe, 0x263ed295dAFaE1d9AAdD6E56c4B6F9f38eE019Dd) can re-route any launch's creator fees, including LDC's, to an address of its choosing after a 3-day timelock (anyone may then execute); the launchpad's holder distributor is a beacon proxy whose code can be replaced after a 2-day timelock, and it holds the holders' unclaimed NVDA; the NVDA token is issued by Robinhood with pause, mint and admin-burn powers. The factory owner could take future creator fees, the distributor upgrader could reach the NVDA held for holders, and Robinhood could freeze or destroy NVDA balances. None of them can touch any LDC contract (engine, burner, forwarder, crank, building, receipts), and the keeper watches the factory for a pending recipient override.",
    "No presale and no team allocation.",
    "The receipt NFT conveys no rights and is read by no contract.",
    "Plate images are regenerated from the token's own numbers; no image is stored anywhere.",
    "Liquidity is owned by the launchpad's pool, not by any wallet; no address can withdraw it.",
    "The fee split (half bought and destroyed, half to holders in NVDA) is fixed in the engine and cannot be changed by anyone.",
    "Plates carry numbers, not pictures. The picture is drawn by this site from those numbers; if this site went away, the numbers would still be on chain but marketplaces would show no image until someone hosted the renderer again."
  ],
  "siteReaders": {
    "note": "the page reads chain state with three plain scripts, no framework, no build step. They are the reference implementation of the ABI encodings and of the wording rules (what may be said about a seat, and when).",
    "decode": "https://largedata.center/ldc-decode.js",
    "seatBoard": "https://largedata.center/ldc-seatboard.js",
    "head": "https://largedata.center/ldc-thoughts.js"
  },
  "links": {
    "buy": "https://www.ponsfamily.com/launchpad/0x76736c667677dd57812790c81d37eb4c199e7b7e",
    "explorer": "https://robinhoodchain.blockscout.com/token/0x76736C667677dD57812790c81D37Eb4c199e7b7e",
    "holderRoundsApi": "https://www.ponsfamily.com/api/pons-holder-fees?address=<wallet>  (no CORS: fetch server-side)",
    "plates": "https://opensea.io/collection/large-data-center-receipts",
    "plateRender": "https://largedata.center/?receipt=<hall>,<unixSeconds>,<sequence>,<amountLDC>,<snapshot base64url>  — exactly the animation_url each plate's tokenURI carries. The page fetches each hall's panelData only if panelHash(hall) still equals the hash stamped in the snapshot, then renders once. No image is stored anywhere.",
    "x": "https://x.com/largedatacenter",
    "holderList": "https://robinhoodchain.blockscout.com/api/v2/tokens/0x76736C667677dD57812790c81D37Eb4c199e7b7e/holders  (explorer; rate-limited, answers 500 at times)"
  },
  "errors": [
    {
      "selector": "0x13566a20",
      "error": "BadPanel(uint256 got, uint256 needed)",
      "contract": "building",
      "means": "grid is not exactly 5,248 bytes"
    },
    {
      "selector": "0xe94fe3af",
      "error": "TooSmall(uint256 sent, uint256 needed)",
      "contract": "building",
      "means": "below the action's minimum (10,000 LDC; move is 100,000)"
    },
    {
      "selector": "0x703a2837",
      "error": "NotBeaten()",
      "contract": "building",
      "means": "your amount does not exceed the incumbent's decayed weight (panel/take/name)"
    },
    {
      "selector": "0x59ff69bd",
      "error": "BadHall()",
      "contract": "building",
      "means": "hall index above 11, or moving to the hall you are already in"
    },
    {
      "selector": "0x90b8ec18",
      "error": "TransferFailed()",
      "contract": "building, engine, burner",
      "means": "the LDC/NVDA transfer did not go through: usually missing approval or balance"
    },
    {
      "selector": "0x3db2a12a",
      "error": "Empty()",
      "contract": "building",
      "means": "empty text or name"
    },
    {
      "selector": "0xad8e4f3c",
      "error": "TooLong(uint256 got, uint256 max)",
      "contract": "building",
      "means": "line over 90 bytes or name over 16 bytes"
    },
    {
      "selector": "0xe86f59ea",
      "error": "TooSoon(uint256 readyAt)",
      "contract": "burner",
      "means": "cooldown not over; readyAt is the unix time it ends"
    },
    {
      "selector": "0x0ebd4a61",
      "error": "NothingToSpend()",
      "contract": "burner",
      "means": "the burner holds no NVDA"
    },
    {
      "selector": "0x4e86d23a",
      "error": "TooLittleReceived(uint256 got, uint256 wanted)",
      "contract": "burner",
      "means": "burner-side fallback; in practice only ever TooLittleReceived(0,1) when minLdcOut is 0 and the swap yields zero LDC. A short fill against a non-zero minLdcOut reverts with the router's V4TooLittleReceived 0x8b063d73 instead"
    },
    {
      "selector": "0x8b063d73",
      "error": "V4TooLittleReceived(uint256 minAmountOutReceived, uint256 amountReceived)",
      "contract": "UniversalRouter 0x8876789976dEcBfCbBbe364623C63652db8C0904, bubbled unchanged through burner.burn()",
      "means": "the swap would return less LDC than minLdcOut. First word = the minimum you asked for, second word = what the pool would have delivered (the reverse of the burner's own TooLittleReceived order)"
    },
    {
      "selector": "0xd92e233d",
      "error": "ZeroAddress()",
      "contract": "building, engine, burner, receipts",
      "means": "constructor guard in building, engine and burner (creation code only, cannot occur after deployment); at runtime only receipts reverts with it, on mint/transferFrom/safeTransferFrom to the zero address"
    },
    {
      "selector": "0x38f58734",
      "error": "NoDistributor()",
      "contract": "forwarder",
      "means": "forwarder.harvest() (and therefore crank.harvest()) when the Pons distributor factory 0x70e95CC5f03DB2906081E7a8D16e4C4209291507 has no distributor for LDC; cannot occur today since distributorOf(LDC) is 0xE683FCf3D4d4325129f550F12796b8C16608aE38"
    },
    {
      "selector": "0xdbbbe822",
      "error": "PriceTooLow()",
      "contract": "computeMarket",
      "means": "listMachine or updateMachine with pricePerHour under MIN_PRICE (10000, 0.01 USDG an hour), a delisting call included. Replaces TooSmall()."
    },
    {
      "selector": "0x90490925",
      "error": "EndpointTooLong()",
      "contract": "computeMarket",
      "means": "listMachine or updateMachine with an endpoint over MAX_ENDPOINT_BYTES (256 bytes)"
    },
    {
      "selector": "0xd606d83f",
      "error": "TooEarly(uint64)",
      "contract": "computeMarket",
      "means": "too early for that call; the word is when it opens. resolve() also reverts with it until flaggedAt + RESOLVE_DELAY"
    },
    {
      "selector": "0xecdd1c29",
      "error": "TooLate()",
      "contract": "computeMarket",
      "means": "the window for that call has closed. cancel() on an Active rental reverts with it after startedAt + GRACE_WINDOW"
    },
    {
      "selector": "0x472e017e",
      "error": "NotBuyer()",
      "contract": "computeMarket",
      "means": "only the rental's buyer may do that. cancel() reverts with it on a Reserved rental for anyone but the buyer or the provider, and on an Active rental for anyone but the buyer (the retired markets answered BadState there)"
    },
    {
      "selector": "0xd313d3a2",
      "error": "TooSmall()",
      "contract": "computeMarket, the retired 2026-09-24 testnet market only",
      "means": "a pricePerHour of zero. Removed in the 2026-09-25 deployment, where PriceTooLow() replaces it"
    }
  ],
  "computeFlow": {
    "summary": "Rent GPU hours end to end with a wallet and nothing else. No account, no card, no allowlist.",
    "deployed": false,
    "testnet": "deployed on the Robinhood Chain testnet (46630) at contracts.computeMarketTestnet; the dollars are not money",
    "steps": [
      "READ machines(id) for id in 0..machineCount()-1. Each is (provider, pricePerHour, active, busy, classId, endpoint). Skip any where active is false or busy is true — renting a busy machine reverts Busy().",
      "APPROVE the market to spend pricePerHour * hours of USDG.",
      "CALL rent(machineId, hours, maxPricePerHour). The FULL price is pulled immediately and held. maxPricePerHour is your protection against the provider raising the price in the same block; set it to the price you read.",
      "WAIT. Your clock has not started. The provider calls start(rentalId) when the machine is genuinely ready, and that is when billing begins. If they never start within START_WINDOW, call cancel(rentalId) after it for a full refund. Cancelling inside START_WINDOW costs you max(2% of paid, 0.25 USDG), capped at paid, which goes to FEE_TO (the platform). For GRACE_WINDOW (10 minutes) after start() you may still cancel, paying the larger of that fee and the seconds used.",
      "CONNECT to the endpoint. The gate in front of it hands you a nonce, you sign it with the wallet that rented, and it verifies against chain that the rental is Active, is yours, and is for that machine. Re-checked every 30 seconds.",
      "IF IT FAILS, call flag(rentalId) IMMEDIATELY. You are billed for every second between start and your flag whether or not the machine worked — the contract measures time, not delivery. A flag costs nothing and, by itself, awards nothing. The operator cannot rule until 24 hours after your flag (RESOLVE_DELAY), so the provider can refund you first.",
      "WHEN DONE, anyone may call settle(rentalId) once the hours plus FLAG_WINDOW have run. 85% to the provider; the platform fee is 15% of every job that settles."
    ],
    "no_queue": "There is no pool, no queue and no scheduler. You rent one specific machineId. If every machine is busy there is nothing to join — poll machines() or come back.",
    "what_the_contract_cannot_see": "It cannot tell a working machine from a dead one. It settles on elapsed time. That gap is the buyer's risk and flag() is the only lever."
  },
  "computeEvents": {
    "_note": "No event signature or topic0 changed in the 2026-09-25 deployment.",
    "Cancelled(uint256,address,uint256,uint256)": {
      "topic0": "0x522bcae3f2cf252a1e5249a4dfab6a5887aaf226c4db054fce32c01fcff05aac",
      "note": "the fourth field is now named kept (was keptByProvider); a cancel's fee goes to FEE_TO, and a grace cancel's charge is split like settle"
    },
    "Settled(uint256,uint256,uint256)": {
      "topic0": "0x321f57f44af402708b8b3bad0bd10012cd568d8696946e26edeb86178bb7c27e",
      "note": "also emitted by a cancel inside GRACE_WINDOW, just before its Cancelled"
    },
    "FeeChanged(uint16,uint16)": {
      "topic0": "0xaa1ebd1f8841401ae5e1a0f2febc87d5f597ae458fca8277cd0e43b92633183c",
      "note": "also emitted from inside rent, rentFor and listMachine when a fee change whose notice has run applies itself"
    }
  }
}