title: Stripe onboarding (USDCX ledger) + MM admin page
Funding leg: Stripe test-mode checkout → internal USDCX ledger
Cause: Jayverse service #2 — jay's "go ahead with the tasks for these three services";
design doc docs/features/jayverse-onboarding-mm.md in the rabbit repo (§4 onboarding flow,
§6 sketch).
Reasoning: Money enters as a Stripe test payment and lives as an internal ledger credit
(USDCX), never as redeemable crypto — the custody caveat is printed plainly in the UI. Webhook
credit must be idempotent (Stripe redelivers), and the signature must be verified against the
raw body. The order path reuses the existing checkExternalFunds read-and-refuse discipline
rather than inventing a second guard style.
Change: POST /funding/checkout (Checkout Session via raw REST, refuses any non-sk_test_
key by prefix), POST /webhooks/stripe (raw-body HMAC + timestamp tolerance, idempotent credit
keyed by event+session inside the credit transaction), Prisma Balance / LedgerEntry /
StripeEvent models + migration 20260907000000_funding_and_mm_admin, USDCX guard + taker
debit/credit inside the matching transaction in book.ts, redeem crediting in resolve.ts,
web /funding screen (preset chips, custody line, post-return banners, mini ledger) and the
header USDCX chip.
Result: tsc clean in api and web, both builds pass, root pnpm test 63 contract + 6 SDK
green; runtime smoke against the local dev servers (balance/ledger shapes, checkout 503 without
a key — by design, no Stripe keys in env). Known v1 gaps recorded: failed on-chain settlement
does not reverse USDCX trade deltas; resting BUY limits are balance-checked at placement only;
group worst-loss models the Yes side; external-address redeems don't credit USDCX.
MM leg: operator ladder exposure + owner-gated /admin/mm
Cause: Same design doc, §6 "operator / admin page" — the MM is money-moving and always-on, so it needs a window and a switch.
Reasoning: Config splits by risk (jay's standing v1 decision in the doc): pause/resume and
a bounded spread are safe to change live; b and the collateral cap define max loss, so they
stay read-only deploy-time env in v1. Every write is validated server-side and audit-logged —
the page controls, the Authority Auditor later merely reports.
Change: mm-admin.ts (status aggregation: per-market inventory via one balanceOfBatch,
net sold, best quotes, b·ln(n) cap and worst-loss headroom; global treasury/committed/PnL;
audited config writes), kill-switch + spread honored in mm.ts (MAX_SPREAD_BPS = 500),
MmConfig / MmAuditLog models + Market.mmPaused, mm flag on book levels with an "MM" tag
in BookPanel, web /admin/mm (Status + Config tabs, operator #0 gate, confirms on writes),
~65 i18n keys EN/KO.
Result: Same verification run as above. Open for jay: suppress the auto-faucet chain-USDC
for Stripe-funded wallets so USDCX is their only spendable balance? VEREX_WEB_URL must be set
per environment for Checkout return URLs.
Next (tomorrow)
- Run the full Stripe path with real test keys (
stripe listen --forward-to localhost:4000/webhooks/stripe, card 4242…) end to end. - Decide faucet-vs-USDCX coexistence and the failed-settlement compensation hook (gap 1).
- Set
VEREX_WEB_URLper environment; consider the EIP-1271 smart-account order question the rabbit AA build surfaced (needed before an AA bet can actually fill on this exchange).