Stake crypto, play chess, win on-chain. A decentralized PvP chess platform with smart contract escrow, real-time gameplay via WebSocket, and a modern Next.js frontend.
| Layer | Tech | Version |
|---|---|---|
| Smart Contracts | Solidity + OpenZeppelin | 0.8.28 / v5.6 |
| Contract Tooling | Hardhat | v2.22 |
| Backend | Node.js + Express + TypeScript | Node 22 / Express 5 |
| Database | PostgreSQL + Prisma | PG 17 / Prisma 6 |
| Real-time | WebSocket (ws) | v8.18 |
| Blockchain Client | Viem | v2.23 |
| Frontend | Next.js + React + Tailwind CSS | Next 16 / React 19 / TW 4 |
| Web3 Frontend | Wagmi + RainbowKit | Wagmi 3.5 / RK 2.2 |
| Chess Engine | chess.js | v1.0 |
| Chess UI | react-chessboard | v4.7 |
| Target Chain | Base (L2) | — |
┌─────────────┐ ┌──────────────┐ ┌──────────┐
│ Frontend │────▶│ Backend │────▶│ Database │
│ Next.js 16 │ WS │ Express 5 │ │ Postgres │
│ Wagmi 3 │◀────│ chess.js │ └──────────┘
└──────┬──────┘ └──────┬───────┘
│ │
│ ▼
│ ┌──────────────┐
└───────────▶│ Base Chain │
Viem/Wagmi │ BonuzChess.sol│
└──────────────┘
Key design decision: Moves happen off-chain (WebSocket) for speed. Only game creation, joining, and result finalization hit the blockchain. This keeps gas costs minimal while maintaining trustless payouts.
- Node.js 22+
- PostgreSQL 17+
- MetaMask or any Web3 wallet
git clone <repo-url> && cd bonuz-chess
npm install # root workspace
cd contracts && npm install && cd ..
cd backend && npm install && cd ..
cd frontend && npm install && cd ..cp contracts/.env.example contracts/.env
cp backend/.env.example backend/.env
cp frontend/.env.local.example frontend/.env.local
# Edit each with your valuescreatedb bonuzchess
cd backend
npx prisma migrate dev
npx prisma generate# Terminal 1 — Local blockchain
cd contracts && npx hardhat node
# Terminal 2 — Deploy contract
cd contracts && npx hardhat run scripts/deploy.ts --network localhost
# Terminal 3 — Backend API
cd backend && npm run dev
# Terminal 4 — Timeout worker
cd backend && npm run worker
# Terminal 5 — Frontend
cd frontend && npm run devOpen http://localhost:3000 and connect your wallet.
docker compose up -dbonuz-chess/
├── contracts/ # Solidity smart contracts
│ ├── contracts/BonuzChess.sol
│ ├── scripts/deploy.ts
│ ├── test/BonuzChess.test.ts
│ └── hardhat.config.ts
├── backend/ # Node.js API server
│ ├── prisma/schema.prisma
│ └── src/
│ ├── config/
│ ├── middleware/
│ ├── routes/
│ ├── services/ # Game, Chess Engine, Contract, WS
│ ├── workers/ # Timeout monitor
│ └── index.ts
├── frontend/ # Next.js 16 app
│ └── src/
│ ├── app/ # Pages (home, lobby, game, profile)
│ ├── components/ # UI, Layout, Web3
│ ├── hooks/ # useGameSocket, useContract
│ ├── lib/ # API client
│ └── config/ # Wagmi/Web3 config
├── docker-compose.yml
└── package.json # Workspace root
BonuzChess.sol — deployed on Base L2.
- Create games with optional ETH stake
- Join games by matching the stake
- Backend finalizes results on-chain
- Pull-payment pattern for secure withdrawals
- 90/10 split: winner gets 90%, treasury gets 10%
- ReentrancyGuard, Pausable, Ownable (OpenZeppelin v5)
cd contracts
npx hardhat test # Run test suite
npx hardhat coverage # Coverage report| Method | Route | Description |
|---|---|---|
| GET | /api/health | Health check + WS stats |
| POST | /api/games | Create a game |
| GET | /api/games/lobby | List pending games |
| GET | /api/games/active | List active games |
| GET | /api/games/:id | Get game details + moves |
| POST | /api/games/:id/join | Join a game |
| POST | /api/games/:id/move | Make a move |
| POST | /api/games/:id/cancel | Cancel pending game |
| GET | /api/games/:id/messages | Get chat messages |
| POST | /api/games/:id/messages | Send chat message |
| GET | /api/users/:wallet | Get user profile |
| GET | /api/users/:wallet/games | Get user's games |
Connect to ws://localhost:3001/ws?gameId=<id>&wallet=<address> for real-time events:
game:move— opponent made a movegame:joined— opponent joinedgame:finished— game endedgame:timeout— player timed outchat:message— new chat messageplayer:connected/player:disconnected
- Get testnet ETH from a faucet
- Set
BASE_SEPOLIA_RPC_URLandDEPLOYER_PRIVATE_KEYin contracts/.env npm run deploy:testnet- Copy contract address to backend/.env and frontend/.env.local
- Deploy contract to Base mainnet
- Run
docker compose up -don your server - Point your domain to the frontend (port 3000)
- Set up SSL with nginx/Caddy
MIT