Privacy-first Web3 strategic risk game — a tile-based, provably fair Mines experience with progression, missions, achievements, leaderboards, referrals and analytics.
Shadow Mines is strategy, not chance — uncover gems on a 4×4 board, dodge bombs, cash out when your edge peaks. Practice for free, play with a stake via on-chain smart contract, verify every round's fairness from your wallet.
- Provably fair rounds (commit/reveal scheme, HMAC-SHA256 derivation).
- Wallet-native auth (EIP-191 signed message — no email, no password).
- Practice & stake modes — internal credits or smart-contract stakes.
- Full progression system: 10 levels, XP, missions, achievements, daily streak.
- Leaderboards — daily, weekly, multiplier, XP, wins.
- Referral system — invite friends, both get credits.
- Analytics dashboard with charts and global pulse.
- Modern gaming UI — glassmorphism, framer-motion, dark theme. Not a casino.
ShadowMine-Midnight/
├── backend/ # Node + Express + Socket.io + Mongoose
│ ├── server.js
│ ├── src/
│ │ ├── app.js
│ │ ├── config/ (db, constants)
│ │ ├── models/ (User, GameSession, Mission, UserMission,
│ │ │ Achievement, Referral, Analytics, DailyClaim)
│ │ ├── controllers/ (auth, user, game, leaderboard, missions, …)
│ │ ├── routes/ (/api/*)
│ │ ├── middleware/ (auth, errorHandler)
│ │ ├── services/ (gameEngine, xpService, levelService,
│ │ │ achievementService, missionService,
│ │ │ leaderboardService, contractService)
│ │ ├── sockets/ (Socket.io rooms per-user, leaderboards)
│ │ ├── utils/ (provablyFair, multiplier, jwt, logger)
│ │ └── seed/ (missions + achievements seeder)
├── contracts/
│ ├── ShadowMines.sol # Solidity contract for stake mode
│ └── abi/ShadowMines.json
└── frontend/ # React + Vite + Tailwind + Framer Motion
├── index.html
└── src/
├── api/ (axios + per-resource clients)
├── context/ (Wallet, Auth, Socket)
├── hooks/ (useGame)
├── components/
│ ├── ui/ (Button, Card, Modal, Badge, Progress, …)
│ ├── layout/ (DashboardLayout — sidebar + topbar)
│ ├── game/ (Tile, GameBoard, GameHUD, Controls, ResultModal)
│ ├── profile/ (LevelBar, GameHistory, StatsChart, BadgeGrid)
│ ├── leaderboard/ (LeaderboardTable)
│ ├── missions/ (MissionCard)
│ ├── achievements/ (AchievementCard)
│ └── common/ (WalletConnect, DailyRewardModal)
├── pages/
│ ├── Landing.jsx
│ ├── Dashboard.jsx
│ ├── Game.jsx
│ ├── Profile.jsx
│ ├── Leaderboard.jsx
│ ├── Achievements.jsx
│ ├── Missions.jsx
│ ├── Referrals.jsx
│ └── Analytics.jsx
└── utils/ (constants, levels, multiplier, formatters)
- Node.js ≥ 18
- MongoDB (local or Atlas)
- MetaMask in your browser
cd backend
cp .env.example .env # set MONGODB_URI, JWT_SECRET, etc.
npm install
npm run seed # populate Missions + Achievements
npm run dev # http://localhost:5000cd frontend
cp .env.example .env # set VITE_API_URL
npm install
npm run dev # http://localhost:5173See contracts/README.md. Deploy ShadowMines.sol via Hardhat/Foundry, then set in backend/.env:
CONTRACT_ADDRESS=0x...
RPC_URL=https://...
HOUSE_PRIVATE_KEY=0x...
- Client requests a nonce:
GET /api/auth/nonce?walletAddress=0x… - Server returns a structured human-readable message.
- Wallet signs the message (EIP-191).
- Client sends
{ walletAddress, signature, nonce, username?, referralCode? }→POST /api/auth/verify. - Server verifies signature, creates the user (with starter credits) if new, returns a JWT.
Subsequent calls send Authorization: Bearer <jwt>.
A round on a 16-tile board with B bombs has multiplier after g gems revealed:
multiplier = (1 − houseEdge) · ∏_{k=0..g-1} (16 − k) / (16 − B − k)
This is implemented in backend/src/utils/multiplier.js and mirrored on the client (frontend/src/utils/multiplier.js) so the HUD can preview the next multiplier without a roundtrip.
- Server generates
serverSeedand commitsserverSeedHash = sha256(serverSeed)before the round. - Client supplies (or auto-generates)
clientSeed.nonceisDate.now(). - Board is derived with
HMAC-SHA256(serverSeed, clientSeed:nonce)driving a Fisher–Yates shuffle. - At round end the server returns
serverSeed. Player can verify:sha256(serverSeed) === serverSeedHash- Replaying the shuffle yields the same
bombTiles.
| Path | Auth | Description |
|---|---|---|
GET /api/health |
— | Service heartbeat |
GET /api/auth/nonce |
— | Get sign-in nonce |
POST /api/auth/verify |
— | Verify signature → JWT |
GET /api/auth/me |
✅ | Current user |
GET /api/user/me |
✅ | Profile + recent games |
PUT /api/user/me |
✅ | Update username/avatar |
GET /api/user/stats |
✅ | Aggregate stats + timeline |
GET /api/game/config |
— | Difficulties + multiplier tables |
POST /api/game/start |
✅ | Start a round |
POST /api/game/:id/reveal |
✅ | Reveal a tile |
POST /api/game/:id/cashout |
✅ | Cash out the round |
GET /api/game/active |
✅ | Currently active round (if any) |
GET /api/game/history |
✅ | Round history |
GET /api/leaderboard/{daily,weekly,multiplier,xp,wins} |
— | Leaderboards |
GET /api/missions |
✅ | List missions for user |
POST /api/missions/:key/claim |
✅ | Claim mission reward |
GET /api/achievements |
✅ | List achievements + unlocked state |
GET /api/referrals/summary |
✅ | Referral stats |
GET /api/analytics/global |
— | Global aggregate |
GET /api/analytics/me |
✅ | User analytics + timeline |
GET /api/rewards/daily/status |
✅ | Streak status |
POST /api/rewards/daily/claim |
✅ | Claim daily reward |
The client joins a private room user:<wallet> upon connecting with its JWT. Events the server may emit:
game:start→{ id, mode, stake, … }game:reveal→ updated session stategame:cashout→ ended session (with seed reveal)reward:daily→{ day, reward }
- Frontend: Vercel (auto from
frontend/). - Backend: Railway or Render. Set env vars, point a MongoDB Atlas cluster, and expose port
5000. - Contract: deploy via Hardhat to Sepolia/Base/Optimism; fund the contract with house liquidity.
- Multiplayer rooms, friends list, chat
- Season pass, NFT skins
- Tournament mode
- AI personalization
- Mobile (React Native) shell
MIT — Use freely, just don't ship a casino with our name on it.