RoastWager
A prediction market where the smart contract is the source of truth
RoastWager is a full-stack opinion-and-prediction market dApp on Monad. Users post an opinion, stake tokens on a side, and claim rewards once the market resolves — with the contract holding the truth and an event-driven backend keeping the UI fast and consistent.

The problem
A trustless prediction market has to keep the money and the outcome on-chain, but reading a chain directly from the browser is slow and inconsistent for a social feed. The challenge was to make create → vote → resolve → claim fully on-chain while still delivering an instant, feed-like experience.
What I built
I split the system into three roles: the smart contract is the source of truth, the backend is the synchronization engine, and the frontend owns the user experience. An event-driven listener tails the contract's events on Monad and mirrors them into a database, so the UI reads a consistent API instead of querying the chain on every render.
Architecture
Smart contract
Solidity + FoundrySource of truth. Exposes createWager, vote, resolve, and claim, and emits WagerCreated / Voted / Resolved / Claimed events. Refunds automatically when one side has no bettors or both pools are equal.
Backend listener
Node.js + Hono + viem + SupabaseSynchronization engine. Reads Monad chain events, syncs them into Supabase, and serves a REST API to the frontend. Rate-limited per IP with an auto-reconnecting event listener.
Frontend
Next.js + wagmi + RainbowKitUser experience. Queries the backend API (not the chain) for UI consistency, with optimistic updates so pending posts appear immediately.
Engineering highlights
- IDs are scoped by contract address, so markets stay valid across contract migrations.
- Automatic refunds when a side has no bettors, or when both pools hold equal value.
- Optimistic UI — pending posts show up instantly, before the transaction confirms.
- XP / level system: +10 XP per vote, then +25 XP for winners and +5 XP for losers on resolution.
- Blind markets hide pool details while a market is still active.
Stack
Deployed contract (Monad Testnet): 0x09AcB861808f014673dAED424c1ACa4a9462559E