14 KiB
Executable File
Peer-hosted markets
Before buying or delivering: read Market payments, buyer protections and seller protections for the complete flow, host/author fees, custody model, refund limits, privacy and dispute responsibilities. Today's payments are simulated; NFT delivery is real. The market is not trustless escrow and does not provide guaranteed reimbursement or arbitration.
Every Wikideck peer can host its own market for cards on the shared NFT blockchain. A host can serve collectors broadly or build a community around a particular collection, theme or subject. Card ownership and confirmed transfers follow the shared chain; each host keeps its own listings, bids and order journal. Buyers and sellers must use the same host to complete a sale.
The current market provides fixed-price sales and timed auctions. Running a collection-focused community is possible today, but built-in collection-specific admission, moderation and curation controls are not implemented. Peer-hosted custom trading card games are also planned, not available yet. Operators can adapt the source and presentation subject to licensing; the project still needs a published software license before open-source reuse rights can be claimed. See project direction and licensing.
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.
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.
Try a sale
- Mine enough blocks to own a mature NFT. Open Marketplace → Sell a card.
- Choose a card, a fixed price or timed auction, and review the seller fee before signing.
- 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.
- Open Your activity as the buyer, review the order, and choose Simulate XMR payment.
- 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.
- 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.
Hardcoded 1% project author fee
Every new marketplace sale (fixed price or winning auction) includes a hardcoded 1% project author fee, on top of the configurable fee for the hosting peer's operator. Both fees are calculated independently on 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 author fee.
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=0returns up to 24 public listings, pagination, server clock, fee policy, and market identity.POST /api/market/commandaccepts 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.
Canonical and pending sale delivery is recognized by the agreed seller/buyer/card/sequence even if submitted through the normal transfer endpoint or peer gossip rather than the marketplace command. Direct delivery without a recorded mock payment enters review instead of paying the seller. A refund check cannot cancel a previously signed transfer that arrives later or after a reorganization; this is a production settlement blocker, not a solved atomic-exchange guarantee.
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; no live adapter is enabled. Stage 5 adds an offline wire-contract and durable settlement prototype 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, 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
paidfield; 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.