This commit is contained in:
2026-10-20 13:00:08 -04:00
parent a1de67ea14
commit bcd8630a8e
18 changed files with 483 additions and 172 deletions
+12 -11
View File
@@ -8,13 +8,13 @@ The current market provides fixed-price sales and timed auctions. Running a coll
## Cryptocurrency payments and the two sale fees
The intended settlement currency is **Monero (XMR)**, with USD-priced listings and an XMR amount quoted at checkout. Mining and payments are separate: RandomX secures Wikideck's own blockchain, while XMR payments would settle on Monero.
New marketplace terms use **native XMR prices** represented exactly in atomic units (12 decimal places). There is no USD conversion, exchange-rate field or live payment route. Historical version-2 USD orders remain in their original currency and signatures; USD listings are read-only until the seller closes them and signs a fresh XMR listing. Mining and payments are separate: RandomX secures Wikideck's own blockchain, while any future XMR settlement would use Monero.
Each sale allocates a configurable hosting fee to the peer's market operator (default **2.5%**) plus a hardcoded **1% author fee** to the project author's fixed XMR address. Both are deducted from the seller's gross proceeds, not compounded or secretly added to the buyer price. At the default rates the seller keeps 96.5% before any future disclosed processor/network-fee policy. The host retains the hosting allocation; the author allocation is a separate payout. **All allocations and payouts are currently simulated.**
## Current testnet 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.
Open **Marketplace** in the interface. New prices and checkout amounts are **XMR-native**; fees, refunds, and automatic seller payouts are simulated. Historical USD orders are explicitly labeled. There is no payable address, payment processor connection, or movement of real Monero in this release. No exchange rate is applied. **Signing delivery transfers the actual card on the selected chain**, even though payment is mocked.
## Try a sale
@@ -25,12 +25,12 @@ Open **Marketplace** in the interface. Prices are **USD**; checkout amounts, fee
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.
Wallet backup/recovery remains local; never send private keys or backup passwords to the node. A Wikideck NFT wallet is not 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.
- **Auction:** one minute to 30 days in the sandbox. Bids must meet the start price and exceed the highest bid by at least one atomic unit. 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. Live auctions remain a separate unreleased gate.
- 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**.
@@ -38,6 +38,8 @@ Wallet backup/recovery remains local; never send private keys or backup password
- 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.
New sale prices use canonical atomic-unit strings and integer arithmetic; JSON/signature payloads never use floating-point XMR. Each fee rounds down independently; seller net is gross minus both allocations. No economic listing minimum is imposed. Historical USD records retain original cents and are never converted or repriced.
## Configuration
| Variable | Default | Meaning |
@@ -45,11 +47,10 @@ Wallet backup/recovery remains local; never send private keys or backup password
| `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.
The single-node and three-node testnet Compose configurations pass these hosting-fee and delivery-confirmation 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.
New listings, bids, and checkout store native XMR atomic-unit amounts (12 decimal places); they are not derived from fiat. Historical v2 records retain USD cents and their originally snapshotted mock XMR amounts. The application bound on newly entered atomic gross is documented in the [amount domain specification](xmr-domain.md); it is not a wallet-balance or exposure approval.
## Hardcoded 1% project author fee
@@ -63,13 +64,13 @@ This is a payout destination, **not a buyer checkout address**. Do not send real
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.
The recipient and percentage are snapshotted into each new order and disclosed in the UI. They are bound to v3 listing/checkout signatures and are neither environment-configurable nor request-overridable. **Existing reserved/paid/completed v2 orders are not retroactively repriced.** Open USD listings remain read-only until eligible sellers close them and relist with fresh v3 XMR authorization; historical bids are not converted. The v2 domain remains for compatibility with historical orders and receipts; new USD listings, bids, and checkout are rejected.
## 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.
- `POST /api/market/command` accepts strict, signed commands. New XMR terms use `market-command-v3`; historical `market-command-v2` is retained only to service existing orders and eligible seller cancellation. Actions include `list`, `bid`, `buy`, `cancel`, `retire-legacy-listing`, `mock-pay`, `deliver`, `refund`, and `activity` under their allowed version.
- Every command binds the network, chain ID, **market instance ID**, actor/public key, UUID nonce, short expiry, action, and all versioned terms. New prices sign the currency and canonical atomic XMR gross. Private activity requires a wallet 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.
@@ -89,7 +90,7 @@ For **review**, preserve backups and inspect canonical blocks, pending transfers
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; no live adapter is enabled.** Stage 5 adds an [offline wire-contract and durable settlement prototype](shkeeper-settlement.md) with fake-transport tests, separate from the running marketplace. Its live factory always refuses activation. 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.
The offline SHKeeper harness still models the provider's documented USD-denominated invoice input. It is disconnected from the native-XMR market and therefore is **not currently compatible with exact XMR-native pricing**. Do not hide a USD conversion behind an XMR price. Seller payouts use a separate Basic-authenticated XMR payout endpoint; the merchant wallet would receive gross funds and the operator would temporarily **custody funds**. Native-XMR invoice capability and settlement architecture remain unverified; no processor path is selected or enabled.
Live settlement needs a separate implementation and review, **after** a reviewed production network exists: