Zero-Knowledge Card Dueling on Midnight Network
The first provably fair card game where neither player — nor the server — ever sees your hand.
| 🌐 Live App | shadow-arena-game.vercel.app |
| 🎬 Demo Video | Watch the ShadowArena MVP Demo |
| 🐦 X (Twitter) | @shadowarenaweb3 |
| 📊 Pitch Deck | Product Slide Deck |
- The Problem
- The Solution
- Live Deployment
- September 2026 — What's New
- Architecture
- Smart Contracts
- ZK Privacy Model
- User Workflow
- File Structure
- CI / CD
- Setup & Run Locally
- Testing
- Feedback & Iterations
- Level 6 Users
- Screenshots
- Roadmap
In every traditional online card game — Web2 or Web3 — the server knows your hidden cards. This fundamental design flaw enables:
- God-mode cheating by server administrators
- MEV front-running by block validators who can inspect pending transactions
- Zero verifiability — players must simply trust the platform
Standard blockchain smart contracts make this worse, not better: all state is public on-chain, meaning your "hidden" card is visible to anyone who reads the chain.
ShadowArena uses Midnight Network's Zero-Knowledge cryptography to eliminate the need for trust entirely.
Instead of sending your card to a server, you generate a ZK proof of your card locally in your browser using the 1AM Wallet. The Midnight smart contract evaluates the winner mathematically in the dark — the outcome is cryptographically guaranteed without any central authority ever seeing the raw card values.
No server. No trust. No way to cheat.
| Resource | Link |
|---|---|
| 🌐 Web App | Deployed on Vercel (Midnight Preprod Network) |
| 📜 Smart Contract | f6a07f0a59838dba800c2e0fe75b6ea4784b94f3ca6e7cbdf2901453148b88b4 |
| 🔗 Player 1 Join | b92423bc... |
| 🔗 Player 2 Join | 5715e670... |
| 🔗 Player 1 Stake | 7ecaa310... |
| 🔗 Player 2 Stake | 539ebac5... |
| 🔗 ZK Reveal | 185a2e99... |
The following features were fully designed, implemented, and deployed during September 2026 as a direct result of the closed beta feedback program.
A live leaderboard backed by real Prisma DB aggregations. Ranks the top 20 players by win count with win rate and total games played. Accessible from the main sidebar navigation.
Commit: f0ed19f
The player profile page now features a full Match History section. Every settled game shows the result (Win / Loss / Draw), opponent wallet address, card values revealed after settlement, stake delta, and a direct link to the Midnight Explorer transaction.
Commits: d0b61a0 · 6a78aed
Games created with "Private" stakes previously leaked the stake amount in the /api/matches/open response. The endpoint now explicitly nullifies private stake amounts before serialization — the lobby table shows "Private" rather than a number.
Commit: d0b61a0
TableFelt (the in-game view) is now fully playable on mobile. The card row uses overflow-x-auto horizontal snapping so all 5 cards are reachable. The action button area has pb-24 clearance to sit above the mobile browser navigation bar.
Commit: ae6bbdf
Card hands are now server-generated using a cryptographic Fisher-Yates shuffle on match creation. Each player receives a unique 5-card hand stored in encrypted deckData on the Match record and retrieved via /api/matches/[id]/hand.
Commit: d11527f
Move pre-images (private card values) were previously written to an ephemeral .moves.json file, causing matches to get stuck after serverless cold starts. Pre-images are now stored as committedValue and committedNonce columns on the MatchPlayer Prisma model — persisting across restarts and deployments.
Commit: d11527f
A dismissable How to Play card was added to the Lobby, walking new players through the 4-step ZK game flow: Fund → Join → Lock Card → Reveal. Full written guide published at docs/CADET_FLIGHT_MANUAL.md.
Commit: adb13f8
- Deleted unauthenticated
/api/matches/clearendpoint (wiped the entire DB with a single GET request) - Deleted
/api/debugdiagnostic endpoint (returned full user data with no auth) - Removed legacy
fs.readFileSyncdead code from/api/matches/[id]/finish - Replaced
alert()in wallet connector with a structured error for toast-based handling
Commits:e351bf2·1101dd2
All four GitHub Actions workflows now pass on every push to main:
- TypeScript typecheck (
tsc --noEmit) - ESLint (0 errors, 0 warnings)
- Vitest unit tests (4/4)
- Next.js production build
Commits:bf5c679·895183a
graph TD
A[Next.js 15 App Router] -->|Connects to| B(1AM Midnight Wallet)
B -->|Signs & generates ZK Proofs locally| C{Midnight Preprod Node}
C -->|Verifies Compact circuits| D[(Midnight Blockchain)]
A -->|Lobby, leaderboard, history| E[(Prisma / PostgreSQL)]
D -->|Settlement events| E
A -->|Serves ZK key artifacts| F[Browser ZK Prover]
F -->|Proof submitted| C
| Layer | Technology |
|---|---|
| Frontend | Next.js 15 (App Router), Tailwind CSS, Framer Motion |
| ZK Infrastructure | Midnight Network, Compact circuits, 1AM Wallet |
| API | Next.js Route Handlers (serverless) |
| Database | Prisma ORM + PostgreSQL (Neon) |
| Auth | 1AM Wallet address — no passwords, no accounts |
| CI / CD | GitHub Actions (build · lint · test · contracts) + Vercel |
ShadowArena uses two Midnight .compact circuits deployed on the Midnight Preprod Network:
Manages the escrow logic. Holds tDUST from both players securely on-chain until the winner is mathematically determined. Prevents withdrawal until the ZK reveal is verified.
The core ZK circuit. Verifies the Blake2b hashes of both players' committed card values, evaluates which card is higher without revealing the actual values, and triggers the payout atomically.
Extension of the stake pool for anonymous games. The stake amount is a private witness — the opponent and spectators see only a commitment hash, not the amount.
Contract Compilation & ZK Keys:

Deployment:
ShadowArena strictly adheres to Midnight's data protection programming model:
| Data | Visibility | Description |
|---|---|---|
| Card hash commitments | 🌐 Public (on-chain) | Blake2b hash of card_value ‖ nonce |
| Wallet addresses | 🌐 Public (on-chain) | Both players' shielded addresses |
| Stake amounts (standard) | 🌐 Public (on-chain) | Visible in lobby and on-chain |
| Stake amounts (private) | 🔒 Private witness | Hidden — only the commitment is on-chain |
| Actual card integer value | 🔒 Private witness | Never leaves the user's 1AM Wallet |
| Cryptographic nonce | 🔒 Private witness | Used only to generate the ZK proof locally |
Guarantee: Even if the ShadowArena server were fully compromised, no attacker could retroactively learn any player's card value from the on-chain data.
sequenceDiagram
participant P1 as Player 1
participant P2 as Player 2
participant MW as Midnight Network
P1->>MW: Deploy Game Contract & Escrow Stake
P2->>MW: Join Contract & Escrow Stake
P1->>P1: Select Card (Private Witness, local only)
P1->>MW: Submit Blake2b Hash Commitment
P2->>P2: Select Card (Private Witness, local only)
P2->>MW: Submit Blake2b Hash Commitment
MW->>MW: Verify both commitments are present
P1->>MW: Call Reveal circuit with ZK Proof
MW->>MW: Mathematically evaluate winner (ZK — no raw values seen)
MW->>P1: Payout to winner's address
ShadowArena/
├── apps/
│ └── web/ # Next.js 15 App Router
│ ├── app/
│ │ ├── (app)/ # Authenticated pages
│ │ │ ├── dashboard/ # Game dashboard
│ │ │ ├── lobby/ # Open game tables
│ │ │ ├── leaderboard/ # Live player rankings ← New Sep 2026
│ │ │ ├── profile/ # Stats, inventory, match history ← Updated Sep 2026
│ │ │ ├── marketplace/ # NFT cosmetic skins
│ │ │ ├── tournaments/ # Tournament browser
│ │ │ └── table/[id]/ # Live game view
│ │ ├── api/
│ │ │ ├── matches/
│ │ │ │ ├── open/ # Lobby table list (private-stake aware)
│ │ │ │ ├── history/ # Settled match history ← New Sep 2026
│ │ │ │ └── [id]/
│ │ │ │ ├── hand/ # Dealt card hand
│ │ │ │ ├── moves/ # ZK pre-image storage
│ │ │ │ ├── join/ # Player 2 join flow
│ │ │ │ └── finish/ # Settlement (Prisma-backed)
│ │ │ ├── leaderboard/ # Rankings aggregation
│ │ │ ├── feedback/ # Beta feedback collection
│ │ │ ├── stats/ # Live platform statistics
│ │ │ └── user/ # Profile, assets, activity
│ │ └── page.tsx # Public landing page
│ ├── components/
│ │ ├── game/
│ │ │ ├── TableFelt.tsx # ZK game state machine ← Mobile-fixed Sep 2026
│ │ │ ├── StakeModal.tsx # Stake creation with retry logic
│ │ │ └── FeedbackModal.tsx
│ │ └── ui/ # shadcn/ui component library
│ ├── lib/
│ │ └── midnight/
│ │ ├── wallet.ts # 1AM Wallet Zustand store
│ │ ├── contract.ts # Compact circuit bindings
│ │ └── deploy.ts # Contract deployment helpers
│ └── prisma/
│ └── schema.prisma # Full DB schema
├── contracts/ # Midnight Compact source
│ └── circuits/
│ ├── stake-pool.compact
│ ├── stake-pool-private.compact
│ └── move-validity.compact
├── docs/
│ ├── FEEDBACK_LOOP.md # Beta issue tracker (this file's sibling)
│ ├── USERS.md # 70 verified tester wallets
│ ├── CADET_FLIGHT_MANUAL.md # Player onboarding guide
│ ├── COMPACT_CIRCUIT.md # ZK circuit technical reference
│ └── SYSTEM_ARCHITECTURE.md # Stack overview
└── .github/
└── workflows/
├── build.yml # Next.js production build
├── lint.yml # TypeScript + ESLint
├── test.yml # Vitest unit tests
└── contracts.yml # ZK artifact validation
All four GitHub Actions workflows run automatically on every push to main and develop.
| Workflow | Trigger | What it checks |
|---|---|---|
| Build | push / PR | npm run build — full Next.js production build with Prisma generate |
| Lint | push / PR | tsc --noEmit typecheck + ESLint (0 errors enforced) |
| Test | push / PR | Vitest unit test suite — game logic, ZK settlement, edge cases |
| Contracts | contracts/** change |
Validates compiled Compact artifacts and ZK key files are present |
- Node.js v18+
- PostgreSQL (local or Neon)
- 1AM Wallet browser extension
- Midnight Preprod tDUST from the faucet
# 1. Clone
git clone https://github.com/aditya-jha033/ShadowArena.git
cd ShadowArena
# 2. Install all workspace dependencies
npm install
# 3. Configure environment
cp apps/web/.env.example apps/web/.env
# Edit apps/web/.env — add your DATABASE_URL
# 4. Initialise database
cd apps/web
npx prisma generate
npx prisma db push
# 5. Start development server
npm run dev # from repo root → http://localhost:3000# apps/web/.env
DATABASE_URL="postgresql://user:password@localhost:5432/shadowarena"
NEXT_PUBLIC_MIDNIGHT_NETWORK="preprod"The cryptographic game-settlement logic is fully unit-tested using Vitest. This includes compiled-circuit adversarial tests and full Preprod end-to-end tests to ensure all edge cases are cryptographically verified.
cd apps/web
npm run testTests cover:
- Win / Loss / Draw determination from committed card values
- Edge cases — tied cards, zero-value cards, maximum card values
- Settlement atomicity — result is deterministic given the same pre-images
ShadowArena ran a structured closed beta with 70 verified Midnight Preprod wallet holders during September 2026.
| Resource | Link |
|---|---|
| 📋 Feedback Form | Google Form |
| 📊 Response Sheet | Google Sheets |
| 🐛 Issue Tracker | FEEDBACK.md |
| 👥 Tester Registry | LAUNCH_USERS.md |
Our launch testers and their valid wallet formats can be found in our LAUNCH_USERS.md registry.
All 13 issues surfaced during the beta were triaged, fixed, and committed during September 2026. Highlights:
| Issue | Reported By | Fix |
|---|---|---|
| Reveal button premature | Soumik Chatterjee | TableFelt state gate — commit 5a3047c |
| Hardcoded cards (2 5 8 10) | Pramod Mahto | Fisher-Yates shuffle — commit d11527f |
| Debug endpoint leaking data | Arnab Sengupta | Deleted /api/debug — commit 5a3047c |
| No leaderboard | Manas Kumar Nayak | Built /leaderboard — commit f0ed19f |
| Private stake leaking | Rajesh Jha | Fixed API masking — commit d0b61a0 |
| Mobile layout broken | Subhro Dasgupta | overflow-x-auto + pb-24 — commit ae6bbdf |
| No match history | Partha Mukhopadhyay | /api/matches/history + Profile section — commit 6a78aed |
Landing Page:

Player Dashboard:

Player Profile (with Match History):

Lobby — Open Game Tables:

Enter Game:

Game View (TableFelt):

Game Play — ZK Card Lock:

Victory Screen:
- High Card Duel with ZK commitment & reveal
- 1AM Wallet integration (Preprod)
- Private & public stake modes
- Leaderboard with real Prisma aggregations
- Match history on player profile
- Mobile-responsive game view
- Full CI / CD pipeline (build · lint · test)
- 70-tester closed beta with structured feedback loop
Built on Midnight Network · Powered by Zero-Knowledge Cryptography
midnight.network · docs · Preprod Faucet

