mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-10-20 07:38:34 +02:00
Hand-authored architecture docs (the 'why'/seams that autodocs can't capture):
- docs/ARCHITECTURE.md index + system map + the 5 pillars + chain profiles + conventions
- docs/CHAT_AND_NOSTR.md ChatProvider seam, bridge vs per-player signing, two-relay
tier model, verifyChatEvent impersonation guard, relay policy
- docs/PAYMENTS.md provider contract + registry, BTCPay/checkout/native, hot path
- docs/RULESETS.md Ruleset data object, win-condition strategies, PvP, MatchRoom seam
- docs/MONETIZATION.md credits, cosmetic_catalog, the four-way unlock rule, premium->tier
Autodocs (reference layer): added a docs:api npm script (jsdoc-to-markdown) that
regenerates docs/API.md from the existing JSDoc. Enable with 'cd src && npm install'
then 'npm run docs:api'. Hybrid by design — auto reference + hand-authored architecture.
No runtime code changed. Suite 56 suites / 407 tests green.
86 lines
4.7 KiB
Markdown
86 lines
4.7 KiB
Markdown
# Payments (P3)
|
|
|
|
The game no longer implements per-chain wallet/daemon code inline. It talks to pluggable **payment
|
|
providers** behind one contract, so an operator routes each chain to whichever backend they run.
|
|
|
|
## The contract
|
|
|
|
`src/payments/providers/paymentProvider.js`:
|
|
|
|
```
|
|
createInvoice({chain, amountAtomic, description, userId, orderId})
|
|
→ {invoiceId, address, uri, amountAtomic, expiresAt, raw}
|
|
getInvoiceStatus(ref) → {status, complete, paidAtomic, confirmations, raw}
|
|
startWatch(ref, onUpdate, intervalMs) / stopWatch(ref)
|
|
sendPayout({chain, address, amountAtomic}) → {txids, raw}
|
|
validateAddress(chain, address) → {valid}
|
|
supportsChain(chain) → bool
|
|
```
|
|
|
|
`PaymentProviderRegistry` routes `chain → providerId` (operator-configurable) with a support-based
|
|
fallback: if the routed provider can't serve a chain, any registered provider that *can* is used.
|
|
|
|
## The providers
|
|
|
|
| Provider | id | Serves | Notes |
|
|
|----------|-----|--------|-------|
|
|
| **BTCPay Greenfield** | `btcpay` | BTC, LTC | `src/payments/providers/btcpayProvider.js` — real BTCPay Server. Invoice priced in the chain's own crypto; address read from the invoice payment-methods; `token` auth. |
|
|
| **xmrcheckout** | `xmrcheckout` | XMR | Same class, different endpoint — the checkout app exposes a **BTCPay-Greenfield-compatible** shim. |
|
|
| **wowcheckout** | `wowcheckout` | WOW | Ditto (matched pair to xmrcheckout). |
|
|
| **Native Monero** | `native-monero` | XMR, WOW | `src/payments/providers/nativeMoneroProvider.js` — wraps the existing `walletRPCService` (subaddress invoicing + `transfer_split` payouts). |
|
|
|
|
The key discovery: **BTCPay, xmrcheckout, and wowcheckout all speak one Greenfield contract**, so a single
|
|
`BTCPayProvider` class (constructor-configurable `id`) serves all three — just registered at different
|
|
endpoints. See the `btcpay-infra-topology` note for the operator's LAN endpoints.
|
|
|
|
## Bootstrap & routing
|
|
|
|
`buildProviderRegistry({env, walletService})` (`src/payments/providers/index.js`) is the single wiring seam:
|
|
|
|
- Native Monero/Wownero provider registers whenever a `walletService` exists.
|
|
- Each Greenfield gateway activates from its own env trio:
|
|
`BTCPAY_URL/_STORE_ID/_API_KEY` (chains from `BTCPAY_CHAINS`, default BTC,LTC),
|
|
`XMRCHECKOUT_URL/_STORE_ID/_API_KEY` (XMR), `WOWCHECKOUT_URL/_STORE_ID/_API_KEY` (WOW).
|
|
- Default routing: BTC/LTC → btcpay, XMR/WOW → their checkout gateway (else native). `PAYMENT_ROUTING`
|
|
(`CHAIN:provider,…` or JSON) overrides any mapping.
|
|
|
|
**Behavior-preserving:** with no gateway env set (prod today), only the native provider registers and
|
|
*every* chain routes to it — byte-for-byte the legacy flow.
|
|
|
|
## The hot path
|
|
|
|
- **Invoice creation** — `gameModeManager.createPaymentRequest` calls `getProvider(cryptoType).createInvoice(...)`.
|
|
The native provider delegates to the same `walletService.createPaymentRequest`, so the subaddress and
|
|
monitoring maps are identical to before.
|
|
- **Monitoring** — `network/paymentHandlers._monitorAddress` calls `provider.startWatch`. Native passes the
|
|
raw wallet status straight through (legacy path unchanged); `BTCPayProvider.getWalletStatus` maps a
|
|
Greenfield invoice to the same raw shape (`Settled → confirmed+complete`, `Processing → in_mempool`,
|
|
paid/required amounts from payment-methods via `ChainProfile` decimals). The confirmation logic is
|
|
extracted to `_handlePaymentStatus`, shared by native + gateway.
|
|
- **Payouts** stay native (the checkout apps are receive-only; XMR/WOW payouts remain on wallet-RPC).
|
|
|
|
## Turning a gateway on
|
|
|
|
1. Mint a store API key in the gateway's admin (money infra — a human step).
|
|
2. Set the `*_URL/_STORE_ID/_API_KEY` env on the deploy host, using an address the host can actually reach
|
|
(verify LAN reachability; a nebula/overlay IP may not route).
|
|
3. Restart. Invoices for that chain now create + confirm through the gateway; no code redeploy.
|
|
|
|
## Money math
|
|
|
|
All amounts are **atomic BigInt**, decimals-parameterized via `src/money/atomic.js` (`format`, `add`,
|
|
`mulByDecimal`, …) and `src/chain/chainProfile.js` (`decimalsFor`, `atomicDivisor`). Never floats. WOW = 11
|
|
decimals, XMR/BTC/LTC per their chain, GRIN = 9.
|
|
|
|
## Files
|
|
|
|
```
|
|
src/payments/providers/paymentProvider.js contract + registry
|
|
src/payments/providers/btcpayProvider.js Greenfield client (btcpay / xmrcheckout / wowcheckout)
|
|
src/payments/providers/nativeMoneroProvider.js wraps walletRPCService
|
|
src/payments/providers/index.js buildProviderRegistry (env → registry)
|
|
src/payments/walletRPCService.js Monero/Wownero wallet-RPC
|
|
src/game/gameModeManager.js createPaymentRequest (invoice seam)
|
|
src/network/paymentHandlers.js _monitorAddress / _handlePaymentStatus (monitoring seam)
|
|
```
|