Markets
This commit is contained in:
Executable
+55
@@ -0,0 +1,55 @@
|
||||
# Gated mainnet candidate
|
||||
|
||||
This repository now has a **separate mainnet candidate profile**, not an audited or launched production network. Shipping code does not establish independent miners, economic security, an operational public network, or a safe real-money market. **Payments remain mocked on every profile.**
|
||||
|
||||
## What is implemented
|
||||
|
||||
| Property | Testnet default | Mainnet candidate |
|
||||
| --- | --- | --- |
|
||||
| Selection | `WIKIDECK_NETWORK=testnet` (or unset) | `WIKIDECK_NETWORK=mainnet` |
|
||||
| Network ID | `wikideck-randomx-testnet-6` | `wikideck-randomx-mainnet-1` |
|
||||
| Protocol | Existing version 6 | Version 6 under a distinct chain identity |
|
||||
| Genesis timestamp | Unchanged | 2027-01-01 00:00 UTC, **candidate only, not a promised launch** |
|
||||
| Ledger/market subdirectory | testnet | mainnet |
|
||||
| Browser wallet | Existing testnet store, unchanged | Separate mainnet store |
|
||||
| Payment mode | Mock only | Mock only |
|
||||
|
||||
Both profiles use real RandomX validation, cumulative-work branch selection, the 15-minute target, mint maturity, signed NFT transfers, atomic card trades, and SQLite persistence. The mainnet candidate has no premine, token migration, hidden checkpoint, or fake-PoW option. Changing the network identifier and candidate genesis derives distinct chain/genesis IDs, RandomX initial keys, signature domains, and consensus manifest checks. Existing testnet values and data remain unchanged.
|
||||
|
||||
**Testnet cards and backups do not migrate.** Browser storage is separate, backup network headers are authenticated and checked, peers reject mismatched manifests, and transactions are checked against the active chain. The selected profile is pinned at startup/browser build, never silently adopted from an RPC response.
|
||||
|
||||
## Inspect without launching
|
||||
|
||||
The node entry point accepts `--network-manifest`. With `WIKIDECK_NETWORK=mainnet` set in the process environment, this prints the candidate network/chain/genesis/timestamp and exits **before** opening databases, starting a RandomX engine, listening, or contacting peers. It does not require activation credentials or approval and does not launch anything.
|
||||
|
||||
Browser builds select `VITE_WIKIDECK_NETWORK=mainnet`; server/miner processes select `WIKIDECK_NETWORK=mainnet`. These must match. Docker's `WIKIDECK_NETWORK` **build argument** sets the browser profile; a runtime variable cannot alter an already compiled UI. A mismatched UI rejects the node network instead of signing for it. The mainnet Compose definition supplies both the build and runtime selections.
|
||||
|
||||
## Explicit launch gates
|
||||
|
||||
[compose.mainnet.yaml](../compose.mainnet.yaml) is an opt-in Compose profile, uses a separate named volume, binds only loopback for an external HTTPS reverse proxy, and does **not** auto-restart a failed candidate. It has no default peers, approval, or public origin. It is not started by the default Compose definitions. **No mainnet nodes have been started by this change.**
|
||||
|
||||
Starting the candidate node or native miner requires all of:
|
||||
|
||||
1. `WIKIDECK_MAINNET_LAUNCH` equals the exact candidate chain ID printed by the manifest command.
|
||||
2. `WIKIDECK_MAINNET_REVIEW_ACK=independent-review-complete` records the operator's review attestation. This is **not cryptographic proof of an audit**, and the manifest still honestly reports `audited: false`.
|
||||
3. The candidate genesis timestamp has arrived. If review changes the timestamp or consensus manifest before launch, the chain ID also changes and the old approval is invalidated. Freeze and publish the final manifest only after review.
|
||||
4. An HTTPS `PUBLIC_ORIGIN`, at least two distinct configured HTTPS peer origins, and no private-peer bypass. Configuration count cannot prove the peers are online, independent, or sufficiently distributed; verify that operationally. Existing peer DNS/origin controls still apply.
|
||||
5. `WIKIDECK_PAYMENT_MODE=mock`. Live modes fail closed independently of launch approval.
|
||||
|
||||
Unknown profile names fail closed. A direct import of the HTTP entry point is also guarded. Library-level manifest/consensus/storage inspection remains possible for tests and review; activation gates are accident prevention, not a security boundary against someone who edits the source.
|
||||
|
||||
## Required before an actual production launch
|
||||
|
||||
- **Independent review:** protocol/cryptography, signatures and wallet lifecycle, RandomX integration, difficulty/time/retarget attacks, state commitments, fork choice, network message validation and denial-of-service limits. Publish findings, fixes and a versioned final manifest.
|
||||
- **Security model:** quantify hashpower, chain-rewrite cost and majority attacks. The inherited easy initial target and ten-block retarget are **not production-calibrated**. Choose reviewed launch difficulty/retarget behavior and test start-up/stall/recovery scenarios. Independent mining participation and sufficient hashpower are not provided by running multiple containers on one host.
|
||||
- **Adversarial rehearsal:** sustained multi-host simulations, partitions/eclipses, competing branches, deep reorganizations, clock skew, bad peers, load/mempool saturation, corrupted state and restart recovery. Test the candidate rules with no valuable assets.
|
||||
- **Operations:** independently administered public HTTPS nodes and miners across failure domains, pinned release artifacts and dependencies, firewall/reverse proxy/rate-limit policies, bounded storage and sync strategy, metrics, alerts, rotation and emergency-response procedures.
|
||||
- **Recovery:** verified offline wallet recovery, consistent ledger/market snapshots, full replay/revalidation, documented incident and fork handling. No silent ledger reset or reuse of testnet data.
|
||||
- **Launch governance:** select the actual genesis date, freeze the reviewed identity/configuration, publish binaries and configuration hashes, agree peer/miner readiness and upgrade policy, and explicitly authorize launch. No operator should attest review merely to bypass the gates.
|
||||
- **Economics and legal review:** no monetary value or security is promised. NFT rights do not imply article/image copyright ownership. A real-money custodial market requires a separate risk, custody and payment review.
|
||||
|
||||
## Still not production-ready
|
||||
|
||||
This remains experimental software. Nodes retain the DAG and overlays in memory, rebuild state roots over the full NFT set, and revalidate proofs at startup. The HTTP UI trusts its connected node rather than independently validating the chain. There is no automatic peer discovery, established bootstrap infrastructure, formal finality, independent audit, built-in anti-shill mechanism or production abuse system. The marketplace is node-local, not consensus escrow. Mainnet selection does not remove any of these limitations.
|
||||
|
||||
See [marketplace sandbox and future SHKeeper boundary](marketplace.md) for the mock settlement model and the additional work required before any real XMR can be accepted or paid out.
|
||||
Executable
+86
@@ -0,0 +1,86 @@
|
||||
# Marketplace sandbox
|
||||
|
||||
Open **Marketplace** in the interface. Prices are **USD**; checkout amounts, fees, refunds, and automatic seller payouts are simulated in **XMR**. There is no payable address, payment processor connection, or movement of real Monero in this release. The displayed exchange rate is a deterministic simulation fixture, not a market quote. **Signing delivery transfers the actual card on the selected chain**, even though payment is mocked.
|
||||
|
||||
## Try a sale
|
||||
|
||||
1. Mine enough blocks to own a mature NFT. Open Marketplace → **Sell a card**.
|
||||
2. Choose a card, a fixed price or timed auction, and review the seller fee before signing.
|
||||
3. In a different browser profile/wallet on the **same marketplace node**, buy the fixed-price listing, or bid and wait for the auction to close.
|
||||
4. Open **Your activity** as the buyer, review the order, and choose **Simulate XMR payment**.
|
||||
5. Return as the seller, review the buyer/card/proceeds, and **Sign and confirm** delivery. This creates an ordinary signed NFT transfer; mine it into the canonical chain.
|
||||
6. After the order's required confirmation depth, reconciliation records automatic **mock-paid** seller and additional-fee payouts. The configured market fee is retained in the simulated accounting. No operator payout click is needed.
|
||||
|
||||
Wallet backup/recovery remains local; never send private keys or backup passwords to the node. USD listings do not turn the NFT wallet into a Monero wallet.
|
||||
|
||||
## Sale rules
|
||||
|
||||
- **Fixed price:** stays listed until sold, cancelled, or invalidated by changing ownership/sequence. Checkout exclusively reserves it for 30 minutes; an unpaid reservation expires and the listing reopens if still valid.
|
||||
- **Auction:** one minute to 30 days. Bids must meet the start price and exceed the highest bid by at least one cent. Bids are signed but **unfunded**. Sellers cannot bid on their own auction or cancel after its first bid. This does not prevent alternate-wallet shill bidding or nonpayment.
|
||||
- No bids are accepted at or after the deadline. If there are bids, the listing remains available only for winner checkout until **30 minutes after auction close**, not 30 minutes after checkout. With no bids it expires at closing. An unpaid winner causes expiry; there is no automatic runner-up sale. The seller may relist.
|
||||
- Seller delivery is due **48 hours after mock payment**. Failed delivery can enter **refund-required**. The buyer can simulate a full refund only if the sale transfer is neither pending nor canonical. Pending/late/ambiguous delivery requires review, not an automatic refund that might also release the card.
|
||||
- Listings are **not consensus escrow**: they do not lock cards on-chain. A seller can transfer or trade elsewhere; availability is rechecked when listing, reserving, paying, and reconciling delivery. Payment and NFT delivery are **not an atomic cross-chain exchange**.
|
||||
- Fee basis points are fixed when the seller lists and explicitly reviewed at checkout. The XMR quote, fee, net, and delivery-confirmation requirement are pinned to the order. Changing configuration does not reprice an existing order.
|
||||
- Settlement matches the **exact canonical transfer identity**, not merely the buyer's current holdings. Unconfirmed submission never counts as delivery. A buyer may transfer onward after delivery without confusing its identity.
|
||||
- If a reorganization affects an already settled order, it enters **review** permanently and does not auto-pay again. The operator must investigate; this sandbox has no administrative recovery/payment override endpoint.
|
||||
|
||||
## Configuration
|
||||
|
||||
| Variable | Default | Meaning |
|
||||
| --- | --- | --- |
|
||||
| `WIKIDECK_PAYMENT_MODE` | `mock` | Only accepted value. Other values fail startup, including on the mainnet candidate. |
|
||||
| `WIKIDECK_MARKET_FEE_BPS` | `250` | Seller fee: 250 basis points = 2.5%; integer 0–5000. |
|
||||
| `WIKIDECK_MARKET_CONFIRMATIONS` | `10` | Canonical delivery confirmations before simulated payout; integer 2–1000. No finite depth guarantees PoW finality. |
|
||||
| `WIKIDECK_MOCK_USD_CENTS_PER_XMR` | `15000` | Simulation-only conversion fixture: $150/XMR. Not a live price feed. |
|
||||
|
||||
The single-node and three-node testnet Compose configurations pass these settings. Choose one market host and use its origin consistently. Node marketplaces have different identities and journals: **listing, bid, checkout, and order state are not gossiped**. NFT transfers/blocks are. Buyers and sellers must use the same market host.
|
||||
|
||||
Money is stored as integer USD cents and calculated in integer Monero atomic units (12 decimal places). Gross XMR is rounded up to an atomic unit; each fee is rounded down separately; seller net is exactly gross minus both fees. Maximum listing/bid price is $1,000,000.00.
|
||||
|
||||
## Fixed additional 1% fee
|
||||
|
||||
Every new marketplace sale (fixed price or winning auction) includes a **hardcoded additional 1% seller fee**, on top of the configurable hosting fee. Both fees are calculated independently on the gross sale proceeds, not compounded. At the default 2.5% hosting fee the combined deduction is **3.5%**. Setting the hosting fee to zero does **not** disable the additional 1%.
|
||||
|
||||
The fixed public XMR payout recipient is:
|
||||
|
||||
44xHcCdFhW4b951yBHpkTPdLSJ85qTCnFQ8N7m96TtqqRL3dbhzbEH4fe2SJ3a6ESHcNyzCYH5nYJ9ActR1JtkeA7QYGbQv
|
||||
|
||||
This is a payout destination, **not a buyer checkout address**. Do not send real XMR to it to pay for a sandbox order. No real transfer is submitted; the journal only records a simulated fee allocation and payout after canonical NFT delivery. Both seller and additional-fee payouts enter review if a settled delivery is reorganized. Refunded or expired sales do not pay either recipient. The fee applies to marketplace sales, not free NFT transfers, card-for-card trades, bids or listing creation, which have no XMR sale proceeds.
|
||||
|
||||
The additional fee is rounded down to an atomic unit separately from the hosting fee. Seller net is exactly gross minus **both** fees. For example, a 0.1 XMR sale with 2.5% hosting allocates 0.0025 XMR hosting fee, 0.001 XMR additional fee, and 0.0965 XMR seller net. Rounding below one atomic unit produces zero rather than increasing the charge above 1%.
|
||||
|
||||
The recipient, rate and amount are snapshotted into each new order and disclosed in the UI. The rate and recipient are bound to listing/checkout signatures using marketplace command version 2. Neither is environment-configurable or overridable in a request. **Existing reserved/paid/completed orders are not retroactively repriced.** Old open listings without the additional fee are invalidated and must be relisted with fresh seller authorization; their old bids do not carry over. Old version-1 signed requests are rejected; refresh the browser before signing after an upgrade.
|
||||
|
||||
## API and storage
|
||||
|
||||
- `GET /api/market?offset=0` returns up to 24 public listings, pagination, server clock, fee policy, and market identity.
|
||||
- `POST /api/market/command` accepts a strict, signed command. Actions: `list`, `bid`, `buy`, `cancel`, `mock-pay`, `deliver`, `refund`, `activity`.
|
||||
- Every command binds the network, chain ID, **market instance ID**, actor/public key, UUID nonce, short expiry, action, and all terms. Private activity requires an actor signature and includes only orders involving that actor. Signed requests expire within five minutes; keep clocks synchronized.
|
||||
- Nonce receipts are persisted and replay returns the same result. A different command cannot reuse that nonce. Refresh activity to obtain the latest order state rather than interpreting an old receipt as current state.
|
||||
- Public listings reveal seller/highest bidder wallet addresses and card holdings. Orders reveal counterparties/amounts only to their participants, but the **market operator and its database backups can see all orders**. This is not private Monero trading.
|
||||
- The marketplace journal is stored alongside the ledger in the selected network subdirectory, uses SQLite/WAL and full synchronous commits, and binds its metadata to the active chain. Mutations are serialized. There is one active local listing per card, at most 100 active listings per seller, and 10,000 total listings/orders per journal. Reaching a journal cap fails closed; operator archival work is required, not deleting active records.
|
||||
- HTTP rate limits and bounded mutation queues apply. Read/reconciliation work still scans the bounded journal and chain; this is not a high-volume production market.
|
||||
|
||||
## Recovery and operations
|
||||
|
||||
Back up the ledger, marketplace SQLite databases and their WAL state consistently, plus the independent wallet backups. Prefer a clean node shutdown before copying the data directory; do not copy a live SQLite file without SQLite's backup facilities. Do not delete the journal to clear a stuck order: this loses reservations, invoice identities and idempotency history.
|
||||
|
||||
The service writes delivery intent before submitting to the ledger. A crash between these steps is reconciled by deterministic transfer ID; the seller can resubmit the same delivery if still valid. Background reconciliation runs every 15 seconds, and marketplace commands reconcile before mutation. A closed server does not send payouts or advance its local journal until restarted; deadline enforcement still uses absolute timestamps.
|
||||
|
||||
For **review**, preserve backups and inspect canonical blocks, pending transfers, signed order terms and transfer ID. Do not clear a payout marker, auto-refund, or blindly resubmit a payout. This release intentionally has no real-fund recovery controls.
|
||||
|
||||
## SHKeeper production boundary
|
||||
|
||||
The intended future live processor is **SHKeeper**, using the operator-provided instance at https://shkeeper.eom.dev/. **It is not contacted or configured by this sandbox; there is no live adapter in this release.** Do not supply payment credentials yet. No secret belongs in browser build variables, source, or version-controlled Compose files.
|
||||
|
||||
According to [SHKeeper's API documentation](https://shkeeper.io/api/), creating an XMR invoice uses `POST /api/v1/XMR/payment_request` with a USD amount and an API key, which naturally supports USD listings with an XMR checkout quote. Seller payouts use a separate Basic-authenticated XMR payout endpoint. The merchant wallet receives the gross amount; paying the seller net means the operator temporarily **custodies funds** and retains the market fee. Network fees and any processor fees need an explicit, disclosed policy before enabling this path.
|
||||
|
||||
Live settlement needs a separate implementation and review, **after** a reviewed production network exists:
|
||||
|
||||
- Authoritative server-to-server verification of invoice identity, XMR currency, address, amount, confirmation policy and settled status. Never trust an unsigned callback's `paid` field; treat callbacks only as bounded reconciliation hints.
|
||||
- Stored quote expiry, payment deadlines and explicit rules for late, partial, duplicate and overpayments, seller refusal/non-delivery, and refunds.
|
||||
- Validated seller XMR payout destinations, server-only secret storage, fixed HTTPS processor origin, no redirects, bounded timeouts/responses, and least-privilege credentials.
|
||||
- Durable payout intents and task reconciliation for both seller net and the fixed 1% recipient, including partial success across these separate payouts. The documented payout create endpoint does not expose a merchant idempotency key; a timeout or crash after submission is **ambiguous** and must not trigger blind retry/double payout.
|
||||
- Reorg holds/reserves, operator reconciliation tools, tested backup/restore, dispute/refund procedures, and applicable custody/payment obligations. Confirmation depth alone does not make a small PoW network safe for real money.
|
||||
|
||||
There is deliberately **no environment switch that bypasses these missing protections**.
|
||||
@@ -79,6 +79,8 @@ Sync polls every **5 seconds**, checks network/chain ID, imports at most **32**
|
||||
| --- | --- |
|
||||
| `GET /healthz` | Process health/network, not sync or consensus security. |
|
||||
| `GET /api/state`, `/api/chain` | Canonical blocks, mined/pending transactions, tip/work and peer count. |
|
||||
| `GET /api/network` | Selected profile, pinned chain/genesis, candidate launch status and mock-payment boundary. |
|
||||
| `GET /api/market?offset=0`, `POST /api/market/command` | Node-local mock-payment marketplace; strict signed listing, bid, checkout, delivery and private activity commands. Not consensus escrow. See [marketplace operations](marketplace.md). |
|
||||
| `GET /api/nfts/:id`, `/api/peers` | Canonical NFT owner/sequence/confirmations, article and at-mint statistics; configured peer status. |
|
||||
| `GET /api/decks/:address?offset=0&limit=24` | Public canonical deck for a wallet address at one tip; paged, maximum 24 cards per response. This reveals public address holdings. |
|
||||
| `GET /api/wikipedia/:pageId` | Cached current enrichment for positive English Wikipedia page IDs: categories, views, size, languages and display-only scores. Never a consensus input. |
|
||||
@@ -89,4 +91,6 @@ Sync polls every **5 seconds**, checks network/chain ID, imports at most **32**
|
||||
| `GET /p2p/status`, `/p2p/blocks?offset=0`, `/p2p/mempool` | Manifest/size/tip, 32-block inventory pages, pending transactions. |
|
||||
| `POST /p2p/block`, `/p2p/transaction` | Same validation as local block/transaction submission; transaction endpoint accepts a transfer or atomic trade. |
|
||||
|
||||
POSTs require JSON, enforce supplied browser origins and signatures where applicable; peers without an Origin header are not authenticated by this check. HTTP parsing is capped at 68 KiB; API/P2P rate limits are 300/minute and block/transaction/trade submissions additionally 30/minute. There are no fees, peer authentication or economic spam deterrents. Same-origin browser RPC trusts the node; it does not independently verify these commitments. Deploy no funds: majority-hashpower, eclipse, censorship, reorg and resource-exhaustion risks require independent audits and adversarial testing before any broader launch.
|
||||
POSTs require JSON, enforce supplied browser origins and signatures where applicable; peers without an Origin header are not authenticated by this check. HTTP parsing is capped at 68 KiB; API/P2P rate limits are 300/minute and block/transaction/trade submissions additionally 30/minute. Marketplace commands additionally allow 60/minute. There are no consensus fees, peer authentication or economic spam deterrents; market fees are off-chain simulations only. Same-origin browser RPC trusts the node; it does not independently verify these commitments. Deploy no funds: majority-hashpower, eclipse, censorship, reorg and resource-exhaustion risks require independent audits and adversarial testing before any broader launch.
|
||||
|
||||
Testnet storage and chain identities above remain unchanged. The [gated mainnet candidate](mainnet-launch.md) selects separate chain/signature domains, storage, lock and wallet identities; it is not a running or certified production network and still rejects real payment modes.
|
||||
|
||||
Reference in New Issue
Block a user