Skip to content

Latest commit

 

History

18 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

Mini Prediction Market (LMSR)

Single hardcoded binary market on Hanson's LMSR. In-memory, no DB/blockchain/auth.

  • Backend: Node.js + NestJS
  • Frontend: React + TypeScript + Vite + Tailwind + shadcn/ui

Run

# Terminal 1
cd backend && npm install && npm run start:dev   # http://localhost:3000

# Terminal 2
cd frontend && npm install && npm run dev        # http://localhost:5173

Open http://localhost:5173 (Vite proxies /api/* to the backend, no CORS setup needed).

Tests: cd backend && npm test (pricing module — golden vector, invariants, overflow, path-independence).

AMM / rounding decisions & trade-offs

  • Cost function uses log-sum-exp; spot price uses the stable sigmoid form — both avoid overflow at large q.
  • priceImpact isn't defined in the brief — used (avgPrice - spotPriceBefore) / spotPriceBefore.
  • API casing matches the brief literally: snake_case for GET /market (q_yes, p_yes), camelCase for /quote (avgPrice). Internal code is camelCase everywhere; only the response boundary maps.
  • Shares can be fractional (LMSR is continuous), capped at 2 decimals, validated on both ends.
  • No explicit lock on trade() — it's fully synchronous with no await in the critical section, so JS already prevents interleaving here; would need one if persistence/async I/O were added later.
  • Sell (bonus) reuses /quote and /trade via an optional side: 'BUY'|'SELL' field (negative delta), not a separate endpoint.
  • Resolve/redeem (bonus): resolve is one-time (OPEN → RESOLVED) and blocks further trading; redeem pays out winning-side holdings at $1/share into collateral and zeroes both sides (losing shares become worthless). redeem is naturally idempotent — a second call pays out $0 since holdings are already zero.

With more time

  • Move shared market/portfolio state into a Zustand store instead of prop-drilling through App.tsx, so mutations (trade/resolve/redeem) can trigger a refetch from anywhere without threading callbacks down the tree.
  • Playwright e2e for the quote → confirm → portfolio flow.
  • Price-history chart.

Assumptions

  • Single demo user; state resets on server restart (as allowed by the brief).
  • b = 100 fixed, not configurable.

About

Mini Polymarket-style prediction market on Hanson's LMSR — NestJS backend, React/TypeScript/Tailwind/shadcn-ui frontend

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages