← Prediction Game · Prompt Deck · Pictures
How do you prove a settlement stack works? Ship a game that uses every piece.
Intent Contract
Agent autonomy boundary. Not parsed by engineering — governance instrument for humans and agents.
| Dimension | Statement |
|---|
| Objective | Prove the Sui settlement stack works by shipping a prediction game where every capability an agent needs — atomic settlement, gasless onboarding, oracle data, owned assets — executes in a single product. |
| Outcomes | 1. 50+ predictions settled atomically on testnet in 30 days. 2. Zero users required to install a wallet extension. 3. Settlement completes in single PTB. |
| Health Metrics | Existing Supabase services must not degrade. Oracle uptime >95%. Sponsored tx success rate >99%. |
| Constraints | Hard: Testnet only for V1. Steering: Rugby fixtures first, other sports later. Budget: <$50/month infrastructure on testnet. |
| Autonomy | Allowed: UI layout, component choice, Move module internal structure. Escalate: Oracle data source selection, mainnet migration. Never: Mainnet deployment without audit, real-money staking without legal review. |
| Stop Rules | Complete when: all Build Contract rows at Live + 50 predictions settled. Halt when: PTB settlement requires >1 tx, or zero predictions after 30 days. |
| Counter-metrics | Oracle must not become a single point of failure — if one operator goes offline, settlement must continue via fallback. Sponsored transactions must not create unbounded liability — cap per-user daily gas spend. |
| Blast Radius | New Move packages on testnet. New Next.js app in NX monorepo. New NX libs for Sui integration. Does NOT touch existing apps, Supabase, or Convex services. |
| Rollback | Testnet contracts are disposable — redeploy to rollback. Frontend is a new app — delete the app to rollback. No shared state at risk. |
Story Contract
Stories are test contracts. Each row converts to test files. Tests must be RED before implementation starts. Tests going GREEN = value delivered.
Every story follows the P2P arc: Pain (who hurts, measurable cost) → Performance Target (the number that proves it works) → Validated Outcome (the Tight Five dimension this serves).
| # | WHEN (Trigger + Precondition) | THEN (Exact Assertion) | ARTIFACT | Test Type | FORBIDDEN (Must not happen) | OUTCOME (Performance Number) |
|---|
| S1 | User navigates to /predictions with 5+ fixtures in GameRegistry where status == upcoming and clock < kickoff_epoch | Page renders fixture cards showing: team names, kickoff time (local TZ), current pool totals per outcome. Cards sorted by kickoff ascending. No wallet connection required. | BLOCKER — test path TBD by engineering | e2e | Page requires wallet connection to view fixtures. Fixtures with status != upcoming appear in the list. Pool totals show stale data (>30s old). | Browse 5+ matches in <3s vs current method of checking multiple betting sites at ~60s per match |
| S2 | User clicks "Predict" on a fixture, authenticates via zkLogin (Google OAuth), selects outcome (home/draw/away), confirms stake amount | Single sponsored PTB executes: create Prediction object (owned by user), transfer stake to fixture pool, update pool totals. Prediction.status == pending. Receipt NFT minted with Dynamic Display showing "Pending." No wallet extension installed. | BLOCKER — test path TBD by engineering | e2e + integration | User prompted to install wallet extension. PTB fails silently — UI shows success but no on-chain object created. Stake deducted but Prediction object not created (partial execution). User charged gas. | Predict in <30s with 0 gas decisions vs EVM flow requiring wallet install + 2 gas approvals at ~3 min total |
| S3 | Oracle agent posts match result for a fixture with 10+ predictions across all three outcome pools | settle_fixture() PTB consumes hot potato OracleResult, calculates proportional payouts, updates all Prediction objects to won/lost, transfers winnings to winners, updates receipt NFT Display to show final status. Single PTB. | BLOCKER — test path TBD by engineering | integration | Settlement requires >1 transaction. OracleResult persists after settlement (hot potato violated). Any Prediction object remains in pending status after settlement. Losers receive payout. Winners receive less than proportional share. | Settle entire fixture in <1s in 1 PTB vs EVM requiring per-user claim transactions at ~15-60s each |
| S4 | User navigates to /predictions/mine with 3+ settled predictions (mix of won and lost) | Page shows prediction cards with: fixture name, predicted outcome, actual result, stake amount, payout (if won), receipt NFT link. Cards sorted by settlement time descending. Won/lost visually distinct. | BLOCKER — test path TBD by engineering | e2e | Page shows predictions from other users. Won predictions show $0 payout. Lost predictions show a payout amount. Pending predictions mixed with settled without clear status indicator. | Track record visible in <5s vs no on-chain history on existing platforms |
| S5 | Oracle agent attempts to post conflicting results for the same fixture (result already submitted) OR oracle agent is offline when settlement window opens | Duplicate submission: Move module rejects with EAlreadySettled error. Oracle offline: Admin can trigger manual settlement after timeout period. Fixture status transitions: upcoming → live → settling → settled. No intermediate state allows double-settlement. | BLOCKER — test path TBD by engineering | integration | Double settlement succeeds — fixture pays out twice. Fixture stuck in live forever with no admin override path. Oracle posts result before clock >= kickoff_epoch (clock guard violated). | Zero double-settlements and zero stuck fixtures vs historical oracle bugs causing fund loss |
Tight Five coverage check:
| P Dimension | Stories | Gap? |
|---|
| Pain (multi-tx EVM settlement) | S2 (single PTB predict), S3 (single PTB settle) | No |
| Demand (rugby fans, crypto-curious) | S1 (browse without wallet), S4 (track record) | No |
| Edge (Move type system, PTB composition) | S3 (hot potato oracle), S5 (compiler-enforced safety) | No |
| Trend (onchain gaming, gasless UX) | S2 (zkLogin + sponsored tx) | No |
| Conversion (dogfood proof) | S1 (frictionless browse), S2 (frictionless predict) | No |
Build Contract
The deliverable. Engineering builds from this. Commissioning reads this.
Job 1: Find and Pick
| # | FeatureID | Function | Artifact | Success Test | Safety Test | Regression Test | Value | State |
|---|
| 1 | WCAP-007 | Browse upcoming fixtures | Match list page with fixture cards | Page loads <2s, shows 5+ fixtures sorted by kickoff | No wallet required to view | Existing app routes unaffected | See what's available without commitment | Gap |
| 2 | WCAP-007 | Filter fixtures by competition/date | Filter controls on match list | Filters reduce list correctly, URL params persist | Filter state doesn't leak between sessions | N/A — new page | Find the match you care about | Gap |
| 3 | WCAP-008 | View fixture detail with pool totals | Match detail page | Shows teams, odds, pool distribution, prediction count | Pool totals refresh without full page reload | N/A — new page | Understand the market before committing | Gap |
| 4 | WCAP-008 | Place prediction on fixture outcome | Prediction form + confirmation | Prediction object created on-chain, receipt minted | Cannot predict after kickoff (clock guard) | N/A — new module | Back your conviction with a stake | Gap |
Job 2: Settle Atomically
| # | FeatureID | Function | Artifact | Success Test | Safety Test | Regression Test | Value | State |
|---|
| 5 | WCAP-019 | Oracle posts match result | oracle.move + agent script | OracleResult created as hot potato, consumed in same PTB | Duplicate results rejected (EAlreadySettled) | N/A — new module | Bring real-world truth on-chain | Gap |
| 6 | WCAP-019 | Settle fixture atomically | treasury.move settlement PTB | Single PTB: consume oracle result + calculate payouts + distribute | Hot potato enforces atomic consumption. No partial settlement. | N/A — new module | Prove atomic settlement works | Gap |
| 7 | WCAP-020 | Calculate proportional payouts | treasury.move payout math | Winners receive (user_stake / winning_pool) * total_pool | Sum of payouts <= total pool (no inflation). Zero-winner edge case handled. | N/A — new module | Fair distribution without intermediary | Gap |
| 8 | WCAP-019 | Update prediction status post-settlement | prediction.move state transition | All predictions transition from pending to won/lost | No prediction remains pending after fixture settled | N/A — new module | Know your result immediately | Gap |
| 9 | WCAP-020 | Update receipt NFT display | Dynamic Display update | Receipt shows current status (pending/won/lost/claimed) | Display template resolves from object state, not cached | N/A — new module | Proof of prediction that evolves | Gap |
Job 3: Track Record
| # | FeatureID | Function | Artifact | Success Test | Safety Test | Regression Test | Value | State |
|---|
| 10 | WCAP-011 | View my predictions | My predictions page | Shows all user predictions with status, stake, payout | Only shows predictions owned by authenticated user | N/A — new page | See your track record | Gap |
| 11 | WCAP-011 | View prediction receipt NFT | Receipt detail view | Shows full prediction metadata: fixture, outcome, stake, result, payout | Receipt object ownership verified before display | N/A — new page | Prove your conviction | Gap |
| 12 | WCAP-011 | Leaderboard by season | Leaderboard page | Ranked by win rate with minimum prediction count | No PII exposed — address or SuiNS only | N/A — new page | Compete on conviction quality | Gap |
| 13 | WCAP-011 | Season stats and trends | Stats dashboard | Win rate, total staked, total won, streak | Stats computed from on-chain data, not cached | N/A — new page | Understand your prediction patterns | Gap |
Job 4: Onboard Frictionlessly
| # | FeatureID | Function | Artifact | Success Test | Safety Test | Regression Test | Value | State |
|---|
| 14 | WCAP-008 | Authenticate via zkLogin | zkLogin integration | User signs in with Google/Apple, gets Sui address | OAuth token never stored on-chain. ZKP salt managed securely. | Existing auth flows unaffected | No seed phrase, no wallet install | Gap |
| 15 | WCAP-007 | Sponsor user transactions | Gas station backend | All user PTBs gas-free. Platform co-signs. | Per-user daily gas cap enforced. Balance alerts at 50%. | N/A — new service | Zero gas decisions | Gap |
| 16 | WCAP-008 | First-time user flow | Onboarding screens | New user: browse → pick → authenticate → predict in <60s | No step requires prior crypto knowledge | N/A — new flow | Convert curious to committed | Gap |
| 17 | WCAP-007 | Wallet extension fallback | dApp Kit wallet connect | Users with existing Sui wallets can connect directly | Wallet adapter handles all Sui wallets uniformly | N/A — new integration | Support power users | Gap |
| 18 | WCAP-019 | Admin override for oracle failure | admin.move + admin UI | Admin can trigger manual settlement after timeout | Admin actions require AdminCap — no unauthorized settlement | N/A — new module | System never gets stuck | Gap |
Screen Contracts
One contract per screen. Each screen is the atomic execution and test unit.
Screen: Match List (/predictions)
Serves: S1, Build Contract #1, #2
Flow and States
| Dimension | Spec |
|---|
| Route | /predictions |
| Entry from | Sidebar "Predictions" link, homepage CTA |
| Success | Page renders fixture cards within 2s |
| Error | Empty state with "No upcoming fixtures" message + retry |
| Auth denied | N/A — page is public, no auth required |
| Loading | Skeleton cards (3 placeholder cards with shimmer) |
| Empty | "No upcoming fixtures right now. Check back before the weekend." + link to past results |
| Disabled | N/A — read-only page |
Elements
| Element | Selector | States |
|---|
| Fixture card | role="article", name={fixtureName} | upcoming, live, settled |
| Competition filter | role="combobox", label="Competition" | default (all), selected |
| Date filter | role="group", label="Date range" | default (upcoming), custom range |
| Pool total badge | role="status" | loading, loaded |
| Predict button | role="link", name="Predict" | enabled (upcoming), disabled (live/settled) |
Serves: S2, Build Contract #3, #4
Flow and States
| Dimension | Spec |
|---|
| Route | /predictions/{matchId}/predict |
| Entry from | "Predict" button on fixture card |
| Success | Prediction confirmed → redirect to /predictions/mine with success toast |
| Error | Same page + revert + error toast with specific message |
| Auth denied | Redirect to zkLogin flow, return to form after auth |
| Loading | Submit button shows spinner, form inputs disabled |
| Empty | N/A — fixture data required to render |
| Disabled | Submit button disabled during PTB execution, all inputs locked |
Elements
| Element | Selector | States |
|---|
| Fixture header | role="heading", name={fixtureName} | loaded |
| Outcome selector | role="radiogroup", label="Your prediction" | unselected, home, draw, away |
| Stake input | role="spinbutton", label="Stake amount" | empty, valid, error (below minimum) |
| Pool distribution | role="meter", name={outcome} | loading, loaded (shows % split) |
| Submit button | role="button", name="Place Prediction" | enabled, loading, disabled |
| Auth prompt | role="dialog", label="Sign in to predict" | hidden, visible |
Screen: My Predictions (/predictions/mine)
Serves: S4, Build Contract #10, #11
Flow and States
| Dimension | Spec |
|---|
| Route | /predictions/mine |
| Entry from | Sidebar "My Predictions" link, post-prediction redirect |
| Success | Page renders prediction cards sorted by settlement time desc |
| Error | Error toast + retry button |
| Auth denied | Redirect to zkLogin flow |
| Loading | Skeleton cards with shimmer |
| Empty | "No predictions yet. Browse upcoming matches to get started." + link to /predictions |
| Disabled | N/A — read-only page |
Elements
| Element | Selector | States |
|---|
| Prediction card | role="article", name={fixtureName} | pending, won, lost, claimed |
| Status badge | role="status" | pending (amber), won (green), lost (red), claimed (blue) |
| Payout amount | testid="payout-{predictionId}" | hidden (lost/pending), visible (won/claimed) |
| Receipt link | role="link", name="View Receipt" | enabled |
| Stats summary | role="region", label="Your Stats" | loading, loaded |
Screen: Match Detail (/predictions/{matchId})
Serves: S1, S3, Build Contract #3, #9
Flow and States
| Dimension | Spec |
|---|
| Route | /predictions/{matchId} |
| Entry from | Fixture card click on match list |
| Success | Page renders fixture detail with pool distribution and prediction list |
| Error | "Fixture not found" with link back to match list |
| Auth denied | N/A — page is public |
| Loading | Skeleton layout with header + pool chart placeholder |
| Empty | Fixture exists but zero predictions — show pool at 0 with "Be the first to predict" CTA |
| Disabled | Predict button disabled if fixture is live or settled |
Elements
| Element | Selector | States |
|---|
| Fixture header | role="heading", name={fixtureName} | upcoming, live, settled |
| Pool chart | role="img", label="Pool distribution" | loading, loaded, empty |
| Prediction list | role="list", label="Recent predictions" | loading, loaded, empty |
| Result banner | role="alert" | hidden (upcoming/live), visible (settled) |
| Predict CTA | role="link", name="Make Your Prediction" | enabled (upcoming), hidden (live/settled) |
Navigation Architecture
How does the user move from pain to effortless performance?
| Stage | User State | Navigation Must Do | Current State | Target State |
|---|
| Pain | Prediction = multiple sites, multiple transactions, gas confusion | Show the cost of the current path | No on-chain prediction product | Match list visible without auth |
| Awareness | There's a simpler way to predict | Surface the new entry without disrupting existing flow | N/A — new product | "Predictions" in sidebar, homepage CTA |
| First Value | That was genuinely fast | Deliver one complete prediction immediately | N/A | zkLogin → predict → confirm in <30s |
| Habit | I check before every match | Make predictions the natural pre-match routine | N/A | Push notification before kickoff (future) |
| Mastery | I track my conviction quality | Support power-user shortcuts | N/A | Leaderboard, season stats, export |
| Effortless | The game suggests what I'd pick | Proactive suggestions based on history | N/A | AI-assisted prediction (future) |
Navigation States (Feature Flag Controlled)
| State | Sidebar | Dashboard | Section Pages | Widget |
|---|
| Flag OFF | Existing nav unchanged | No prediction widgets | No cross-links | Hidden |
| Flag ON (T0) | "Predictions" added after existing sections | Upcoming matches card | N/A | Hidden |
| Flag ON (T2+) | Same | Same + win streak widget | Cross-links to prediction history | Match reminder floating button |
Cross-Cutting Navigation
| From | To | Trigger | What Happens |
|---|
| Homepage | /predictions | "Predictions" sidebar link or hero CTA | Navigate to match list |
| Match list | /predictions/{matchId} | Click fixture card | Navigate to match detail |
| Match detail | /predictions/{matchId}/predict | Click "Predict" button | Navigate to prediction form (auth check) |
| Prediction form | /predictions/mine | Successful prediction | Redirect with success toast |
| My predictions | /predictions/{matchId} | Click fixture name on prediction card | Navigate to match detail |
| Any page | zkLogin flow | Any authenticated action when not signed in | Modal overlay, return to origin after auth |
Predictions (new section)
├── Upcoming Matches → /predictions
├── My Predictions → /predictions/mine
└── Leaderboard → /predictions/leaderboard
Positioned after existing product sections. Rationale: prediction game is a new product vertical, not a sub-feature of existing tools.
Priority Score
| Dimension | Score | Evidence |
|---|
| Pain | 4 | Multi-transaction settlement on EVM requires 4-5 txs, wallet install, gas management. Real friction measured in the value stream map. |
| Demand | 3 | Rugby community is niche but passionate. Crypto prediction market demand proven (Polymarket $1B+ volume). No Sui-native prediction product exists. |
| Edge | 5 | PTB atomic settlement, hot potato oracle pattern, Move type safety — none available on EVM. Compiler prevents the bugs competitors write. |
| Trend | 5 | Onchain gaming growing. Gasless UX becoming table stakes. Google chose Sui for agent commerce. zkLogin adoption accelerating. |
| Conversion | 3 | Testnet dogfood with rugby community. No revenue model yet. Conversion thesis: frictionless UX converts crypto-curious sports fans. |
| Composite | 900 | 4 × 3 × 5 × 5 × 3 |
Quality Targets
| Metric | Target | Method |
|---|
| Prediction-to-settlement time | <1s (single PTB) | On-chain transaction timing |
| First prediction time (new user) | <60s from landing | Session recording |
| Oracle data freshness | <5 min after match end | Oracle agent monitoring |
| Sponsored tx success rate | >99% | Gas station metrics |
Kill Signal
Zero predictions on testnet after 30 days of deployment, OR PTB settlement requires >1 transaction. Either means the thesis is wrong for this use case.
Current State
| Layer | What Exists | What's Needed |
|---|
| Move contracts | 14 packages deployed to testnet (DePIN, identity, mandate) | New prediction_game package (7 modules) |
| Frontend | Next.js 15 app with dApp Kit | New prediction app in NX monorepo |
| Oracle | None | Custom agent-operated oracle + integration |
| Gas station | None | Sponsored transaction backend |
| zkLogin | None deployed | zkLogin integration in new app |
Build Ratio
| Category | Existing | New | Ratio |
|---|
| Move patterns | 14 packages, 2,500+ lines | 7 modules, ~1,500 lines | 60% reuse of patterns |
| Frontend | dApp Kit, shadcn, Tailwind | 4 new pages, prediction components | 70% reuse of stack |
| Infrastructure | Testnet deployment, CI | Gas station, oracle agent | 30% new |
Process
Build Order
| Sprint | Features | What | Effort | Acceptance |
|---|
| 1 | #1-4, #14, #15 | Core contracts + zkLogin + sponsored tx | 2 weeks | Prediction created on testnet via zkLogin |
| 2 | #5-9 | Oracle + settlement + receipts | 2 weeks | Full settlement cycle in single PTB |
| 3 | #10-13, #16-17 | Frontend polish + history + onboarding | 1 week | Complete user journey from browse to settle |
| 4 | #18, #12 | Admin tools + leaderboard + dogfood | 1 week | 50 predictions from real users |
Commissioning
| Gate | What | Evidence Required |
|---|
| L0 | Spec exists | This document |
| L1 | Core contracts deployed | game.move, prediction.move, treasury.move on testnet |
| L2 | Settlement works | Full predict → settle → payout cycle in single PTB |
| L3 | Dogfood passed | 50+ predictions from real users, zero double-settlements |
| L4 | Production ready | Mainnet audit passed, monitoring live, gas station funded |
Players
Demand-Side Jobs
| Who | Job | Current Solution | Switching Trigger |
|---|
| Rugby fan (crypto-curious) | Back my convictions on match outcomes | Informal bets with friends, traditional bookmakers | Zero-friction entry (no wallet, no gas, no KYC) |
| Crypto native | Prove prediction skill with on-chain record | Polymarket (EVM), no Sui-native option | Sui-native UX, atomic settlement, Dynamic NFT receipts |
| Builder (dogfood) | Validate Sui settlement patterns for other products | No working reference implementation | Working prediction game proves PTB, zkLogin, oracle patterns |
Roles
| Role | Responsibility |
|---|
| Product (Dream) | PRD spec, stories, acceptance criteria |
| Engineering | Move contracts, frontend, oracle agent |
| Oracle operator | Match data feed, result attestation |
| Admin | Manual settlement override, season management |
| Dogfood users | Real predictions on testnet, feedback |
Context
- Onchain JTBD — WCAP-007, WCAP-008, WCAP-011, WCAP-019, WCAP-020
- Sui Patterns — Hot potato, Dynamic Display, clock guard, pool accounting
- Sui Standards — Display, sponsored txs, kiosk
- Sui Protocols — Oracle + Settlement layers
- Sui Business Development — Strategic context, 5Ps analysis
- Outcome Map — Binary success measures
- Value Stream Map — EVM vs Sui compression
- Dependency Map — Critical path and risks
Questions
If the prediction game proves the settlement stack works, what's the next product that inherits the patterns — and which patterns don't transfer?
- Is rugby the right sport for dogfood, or does the niche community limit what we learn about onboarding?
- The hot potato oracle pattern prevents double-settlement — but what happens when the oracle is wrong, not malicious?
- If zkLogin eliminates seed phrases, what new trust assumption replaces them — and is it actually better?