A production-ready, multi-tier decentralized lottery system built on Ethereum and BNB Chain with Chainlink VRF for provably fair randomness.
- Overview
- Features
- Architecture
- Lottery Tiers
- Prize Distribution
- Quick Start
- Deployment
- Configuration
- API Reference
- Smart Contract
- Security
- Contributing
- License
The Lottery Platform is a decentralized, transparent lottery system featuring:
- Three lottery tiers (Small, Medium, Large) with different draw frequencies
- Chainlink VRF for verifiable random number generation
- Upgradeable smart contracts using OpenZeppelin UUPS proxy pattern
- Multi-chain support for Ethereum and BNB Chain
- Manual prize claiming - Winners claim their prizes (they pay gas)
- Automated draw triggering via dedicated drawer wallet
- Transparency - All lottery logic is on-chain and verifiable
- Fairness - Chainlink VRF ensures provably random winner selection
- Security - Auditable code with comprehensive access controls
- Simplicity - Clean architecture with minimal complexity
- 🎫 Purchase tickets in multiples of the ticket price (0.01 ETH/BNB)
- 💸 Withdraw tickets anytime before sales close
- 🏆 Automatic notification when you win
- 💰 Claim prizes at your convenience (you pay the gas)
- 📊 View statistics and history
- ⚙️ Configure ticket prices, limits, and intervals
- 🚫 Blacklist malicious wallets
- ⏸️ Pause/unpause pots or entire platform
- 🚨 Emergency withdrawal capabilities
- 💵 Withdraw accumulated platform fees
- 🔄 Upgradeable smart contracts (no migration needed)
- 🎲 Single VRF call for multiple winners (gas efficient)
- 📡 Real-time event-driven updates
- 🔒 Role-based access control (Admin, Drawer)
- 📦 In-memory cache (no external database)
┌─────────────────────────────────────────────────────────────────────────────┐
│ LOTTERY PLATFORM │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────────────┐ │
│ │ Frontend │───▶│ Backend │───▶│ Smart Contract (Blockchain)│ │
│ │ (React) │ │ (Express) │ │ (Source of Truth) │ │
│ └──────────────┘ └──────────────┘ └──────────────────────────────┘ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌──────────────┐ │ │
│ │ │ In-Memory │ ◀───────────────┘ │
│ │ │ Cache │ (Event Listener) │
│ │ └──────────────┘ │
│ │ │ │
│ └───────────────────┘ │
│ (API Calls) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
| Component | Responsibility |
|---|---|
| Smart Contract | All business logic, state storage, winner selection |
| Backend | Event listening, caching, draw scheduling, API |
| Frontend | User interface, wallet connection, transaction submission |
- Blockchain is the database - No external database required
- Backend is optional - Frontend can read directly from blockchain
- Manual prize claiming - Winners initiate withdrawals (they pay gas)
- Drawer wallet - Dedicated wallet for automated draw triggering
| Feature | Small Pot | Medium Pot | Large Pot |
|---|---|---|---|
| Draw Frequency | Daily (24h) | Weekly (7d) | Monthly (30d) |
| Number of Winners | 1 | 3 | 11 |
| Min Participants | 5 | 20 | 100 |
| Max Participants | 100 | 1,000 | 10,000 |
| Max Tickets/Wallet | 10 | 50 | 100 |
| Sales Close Before Draw | 1 hour | 1 day | 1 day |
| Ticket Price | 0.01 ETH/BNB | 0.01 ETH/BNB | 0.01 ETH/BNB |
- 3% of the total prize pool is taken as platform fee
- Fee is only deducted after the draw, not on deposits/withdrawals
| Place | Percentage |
|---|---|
| 1st | 100% |
| Place | Percentage |
|---|---|
| 1st | 60% |
| 2nd | 25% |
| 3rd | 15% |
| Level | Winners | Each Gets |
|---|---|---|
| Level 1 | 1 | 50% |
| Level 2 | 2 | 10% each |
| Level 3 | 4 | 5% each |
| Level 4 | 4 | 2.5% each |
- Node.js >= 18.0.0
- npm or yarn
- Git
# Clone the repository
git clone https://github.com/your-username/lottery-platform.git
cd lottery-platform
# Install all dependencies
npm run install:all
# Copy environment file
cp .env.example .env
# Edit .env with your configuration# Terminal 1: Start local blockchain
npm run node
# Terminal 2: Deploy contracts
npm run deploy:local
# Terminal 3: Start backend
npm run backend:dev
# Terminal 4: Start frontend
npm run frontend:dev# Run all tests
npm test
# Run with gas report
npm run test:gas
# Run with coverage
npm run test:coverage-
Configure environment variables
# .env DEPLOYER_PRIVATE_KEY=your_private_key VRF_SUBSCRIPTION_ID=your_subscription_id -
Deploy contracts
# Sepolia npm run deploy:sepolia # BSC Testnet npm run deploy:bsc-testnet
-
Add contract as VRF consumer
- Go to vrf.chain.link
- Add the proxy address as a consumer
-
Verify contracts
npm run verify:sepolia # or npm run verify:bsc-testnet
# Ethereum Mainnet
npm run deploy:mainnet
# BNB Chain Mainnet
npm run deploy:bsc| Variable | Description | Required |
|---|---|---|
DEPLOYER_PRIVATE_KEY |
Private key for contract deployment | Yes |
DRAWER_PRIVATE_KEY |
Private key for draw triggering | Yes |
VRF_SUBSCRIPTION_ID |
Chainlink VRF subscription ID | Yes |
RPC_URL |
Blockchain RPC endpoint | Yes |
CONTRACT_ADDRESS |
Deployed contract address | Auto |
ETHERSCAN_API_KEY |
For contract verification | No |
BSCSCAN_API_KEY |
For contract verification | No |
Edit backend/src/config/config.json to modify:
- Ticket prices
- Participant limits
- Draw intervals
- Prize distributions
| Endpoint | Method | Description |
|---|---|---|
/api/lottery/rounds |
GET | Get all current rounds |
/api/lottery/round/:potType |
GET | Get specific pot round |
/api/lottery/configs |
GET | Get all pot configurations |
/api/lottery/stats |
GET | Get platform statistics |
/api/lottery/winners |
GET | Get recent winners |
/api/lottery/wallet/:address |
GET | Get wallet information |
/api/lottery/health |
GET | Health check |
| Endpoint | Method | Description |
|---|---|---|
/api/admin/status |
GET | Get system status |
/api/admin/draw-status |
GET | Check draw eligibility |
/api/admin/trigger-draw |
POST | Manually trigger draw |
/api/admin/drawer |
GET | Get drawer wallet info |
{
"success": true,
"data": {
"small": {
"roundId": 5,
"state": "OPEN",
"participantCount": 23,
"totalDepositsFormatted": "0.45",
"timeUntilDraw": 43200
}
},
"timestamp": 1711900000000
}// Purchase tickets (amount must be multiple of ticket price)
function deposit(PotType _potType) external payable;
// Withdraw tickets (before sales close)
function withdraw(PotType _potType, uint256 _ticketCount) external;
// Claim winnings
function claimPrize() external;
// Claim specific round prize
function claimRoundPrize(PotType _potType, uint256 _roundId) external;// Close sales for a round
function closeSales(PotType _potType) external;
// Trigger draw (requests VRF randomness)
function triggerDraw(PotType _potType) external;// Set drawer wallet
function setDrawer(address _drawer) external;
// Update pot configuration
function updatePotConfig(...) external;
// Update platform fee
function updatePlatformFee(uint256 _newFeePercent) external;
// Pause/unpause
function pause() external;
function unpause() external;
// Blacklist wallet
function setBlacklisted(address _wallet, bool _isBlacklisted) external;
// Emergency functions
function emergencyWithdraw(address _wallet, PotType _potType) external;
function emergencyWithdrawAll() external;
// Withdraw platform fees
function withdrawPlatformFees() external;event TicketsPurchased(address wallet, PotType potType, uint256 roundId, uint256 amount, uint256 ticketCount, uint256 totalTickets, uint256 timestamp);
event TicketsWithdrawn(address wallet, PotType potType, uint256 roundId, uint256 amount, uint256 ticketCount, uint256 remainingTickets, uint256 timestamp);
event RoundStarted(PotType potType, uint256 roundId, uint256 startTime, uint256 drawTime, uint256 salesCloseTime);
event SalesClosed(PotType potType, uint256 roundId, uint256 totalDeposits, uint256 participantCount);
event DrawInitiated(PotType potType, uint256 roundId, uint256 vrfRequestId);
event WinnersSelected(PotType potType, uint256 roundId, uint256 winnerCount, uint256 totalPrizePool, uint256 platformFee);
event PrizeClaimed(address wallet, PotType potType, uint256 roundId, uint256 amount, uint8 level);
event RoundCancelled(PotType potType, uint256 roundId, string reason);- ReentrancyGuard - Prevents reentrancy attacks
- Pausable - Emergency stop mechanism
- AccessControl - Role-based permissions
- UUPS Upgradeable - Secure upgrade pattern
- Blacklist - Block malicious wallets
| Role | Permissions |
|---|---|
| ADMIN_ROLE | Full administrative control, upgrades |
| DRAWER_ROLE | Only trigger draws |
Before mainnet deployment:
- Professional security audit
- Formal verification
- Bug bounty program
- Multi-sig admin wallet
lottery-platform/
├── contracts/ # Solidity smart contracts
│ ├── LotteryPlatform.sol # Main contract
│ ├── interfaces/ # Contract interfaces
│ └── mocks/ # Test mocks (VRF)
├── backend/ # Node.js backend
│ └── src/
│ ├── config/ # Configuration
│ ├── services/ # Business logic
│ ├── routes/ # API routes
│ └── utils/ # Utilities
├── frontend/ # React frontend
│ └── src/
│ ├── components/ # React components
│ ├── hooks/ # Custom hooks
│ ├── pages/ # Page components
│ └── config/ # Frontend config
├── scripts/ # Deployment scripts
├── test/ # Test files
├── docs/ # Documentation
├── docker/ # Docker configuration
└── deployments/ # Deployment addresses
Additional documentation available in /docs:
- DEPLOYMENT.md - Detailed deployment guide
- CHAINLINK_VRF_GUIDE.md - VRF setup instructions
- USER_GUIDE.md - End-user documentation
- ADMIN_GUIDE.md - Administrator guide
- DEVELOPER_GUIDE.md - Developer documentation
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- OpenZeppelin - Smart contract libraries
- Chainlink - VRF oracle
- Hardhat - Development environment
- ethers.js - Ethereum library
This software is provided "as is" without warranty of any kind. Use at your own risk. Always conduct thorough testing and security audits before deploying to mainnet with real funds.
Made with ❤️ by the Lottery Platform Team