Building Your First Game on Midnight
Develop privacy-preserving blockchain games with zero-knowledge proofs. Build a Rock-Paper-Scissors game where moves stay hidden until revelation.
Summary
This comprehensive developer guide introduces Midnight, a privacy-focused blockchain platform designed for creating decentralized games with built-in data protection through zero-knowledge proofs.
Key Concepts
Midnight Platform Features
- Privacy by Default: All contract state can be kept private using ZK proofs
- Supports both shielded (private) and unshielded (public) assets
- Uses the Compact language for smart contract development
- Includes full-stack dApp support with React integration
Why Games Benefit from Midnight
The platform solves traditional blockchain gaming problems like visible game state, front-running attacks, and strategy exposure by enabling private computations that prove validity without revealing sensitive information.
Technical Architecture
The stack includes:
- Frontend: React with Lace wallet integration
- Smart Contracts: Written in Compact language, compiling to WebAssembly
- Blockchain Layer: Public ledger combined with private state storage
- Proof Generation: Server-side zero-knowledge proof creation
Practical Implementation
The tutorial provides:
- Setup instructions including Git LFS, Compact compiler, and Lace wallet installation
- Project structure overview covering contract files, CLI tools, and React frontend
- Rock-Paper-Scissors game example demonstrating commit-reveal mechanics
- Testing frameworks using Vitest for contract validation
- Deployment guidance for local development and Preview Network testnet
Rock-Paper-Scissors Implementation
The game demonstrates core privacy patterns:
pragma language_version >= 0.19;
import CompactStandardLibrary;
enum Choice { rock, paper, scissors }
enum GameState { waiting, committed, revealed, finished }
export ledger gameState: GameState;
export ledger player1Commitment: Bytes<32>;
export ledger player2Commitment: Bytes<32>;
witness get_secret(): Bytes<32>;
circuit commit_move(choice: Choice): Bytes<32> {
const secret = get_secret();
return persistentHash<Vector<2, Field>>([
choice as Field,
secret as Field
]);
}
export circuit player1_commit(commitment: Bytes<32>): [] {
assert(gameState == GameState.waiting, "Invalid state");
player1Commitment = commitment;
}
export circuit player1_reveal(choice: Choice, secret: Bytes<32>): [] {
const expected = persistentHash<Vector<2, Field>>([
choice as Field,
secret as Field
]);
assert(expected == player1Commitment, "Invalid reveal");
"hl-comment">// Continue with game logic...
}
Advanced Patterns
Includes techniques for:
- Multi-player game state management: Coordinate turns and actions between players
- Commit-reveal schemes: Hide moves until all players have committed
- Time-locked actions: Enforce deadlines for player responses
- Token staking mechanisms: Add economic incentives to games
Testing Your Game
class="hl-keyword">import { describe, it, expect } class="hl-keyword">from class="hl-string">'vitest';
class="hl-keyword">import { GameSimulator } class="hl-keyword">from class="hl-string">'./simulator';
describe(class="hl-string">'Rock Paper Scissors', () => {
it(class="hl-string">'should allow player to commit move', class="hl-keyword">async () => {
class="hl-keyword">const sim = new GameSimulator();
class="hl-keyword">const commitment = class="hl-keyword">await sim.commitMove(class="hl-string">'rock', class="hl-string">'secret123');
expect(commitment).toBeDefined();
});
it(class="hl-string">'should correctly determine winner', class="hl-keyword">async () => {
class="hl-keyword">const sim = new GameSimulator();
class="hl-keyword">await sim.player1Commit(class="hl-string">'rock');
class="hl-keyword">await sim.player2Commit(class="hl-string">'scissors');
class="hl-keyword">await sim.revealMoves();
expect(sim.getWinner()).toBe(class="hl-string">'player1');
});
});
Deployment Checklist
- Install Compact compiler v0.27.0
- Run all tests locally
- Set up Lace wallet with testnet tokens
- Configure environment variables
- Deploy to Preview Network
- Verify contract on explorer
Best Practices
The guide emphasizes:
- Minimizing circuit complexity for faster proof generation
- Appropriate state visibility (public vs private)
- Graceful error handling with clear messages
- Comprehensive edge-case testing
- Gas optimization for complex games
Resources
- Midnight Documentation: https://docs.midnight.network
- Compact Language Guide: https://docs.midnight.network/develop/reference/compact
- Lace Wallet: https://www.lace.io
- Discord Community: Join for developer support