{
  "project": {
    "name": "p/xmr",
    "file": "p-xmr.json",
    "schema_version": "1.0.0",
    "settlement_chain": "Monero mainnet",
    "one_line": "A pump.fun style coin whose issuance, bonding curve, buys, sells, creator fees and graduation all settle as ordinary Monero transactions, with no bridge, no wrapped asset and no second chain.",
    "summary": "Monero has no smart contracts and no token standard. p/xmr treats that as the design constraint rather than a blocker. The coin exists as a deterministic registry that anyone can rebuild from scratch by scanning one Monero wallet with its published view key. Every buy is an XMR transfer into the curve wallet. Every sell is an XMR transfer out of it. The curve formula is fixed, the constants are fixed, and the registry is the pure function of the inflows and outflows that the view key exposes. Nothing about a holder's position lives anywhere except inside Monero transactions and the rules in this file.",
    "principles": [
      "Every state transition is a Monero transaction. If it did not settle on Monero it did not happen.",
      "The curve wallet publishes its private view key and its public address on the first block it is used. From that moment every inflow is publicly auditable by anyone running a node.",
      "The coin registry is rebuildable from nothing. A verifier with monerod, monero-wallet-rpc and this file can reconstruct every balance without trusting the operator.",
      "No event fires on a clock. Anchors, fee sweeps and graduation are triggered by trades and by the state of the curve, never by a timer.",
      "Holders never hand over spend keys. Selling is authorized with a Monero message signature over a fixed payload.",
      "Nothing is wrapped, bridged, pegged or mirrored. The reserve is XMR sitting in a Monero wallet."
    ]
  },

  "monero_reference": {
    "note": "Protocol facts about Monero mainnet used by the design. These are properties of the network, not choices made by p/xmr.",
    "consensus": {
      "proof_of_work": "RandomX",
      "target_block_time_seconds": 120,
      "difficulty_adjustment": "every block, using a window of recent block timestamps",
      "coinbase_maturity_blocks": 60,
      "spend_lock_blocks": 10,
      "tail_emission_xmr_per_block": 0.6,
      "tail_emission_note": "Once the main emission curve ran out the block reward floored at 0.6 XMR per block and stays there permanently, so the network always has a miner subsidy."
    },
    "units": {
      "base_unit": "piconero",
      "piconero_per_xmr": 1000000000000,
      "decimals": 12,
      "rpc_amounts": "All monerod and monero-wallet-rpc amounts are integers in piconero."
    },
    "privacy_primitives": {
      "sender_privacy": "ring signatures, CLSAG scheme, fixed ring size of 16 members since network upgrade v15",
      "receiver_privacy": "stealth addresses, one time output keys derived per output",
      "amount_privacy": "RingCT with Bulletproofs+ range proofs",
      "network_privacy": "Dandelion++ transaction propagation, optional Tor and I2P for node connections",
      "consequence_for_design": "The sender of a transaction cannot be identified from the chain. That is why every buy has to carry its own payout instruction inside tx_extra, and why the registry keys positions by payout address rather than by any notion of sender."
    },
    "addresses": {
      "standard_address_prefix": "4",
      "standard_address_length_chars": 95,
      "subaddress_prefix": "8",
      "subaddress_length_chars": 95,
      "integrated_address_prefix": "4",
      "integrated_address_length_chars": 106,
      "integrated_address_payment_id_bytes": 8,
      "subaddress_indexing": "account index (major) and address index (minor), written as major/minor, for example 0/0 for the primary address"
    },
    "transaction_format": {
      "version": 2,
      "extra_field": "tx_extra, a byte array that carries the transaction public key, optional additional pubkeys for subaddress outputs, an optional 8 byte encrypted payment id, and an optional extra nonce",
      "extra_nonce_max_bytes": 255,
      "extra_nonce_tag_byte": "0x02",
      "encrypted_payment_id_tag_bytes": "0x02 0x09 0x01",
      "additional_pubkeys_tag_byte": "0x04",
      "tx_pubkey_tag_byte": "0x01",
      "fee_model": "dynamic per byte fee derived from recent block weights, with four wallet priority tiers",
      "penalty_free_block_weight_bytes": 300000,
      "wallet_rpc_fee_priorities": [
        { "priority": 0, "name": "default", "meaning": "wallet picks based on current conditions" },
        { "priority": 1, "name": "unimportant" },
        { "priority": 2, "name": "normal" },
        { "priority": 3, "name": "elevated" },
        { "priority": 4, "name": "priority" }
      ]
    },
    "ports": {
      "p2p_default": 18080,
      "node_rpc_default": 18081,
      "wallet_rpc_common": 18082
    },
    "message_signing": {
      "rpc_method": "sign",
      "verify_method": "verify",
      "signature_prefix_spend_key": "SigV2",
      "note": "monero-wallet-rpc signs arbitrary strings with the wallet spend key and anyone can verify against the public address. p/xmr uses this for sell authorization so a holder never exposes a private key."
    },
    "multisig": {
      "supported_schemes": "M of N wallets built through prepare_multisig, make_multisig, exchange_multisig_keys, and signing with sign_multisig and submit_multisig",
      "status": "available in the reference wallet, documented as experimental",
      "use_in_p_xmr": "the post graduation pool wallet is 2 of 3 multisig so that no single operator key can drain the reserve"
    }
  },

  "pump_fun_reference": {
    "note": "The constants p/xmr carries over from the pump.fun bonding curve on Solana. Token side constants are preserved exactly. The quote asset changes from SOL to XMR.",
    "token_total_supply": 1000000000,
    "token_decimals_on_solana": 6,
    "initial_virtual_token_reserves": 1073000000,
    "initial_real_token_reserves": 793100000,
    "tokens_reserved_for_post_curve_liquidity": 206900000,
    "initial_virtual_sol_reserves": 30,
    "graduation_condition": "real token reserves reach zero, at which point roughly 85 SOL has been collected on the curve and the coin moves to an open market pool",
    "curve_type": "constant product on virtual reserves, x times y equals k",
    "trade_fee_percent": 1.0
  },

  "coin": {
    "display_name": "p/xmr",
    "total_supply_units": 1000000000,
    "decimals": 6,
    "smallest_unit_name": "grain",
    "grains_per_unit": 1000000,
    "supply_in_grains": 1000000000000000,
    "mint_authority": "none, the supply is fixed by this file and never changes",
    "where_balances_live": "in the registry, which is a deterministic fold over the curve wallet's transaction history",
    "position_key": "a Monero payout address (standard or subaddress) supplied by the buyer inside tx_extra at purchase time",
    "transferability": "positions move only by selling into the curve or pool and buying again; there is no send between holders in phase one, because a peer transfer would need a settlement that Monero cannot express without an XMR movement",
    "phase_two_transfer": "after graduation a holder may reassign a position to a new payout address with a signed reassignment message, which the registry treats as a zero XMR event anchored in the next anchor transaction"
  },

  "wallet_architecture": {
    "curve_wallet": {
      "role": "receives every buy, pays every sell, holds the XMR reserve during the curve phase",
      "key_material": {
        "private_spend_key": "held by the operator only, never published, used to pay sells and to sign anchors",
        "private_view_key": "published in full at deployment so that all inflows are auditable",
        "public_address": "published at deployment, standard address of account 0"
      },
      "account_layout": [
        { "major": 0, "minor": 0, "purpose": "primary address, buy destination, printed everywhere" },
        { "major": 0, "minor": 1, "purpose": "creator fee accumulation, receives the fee cut of every buy as a separate output in the same sell or anchor transaction" },
        { "major": 0, "minor": 2, "purpose": "anchor self sends, every anchor transaction pays a minimal output here so that the anchor is a real on chain event" },
        { "major": 1, "minor": 0, "purpose": "graduation staging, the reserve is moved here in a single transaction at graduation before the multisig pool is funded" }
      ],
      "rpc_flags": [
        "monero-wallet-rpc --daemon-address 127.0.0.1:18081 --rpc-bind-port 18082 --wallet-file curve --password-file curve.pass --disable-rpc-login",
        "monerod --data-dir /var/lib/monero --rpc-bind-port 18081 --p2p-bind-port 18080 --prune-blockchain --no-igd --out-peers 32"
      ]
    },
    "view_only_verifier_wallet": {
      "role": "what any third party runs to audit p/xmr",
      "creation": "generate_from_keys with the published address and published private view key, no spend key",
      "capability": "sees every incoming transfer to any subaddress of the curve wallet with amount, block height, tx hash and tx_extra; cannot spend",
      "limitation": "a view only wallet cannot see outgoing spends with certainty because Monero hides the spender. p/xmr solves this by having every outgoing transaction also pay a marker output back into 0/2, and by publishing the key images of spent outputs in the anchor payload so the verifier can match them."
    },
    "pool_wallet": {
      "role": "holds the XMR side of the constant product market after graduation",
      "type": "2 of 3 multisig",
      "signers": [
        "operator key one",
        "operator key two, held on a separate machine",
        "recovery key, held offline and only used if one operator key is lost"
      ],
      "view_key_publication": "the multisig wallet's private view key is published at graduation exactly as the curve wallet's was"
    },
    "user_wallet_requirements": {
      "must_support": [
        "setting a custom tx_extra nonce on an outgoing transfer, or using an integrated address so an 8 byte payment id can be embedded",
        "signing an arbitrary message with the spend key",
        "generating subaddresses"
      ],
      "known_compatible": [
        "monero-wallet-cli",
        "monero-wallet-rpc",
        "monero-wallet-gui"
      ],
      "integrated_address_fallback": "a wallet that cannot set tx_extra can still buy by sending to an integrated address whose 8 byte payment id encodes a registration index; the buyer first registers a payout address through a zero cost signed message and receives that index"
    }
  },

  "bonding_curve": {
    "formula": {
      "invariant": "virtual_xmr_reserve times virtual_token_reserve equals k",
      "buy": "tokens_out equals virtual_token_reserve minus k divided by (virtual_xmr_reserve plus xmr_in_after_fee)",
      "sell": "xmr_out_before_fee equals virtual_xmr_reserve minus k divided by (virtual_token_reserve plus tokens_in)",
      "spot_price_xmr_per_token": "virtual_xmr_reserve divided by virtual_token_reserve",
      "rounding": "all arithmetic in integers, XMR in piconero, tokens in grains, division floors, k is computed once at genesis and stored as an integer"
    },
    "constants": {
      "note": "Design parameters of p/xmr. Token side matches pump.fun. The XMR virtual reserve is a chosen parameter of this project.",
      "initial_virtual_token_reserves_units": 1073000000,
      "initial_virtual_token_reserves_grains": 1073000000000000,
      "initial_real_token_reserves_units": 793100000,
      "initial_real_token_reserves_grains": 793100000000000,
      "post_curve_liquidity_units": 206900000,
      "post_curve_liquidity_grains": 206900000000000,
      "initial_virtual_xmr_reserve_xmr": 30,
      "initial_virtual_xmr_reserve_piconero": 30000000000000,
      "initial_real_xmr_reserve_piconero": 0,
      "k_piconero_times_grains": 32190000000000000000000000000,
      "graduation_real_xmr_collected_xmr": 85,
      "graduation_real_xmr_collected_piconero": 85000000000000,
      "graduation_rule": "the curve closes when real token reserves reach zero grains; solving the invariant, that happens when about 85 XMR of real reserve has accumulated, the same shape as the Solana curve"
    },
    "worked_example_first_buy": {
      "note": "Pure arithmetic from the constants above, not an observed trade.",
      "xmr_in": 1,
      "xmr_in_piconero": 1000000000000,
      "fee_percent": 1.0,
      "fee_piconero": 10000000000,
      "xmr_in_after_fee_piconero": 990000000000,
      "new_virtual_xmr_piconero": 30990000000000,
      "new_virtual_token_grains": "k divided by 30990000000000, floored, equals 1038722168441432",
      "tokens_out_grains": "1073000000000000 minus 1038722168441432 equals 34277831558568",
      "tokens_out_units": "34277831.558568",
      "spot_price_after_xmr_per_unit": "30.99 divided by 1038722168.441432 equals 0.0000000298348"
    },
    "minimums": {
      "minimum_buy_piconero": 10000000000,
      "minimum_buy_xmr": 0.01,
      "reason": "a buy below the network fee plus the fee cut would produce a sell payout smaller than the dust threshold of the wallet, so it is refused at registry level and the XMR is returned in the next anchor"
    }
  },

  "fees": {
    "trade_fee_percent": 1.0,
    "split": {
      "creator_percent_of_fee": 50,
      "operator_percent_of_fee": 50
    },
    "creator_fee_destination": "subaddress 0/1 of the curve wallet during the curve phase, then the creator's own payout address after graduation, paid out inside the same transaction as each sell",
    "no_clock_rule": "creator fees are never batched on a schedule; they are settled as an output inside the next transaction the curve wallet sends, which is always a sell payout or an anchor triggered by a trade",
    "network_fee_handling": "the buyer pays the Monero network fee on a buy; the curve wallet pays the network fee on a sell and deducts it from xmr_out"
  },

  "transactions": {
    "buy": {
      "direction": "user wallet to curve wallet 0/0",
      "amount": "any XMR at or above the minimum buy",
      "tx_extra_nonce_layout": {
        "byte_0": "0x02 extra nonce tag",
        "byte_1": "length of the nonce that follows",
        "bytes_2_to_5": "ascii p x m r, the magic",
        "byte_6": "0x01, operation code for buy",
        "bytes_7_to_38": "32 byte public spend key of the payout address",
        "bytes_39_to_70": "32 byte public view key of the payout address",
        "byte_71": "0x00 for a standard address, 0x01 for a subaddress",
        "bytes_72_to_79": "8 byte little endian minimum tokens out in grains, the slippage floor, zero means no floor"
      },
      "total_nonce_bytes": 78,
      "registry_effect": "on confirmation the registry computes tokens_out from the amount and the curve state at that height, checks the slippage floor, and credits the payout address; if the floor fails the XMR is queued for refund in the next anchor",
      "confirmation_rule": "10 blocks, matching the Monero spend lock, because the reserve cannot be spent before then anyway",
      "ordering_rule": "buys in the same block are ordered by their position in the block's transaction list, which is fixed by the miner and visible to every node"
    },
    "sell": {
      "step_1_authorization": {
        "what_the_holder_signs": "the canonical string p/xmr|sell|<payout_address>|<tokens_in_grains>|<min_xmr_out_piconero>|<registry_height>",
        "how": "monero-wallet-rpc sign with the spend key of the payout address, producing a SigV2 signature",
        "delivery": "the signature and the string are submitted to the sell intake endpoint of the operator, and also broadcast to the registry mirror channel so that the intake cannot silently drop them"
      },
      "step_2_settlement": {
        "direction": "curve wallet to the holder's payout address",
        "outputs": [
          { "destination": "holder payout address", "amount": "xmr_out minus fee minus network fee" },
          { "destination": "curve wallet 0/1", "amount": "creator half of the fee" },
          { "destination": "curve wallet 0/2", "amount": "1 piconero marker" }
        ],
        "tx_extra_nonce_layout": {
          "bytes_2_to_5": "ascii p x m r",
          "byte_6": "0x02, operation code for sell settlement",
          "bytes_7_to_38": "32 byte blake2b hash of the signed authorization string",
          "bytes_39_to_46": "8 byte little endian tokens_in in grains",
          "bytes_47_to_78": "32 byte registry root after this sell is applied"
        }
      },
      "registry_effect": "tokens_in are debited from the payout address and returned to real token reserves; the registry root in the nonce becomes the new head",
      "replay_protection": "the registry_height inside the signed string must equal the current registry head height, so a signature is valid for exactly one state"
    },
    "anchor": {
      "purpose": "commit the registry root on chain and publish the key images of every output the curve wallet has spent since the last anchor, so the verifier can reconcile outflows",
      "trigger": "fires when the registry has applied a trade and no sell settlement has already carried a root for that trade, so every buy that is not followed by a sell within the same block gets its own anchor; there is no interval and no timer",
      "outputs": [
        { "destination": "curve wallet 0/2", "amount": "1 piconero" }
      ],
      "tx_extra_nonce_layout": {
        "bytes_2_to_5": "ascii p x m r",
        "byte_6": "0x03, operation code for anchor",
        "bytes_7_to_38": "32 byte registry root",
        "bytes_39_to_46": "8 byte little endian registry height",
        "bytes_47_onward": "concatenated 32 byte key images of outputs spent since the previous anchor, as many as fit in the remaining nonce budget, overflow rolls into the next anchor"
      }
    },
    "refund": {
      "trigger": "a buy that failed its slippage floor or fell below the minimum",
      "settlement": "paid back to the payout address encoded in the failed buy, inside the next anchor or sell transaction as an additional output",
      "fee": "the network fee of the returning transaction is deducted, nothing else"
    },
    "graduation": {
      "trigger": "the buy that drives real token reserves to zero grains",
      "steps": [
        "the curve wallet moves the entire real XMR reserve minus accumulated creator fees to subaddress 1/0 in one transaction tagged with operation code 0x04",
        "the 2 of 3 multisig pool wallet is created and its address and private view key are published inside the tx_extra of a second transaction tagged 0x05",
        "the staged reserve is sent from 1/0 to the pool wallet address in a third transaction tagged 0x06",
        "the registry marks 206900000 units of the post curve liquidity as the pool's token side and switches the price function to the pool's constant product",
        "creator fees accumulated in 0/1 are paid to the creator's payout address in the same 0x06 transaction as a separate output"
      ],
      "irreversibility": "once operation 0x06 confirms the curve wallet's 0/0 address stops accepting buys; any XMR sent there afterwards is refunded by the pool wallet in its next transaction"
    },
    "pool_trade": {
      "note": "after graduation buys and sells follow the same nonce formats as the curve, with the pool wallet address as the destination and the pool's reserves as the virtual reserves",
      "pool_invariant": "pool_xmr_reserve times pool_token_reserve equals k_pool, set at graduation from the actual XMR received and 206900000 units",
      "pool_fee_percent": 1.0
    }
  },

  "registry": {
    "definition": "an ordered list of events derived from the curve wallet's confirmed transactions, and the balances that result from folding those events in order",
    "event_types": [
      { "code": 1, "name": "buy", "source": "incoming transfer to 0/0 with a valid buy nonce" },
      { "code": 2, "name": "sell", "source": "outgoing transaction with a sell nonce and a valid signed authorization" },
      { "code": 3, "name": "anchor", "source": "outgoing transaction with an anchor nonce" },
      { "code": 4, "name": "stage", "source": "outgoing transaction to 1/0 with the stage nonce" },
      { "code": 5, "name": "pool_declare", "source": "outgoing transaction carrying the pool wallet address and view key" },
      { "code": 6, "name": "fund_pool", "source": "outgoing transaction from 1/0 to the pool wallet" },
      { "code": 7, "name": "refund", "source": "an output in a sell or anchor that returns a failed buy" },
      { "code": 8, "name": "reassign", "source": "a signed reassignment message committed inside an anchor after graduation" }
    ],
    "state_fields": {
      "registry_height": "count of applied events",
      "registry_root": "blake2b-256 over the previous root concatenated with the canonical encoding of the event",
      "virtual_xmr_reserve_piconero": "integer",
      "virtual_token_reserve_grains": "integer",
      "real_xmr_reserve_piconero": "integer",
      "real_token_reserve_grains": "integer",
      "creator_fee_accrued_piconero": "integer",
      "positions": "map from payout address string to balance in grains",
      "phase": "one of the phases listed under state_machine",
      "last_anchor_tx_hash": "hex",
      "last_anchor_height": "Monero block height",
      "spent_key_images": "set of hex strings"
    },
    "canonical_event_encoding": "operation code byte, then Monero block height as 8 byte little endian, then tx hash as 32 bytes, then output index as 4 bytes little endian, then amount in piconero as 8 bytes little endian, then the raw nonce bytes",
    "rebuild_procedure": [
      "start monerod and let it sync fully",
      "create a view only wallet with generate_from_keys using the published address and private view key, restore height equal to the published genesis height",
      "call refresh until the wallet reports the daemon's height",
      "call get_transfers with in true, out true, pool false, filter_by_height true, min_height equal to genesis height",
      "for each incoming transfer read the tx_extra of the transaction with get_transaction_by_hash on monerod, decode the extra nonce, and if the magic and operation code match, emit an event",
      "for each anchor transaction read the key image list and add them to spent_key_images",
      "sort events by block height then by index within the block",
      "fold events from the genesis constants and compare the resulting root to the root inside the latest anchor",
      "a match means the operator has not deviated; a mismatch means the operator applied an event the chain does not support, and the chain wins"
    ]
  },

  "state_machine": {
    "phases": [
      {
        "name": "unfunded",
        "meaning": "genesis constants published, view key published, no buy yet",
        "exits": ["accumulating on the first confirmed buy"]
      },
      {
        "name": "accumulating",
        "meaning": "curve open, real token reserves above zero",
        "exits": ["staged on the buy that empties real token reserves"]
      },
      {
        "name": "staged",
        "meaning": "reserve moved to 1/0, pool not yet declared",
        "exits": ["declared when the 0x05 transaction confirms"]
      },
      {
        "name": "declared",
        "meaning": "pool wallet address and view key are public, reserve not yet inside it",
        "exits": ["pooled when the 0x06 transaction confirms"]
      },
      {
        "name": "pooled",
        "meaning": "constant product market live in the multisig wallet",
        "exits": ["none, this is terminal"]
      }
    ],
    "market_modes_inside_accumulating": [
      { "name": "compressed", "rule": "spot price within 2 percent of the price at the last anchor" },
      { "name": "directional", "rule": "spot price moved more than 2 percent in one direction across the last three anchors" },
      { "name": "dislocated", "rule": "a single trade moved spot price more than 10 percent" }
    ],
    "market_mode_note": "modes are derived labels computed from registry state for display only; they never change any rule"
  },

  "verification": {
    "what_anyone_can_check_without_trust": [
      "every XMR that ever entered the curve wallet, with height and amount, from the view key",
      "the payout address encoded on each buy",
      "the registry root committed in each anchor and each sell",
      "that the registry rebuilt from the chain produces the same root",
      "the key images of every spend the operator made, and therefore that the reserve balance equals inflows minus the outflows the anchors admit to"
    ],
    "what_requires_the_operator_to_be_honest": [
      "that a valid sell authorization is settled promptly; the chain cannot force the operator to send, it can only expose that a signed authorization exists and was not honored, which is why authorizations are mirrored publicly",
      "that no spend is made without an anchor admitting it; a hidden spend would show up as reserve drift when a verifier compares inflows to the admitted key images and the balance the wallet later proves"
    ],
    "balance_proof": "the operator publishes a reserve proof with get_reserve_proof after every anchor; anyone verifies it with check_reserve_proof against the published address, which proves the wallet controls at least the stated amount without revealing the spend key",
    "spend_proof": "every sell settlement is accompanied by get_spend_proof output so the holder can confirm the payout originated from the curve wallet",
    "node_rpc_methods_used": [
      "get_info",
      "get_block_count",
      "get_block",
      "get_transactions",
      "get_transaction_pool",
      "is_key_image_spent",
      "send_raw_transaction"
    ],
    "wallet_rpc_methods_used": [
      "generate_from_keys",
      "refresh",
      "get_balance",
      "get_address",
      "create_address",
      "get_transfers",
      "get_transfer_by_txid",
      "transfer",
      "transfer_split",
      "sign",
      "verify",
      "get_reserve_proof",
      "check_reserve_proof",
      "get_spend_proof",
      "check_spend_proof",
      "get_tx_key",
      "check_tx_key",
      "make_integrated_address",
      "split_integrated_address",
      "prepare_multisig",
      "make_multisig",
      "exchange_multisig_keys",
      "export_multisig_info",
      "import_multisig_info",
      "sign_multisig",
      "submit_multisig",
      "export_key_images",
      "import_key_images"
    ]
  },

  "edge_cases": {
    "buy_with_no_nonce": "credited to a holding bucket keyed by the transaction hash; the sender can claim it by signing the string p/xmr|claim|<tx_hash>|<payout_address> with the tx key proven through check_tx_key, otherwise it sits unclaimed and is never spent",
    "buy_with_malformed_nonce": "same as no nonce",
    "buy_below_minimum": "refunded minus network fee in the next outgoing transaction",
    "two_buys_same_block": "applied in block order, second buy gets the price after the first",
    "sell_larger_than_balance": "rejected at intake, nothing settles",
    "sell_signature_for_old_height": "rejected, holder re-signs with the current height",
    "operator_wallet_offline": "buys still confirm and still count because the registry is derived from the chain; sells queue in the public mirror and settle when the wallet returns; graduation trigger is evaluated on the chain state not on the operator's uptime",
    "chain_reorg": "the registry follows the longest chain; an event in an orphaned block is dropped and re-applied if its transaction is included again; the 10 block confirmation rule makes this practically unreachable for settled sells",
    "dust_output": "a sell whose xmr_out after fees is below 1000 piconero is refused at intake",
    "fee_spike": "if the network fee for a sell exceeds 5 percent of xmr_out the intake asks the holder to re-sign with a lower min_xmr_out or wait; nothing settles without a valid signature that covers the outcome",
    "lost_operator_key_during_curve": "the reserve is unrecoverable, which is the honest statement; mitigations are the multisig at graduation and the reserve proofs that show the wallet is still under control after every anchor"
  },

  "security": {
    "keys_never_leaving_users": "holders only ever sign messages; the sell flow has no step where a private key is transmitted",
    "operator_key_handling": "spend key of the curve wallet lives on one machine with no inbound network access; the wallet rpc is reached over a local socket by the intake process",
    "intake_hardening": [
      "every authorization is verified with the verify rpc before it is queued",
      "authorizations are appended to a public mirror so dropping one is visible",
      "the settlement process refuses to build a transaction whose outputs do not match the registry's computed xmr_out exactly"
    ],
    "what_the_view_key_reveals": "all incoming amounts, all subaddresses used, and the tx_extra of every incoming transaction; it does not reveal outgoing amounts or the spend key",
    "what_the_view_key_does_not_protect": "holder privacy is bounded by the payout address the holder chose; a holder who wants unlinkable positions uses a fresh subaddress per buy"
  },

  "build": {
    "components": [
      {
        "name": "registry daemon",
        "language": "Rust",
        "inputs": ["monerod rpc", "monero-wallet-rpc view only wallet"],
        "outputs": ["registry state json", "registry root", "event log"],
        "crates": ["monero-rs for address and tx_extra parsing", "blake2 for roots", "serde_json"]
      },
      {
        "name": "intake service",
        "language": "Rust",
        "inputs": ["signed sell authorizations", "registry state"],
        "outputs": ["settlement transactions through the spend wallet rpc"],
        "rules": ["verifies signature", "checks height", "computes xmr_out", "builds transfer with exact outputs", "attaches sell nonce", "broadcasts", "waits for confirmation", "publishes spend proof"]
      },
      {
        "name": "anchor builder",
        "language": "Rust",
        "trigger": "registry applied a buy that has no root on chain",
        "output": "anchor transaction with root, height and pending key images"
      },
      {
        "name": "verifier cli",
        "language": "Rust",
        "purpose": "the thing an outsider runs; rebuilds the registry and compares roots"
      },
      {
        "name": "site",
        "tool": "Lovable",
        "data_source": "registry state json served by the registry daemon over a Supabase edge function that proxies the local rpc, no key material ever reaches the browser",
        "site_rules": [
          "the site is a readout with no controls on public pages",
          "buys and sells happen in the visitor's own Monero wallet, the site only shows the address, the nonce to attach, and the current curve state",
          "every value slot renders blank until the genesis transaction is confirmed, then fills from the registry"
        ]
      }
    ],
    "deploy_checklist": [
      "generate the curve wallet on the offline machine and record the address, private view key and genesis restore height",
      "publish the address, view key and genesis height inside the tx_extra of a first self send to 0/2 tagged with operation code 0x00, which is the genesis event and fixes the constants in this file by including its blake2b hash",
      "start monerod pruned and let it sync",
      "start the registry daemon pointed at the view only wallet and confirm it reports phase unfunded",
      "start the intake service against the spend wallet rpc on the local socket",
      "start the anchor builder",
      "run the verifier cli from a clean machine and confirm it reproduces the genesis root",
      "fill the slots below from the confirmed genesis transaction and only then let the site fill its value slots"
    ]
  },

  "slots": {
    "note": "Filled from the chain after deployment. Blank until then. Nothing in this block is ever guessed.",
    "curve_wallet_address": "",
    "curve_wallet_private_view_key": "",
    "genesis_tx_hash": "",
    "genesis_block_height": null,
    "genesis_root": "",
    "creator_payout_address": "",
    "pool_wallet_address": "",
    "pool_wallet_private_view_key": "",
    "stage_tx_hash": "",
    "pool_declare_tx_hash": "",
    "fund_pool_tx_hash": "",
    "latest_anchor_tx_hash": "",
    "latest_registry_root": "",
    "latest_registry_height": null
  },

  "glossary": {
    "anchor": "an outgoing Monero transaction whose only job is to commit the registry root and spent key images on chain",
    "curve wallet": "the Monero wallet that runs the bonding curve phase",
    "extra nonce": "the free form byte field inside tx_extra that p/xmr uses to carry instructions",
    "grain": "the smallest unit of the coin, one millionth of a unit",
    "key image": "the value a Monero spend publishes so the same output cannot be spent twice; p/xmr publishes the curve wallet's key images so verifiers can see which outputs it spent",
    "payout address": "the Monero address a holder's position is keyed by and paid to",
    "piconero": "the smallest unit of XMR, one trillionth",
    "registry": "the deterministic state rebuilt from the curve wallet's transactions",
    "registry root": "a hash chain over every applied event",
    "reserve proof": "a Monero proof that a wallet controls at least a stated balance",
    "spend proof": "a Monero proof that a given transaction was sent by a given wallet",
    "view key": "the key that reveals incoming transfers to a Monero wallet without allowing spending",
    "virtual reserve": "the curve's accounting reserve, which starts above the real reserve so that the first buy has a finite price"
  }
}
