A Web3 trivia game built on Base network. Players can play trivia rounds, answer questions, and earn real ETH rewards on-chain.
Zali is a fun, lightweight Web3 game designed to showcase:
- Seamless Web3 wallet integration
- Fast L2 transactions on Base
- Real ETH rewards
- Smooth gameplay experience
- Secure, simple blockchain architecture
Players can:
- Connect their Web3 wallet (MetaMask, Coinbase Wallet, etc.)
- Register a username
- Play free trivia rounds (no entry fee)
- Answer timed trivia questions
- Earn ETH rewards paid automatically via smart contracts
No staking. No long setup. Just connect → play → earn.
🎉 DEPLOYED: December 14, 2024
- SimpleTriviaGame:
0x7409Cbcb6577164E96A9b474efD4C32B9e17d59d - USDC (Base Mainnet):
0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 - Network: Base Mainnet (Chain ID: 8453)
- Compiler: Solc v0.8.30
- Optimization: 200 runs
| Property | Value |
|---|---|
| Deployer | 0x2c8D82a53f11B0E9B527a111B2f53C5D5E809806 |
| Gas Used | 2,913,596 |
| Deploy Cost | ~$0.05 |
| Initial Questions | 5 trivia questions |
| Reward per Answer | 0.1 USDC |
- 🔍 View on BaseScan
- 🎮 Frontend: (Deploying soon)
- 📹 Demo Video: (Coming soon)
- Works with any Web3 wallet (MetaMask, Coinbase Wallet, WalletConnect)
- Instant balance updates
- Fast and cheap Base L2 transactions
- Each player can receive 10 USDC once (testnet only)
- Enforced by smart contract
- Secure against multiple claims
- 10 random questions per game session
- Multiple-choice questions
- 5-minute time limit
- Responsive UI with smooth animations
- Questions selected via Chainlink VRF for fairness
- FREE to play (no entry fee)
- Earn 0.001 ETH per correct answer
- Earn 0.005 ETH bonus for perfect score (10/10)
- Earn up to 0.002 ETH speed bonus for fast answers
- Max reward per game: 0.017 ETH
- Rewards distributed automatically via smart contract
- Track top 100 players by total score
- Username registration system
- Weekly reward distribution for top 10 players
- Real-time rank updates
- Responsive design
- Optimized for both desktop and mobile
- Smooth animations with Framer Motion
- Minimal steps to play
Web3 Wallet → Register Username → Start Game → Answer Questions → Submit Answers → Claim ETH Rewards
+------------------+ +----------------------+ +----------------------+
| Frontend (Next) | <--> | TriviaGameV2.sol | <-> | Chainlink VRF V2 |
+------------------+ +----------------------+ +----------------------+
| |
| |
v v
+------------------+ +------------------+
| Faucet.sol | | USDC Token |
| (Optional) | | (Base Mainnet) |
+------------------+ +------------------+
- Solidity 0.8.20
- Foundry (Forge)
- OpenZeppelin Contracts
- Chainlink VRF V2
- Base Mainnet
- USDC (ERC20)
- Next.js 14 (App Router)
- React 18
- TypeScript
- Wagmi v2 (React Hooks for Ethereum)
- Viem (Ethereum utilities)
- Reown AppKit (WalletConnect v2)
- TailwindCSS
- Framer Motion
- React Hot Toast
- On-chain only (no traditional backend)
- Questions stored in smart contract
- Chainlink VRF for randomness
Zali/
├── contracts/ # Smart contracts (Foundry)
│ ├── src/
│ │ ├── Faucet.sol
│ │ ├── TriviaGame.sol
│ │ ├── TriviaGameV2.sol
│ │ └── MockVRF*.sol
│ ├── script/ # Deployment scripts
│ │ ├── Deploy.s.sol
│ │ ├── DeployTriviaGameV2.s.sol
│ │ └── Add*Questions.s.sol
│ ├── test/ # Contract tests
│ └── foundry.toml # Foundry config
├── frontend/
│ ├── src/
│ │ ├── app/ # Next.js pages
│ │ ├── components/ # React components
│ │ ├── hooks/ # Custom hooks
│ │ ├── config/ # Contract ABIs & addresses
│ │ ├── store/ # Zustand state management
│ │ └── contexts/ # React contexts
│ ├── config/ # Web3 configuration
│ └── package.json
├── BASE_MIGRATION_GUIDE.md
└── README.md
Manages the complete trivia game with leaderboard, VRF randomness, and ETH rewards.
Key features:
- Username registration system
- Chainlink VRF V2 for random question selection
- On-chain question storage
- Automatic ETH reward distribution
- Leaderboard tracking (top 100 players)
- Weekly reward pools for top players
- Speed bonus calculations
Key functions:
function registerUsername(string memory _username) external;
function startGame() external returns (uint256 sessionId);
function submitAnswers(uint256 _sessionId, uint8[] calldata _answers) external;
function claimRewards() external;
function getLeaderboard(uint256 _count) external view returns (...);
function addQuestion(...) external onlyOwner;Provides a one-time 10 USDC claim per user for testing.
Key functions:
function claim() external;
function withdrawTokens(uint256 amount) external onlyOwner;git clone https://github.com/yourname/zali.git
cd Zalicd contracts
forge installcd frontend
npm installCreate a .env.local file in /frontend:
# Contract Addresses (update after deployment)
NEXT_PUBLIC_TRIVIA_GAME_V2_ADDRESS=0x...
NEXT_PUBLIC_FAUCET_ADDRESS=0x... # Optional - testnet only
NEXT_PUBLIC_MOCK_VRF_ADDRESS=0x... # Optional - for testing
# Network Configuration
NEXT_PUBLIC_RPC_URL=https://mainnet.base.org
# WalletConnect
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=your_project_id
# Deployer Private Key (for deployment only)
PRIVATE_KEY=your_private_key_here- Base Mainnet: Chain ID
8453 - Base Sepolia (Testnet): Chain ID
84532
Run Foundry tests:
cd contracts
forge test
forge test -vvv # Verbose output- Visit https://vrf.chain.link
- Create a subscription on Base Mainnet
- Fund with LINK tokens
- Copy subscription ID
- Update
contracts/script/DeployTriviaGameV2.s.solwith your subscription ID
cd contracts
# Deploy to Base Mainnet
forge script script/DeployTriviaGameV2.s.sol:DeployTriviaGameV2 \
--rpc-url https://mainnet.base.org \
--broadcast --verify \
--etherscan-api-key $BASESCAN_API_KEY
# Or deploy to Base Sepolia (testnet)
forge script script/DeployTriviaGameV2.s.sol:DeployTriviaGameV2 \
--rpc-url https://sepolia.base.org \
--broadcast --verify \
--etherscan-api-key $BASESCAN_API_KEYGo to https://vrf.chain.link and add your deployed contract address as a consumer.
cast send YOUR_CONTRACT_ADDRESS --value 0.5ether \
--rpc-url https://mainnet.base.org \
--private-key $PRIVATE_KEYforge script script/AddBasicQuestions.s.sol \
--rpc-url https://mainnet.base.org \
--broadcastCopy contract addresses → /frontend/src/config/contracts.ts.
npm run devView at:
http://localhost:3000
Deploy using Vercel:
vercel --prodAdd environment variables on Vercel.
The contracts emit events for tracking game progress:
event PlayerRegistered(address indexed player, string username);
event GameStarted(address indexed player, uint256 sessionId, uint256 requestId);
event QuestionsAssigned(address indexed player, uint256 sessionId, uint256[] questionIds);
event GameCompleted(address indexed player, uint256 sessionId, uint256 score, uint8 correctCount, uint256 reward);
event RewardClaimed(address indexed player, uint256 amount);
event LeaderboardUpdated(address indexed player, uint256 newRank, uint256 totalScore);ETH balance fetched in real time.
One-time registration, stored on-chain.
Transaction triggers Chainlink VRF request for random questions.
Chainlink VRF callback selects 10 random questions from contract storage.
10 multiple-choice questions with 5-minute time limit.
Smart contract calculates:
- Correct answer count
- Speed bonus (faster = more bonus)
- Total score
- ETH reward amount
Player's rank updates automatically based on total score.
ETH rewards transferred instantly to player's wallet.
Top 10 players share weekly reward pool.
- Responsive design (mobile & desktop)
- Smooth animations with Framer Motion
- Question timer with visual countdown
- Progress tracking
- Real-time balance updates
- Toast notifications for transactions
- Error boundaries for graceful error handling
- Loading states and skeleton screens
- Gradient themes
- Interactive leaderboard
- Wallet connection modal (AppKit)
On-chain leaderboard tracking:
- Top 100 players by total score
- Player username
- Total score (includes correct answers + speed bonuses)
- Games played
- Best score in a single session
- Accuracy percentage
- Real-time rank updates
Weekly rewards:
- Top 10 players share weekly reward pool
- Distribution: 40%, 25%, 15%, 10%, 5%, 2.5%, 1%, 0.5%, 0.5%, 0.5%
- Reentrancy protection with OpenZeppelin's
ReentrancyGuard - Access control with
Ownable - Input validation for all user-provided data
- Secure random number generation using Chainlink VRF
- Emergency withdrawal functions for admin
- Comprehensive test coverage
The application implements comprehensive input sanitization to prevent XSS and injection attacks. The following measures are in place:
sanitizeString(input: string): Removes HTML/JS tags and escapes special characterssanitizeUsername(username: string): Sanitizes usernames with strict character whitelistingsanitizeNumber(input: unknown): Safely converts input to a number with proper error handlingsanitizeAddress(address: string): Validates and sanitizes Ethereum addresses
The useSanitizedForm hook wraps react-hook-form with automatic input sanitization:
import { useSanitizedForm } from '@/hooks/useSanitizedForm';
import { z } from 'zod';
const schema = z.object({
username: z.string().min(3).max(20),
// other fields...
});
const form = useSanitizedForm(schema, {
// optional react-hook-form options
});Input validation is handled by Zod schemas with built-in sanitization:
import { z } from 'zod';
import { sanitizeUsername } from '@/utils/sanitize';
export const usernameSchema = z
.string()
.min(3)
.max(20)
.transform(val => sanitizeUsername(val.trim()));All sanitization functions have corresponding unit tests in src/utils/__tests__/sanitize.test.ts.
- Reentrancy Protection: All contracts use OpenZeppelin's
ReentrancyGuard - Access Control: Admin functions protected with
onlyOwnermodifier - Input validation: Alphanumeric + underscore only
- Time limits: 5-minute timeout per game session
- Gas optimization: Efficient storage patterns and loops
- No price manipulation: Rewards are fixed in ETH, not dependent on oracle prices
Your demo video should include:
- Opening the webapp in browser
- Connecting Web3 wallet (MetaMask/Coinbase Wallet)
- Registering username
- Starting a game session
- Showing Chainlink VRF question assignment
- Playing trivia (answering questions)
- Submitting answers and viewing score
- Claiming ETH rewards
- Viewing leaderboard position
- Showing transaction on BaseScan
- Explaining the architecture and Base integration
- Built on Base: Fast, cheap L2 transactions
- Chainlink VRF Integration: Provably fair randomness
- Real ETH rewards: Instant payouts on-chain
- No entry fees: Free to play, earn based on performance
- Comprehensive leaderboard: Competitive gameplay with weekly rewards
- Production-ready: Full error handling, state management, and testing
- Fully on-chain: No backend dependencies
- Modern Web3 stack: Wagmi, Viem, AppKit for seamless wallet integration
- Clean architecture: Well-documented and maintainable code
Feel free to fork, open issues, or submit pull requests.
MIT License © 2025
- Base Mainnet Explorer: https://basescan.org
- Base Sepolia Explorer: https://sepolia.basescan.org
- Base Documentation: https://docs.base.org
- Chainlink VRF (Base): https://docs.chain.link/vrf/v2/subscription/supported-networks#base-mainnet
- USDC on Base: https://basescan.org/token/0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
- Get testnet ETH: https://www.coinbase.com/faucets/base-ethereum-sepolia-faucet
For issues, questions, or contributions:
- Open an issue on GitHub
- Check
BASE_MIGRATION_GUIDE.mdfor deployment help - Review contract documentation in
/contracts/src/