Project · Gold

Crypto Millions

The alchemist's prize — a lottery that proves it cannot cheat you.

Essence

For the people who play it

Crypto Millions is a decentralized lottery on Ethereum. Pick six unique numbers from one to thirty-nine. Buy a ticket with stablecoin USDC. Each ticket you buy is an NFT — a proper ERC-721 token, transferable, inspectable, yours on chain. Every seven days, Chainlink VRF draws six winning numbers and a Chainlink Keeper triggers the draw automatically. Winners claim their prize themselves; unclaimed prizes roll into the next jackpot.

The point is to remove trust. A traditional lottery asks you to take the operator's word that the draw was honest, the books are right and the prize will be paid. Crypto Millions removes the operator: the contract is the operator, the randomness is provably fair (Chainlink VRF publishes the proof), the prize pool is visible on chain, and the rules cannot be quietly changed behind a closed door.

Three prize tiers reward six, five and four matches. The jackpot grows from 95% of ticket revenue. Tickets are NFTs you actually own — keep them, transfer them, sell them, prove them.

Visit Crypto Millions Test environment · Sepolia testnet

Construction

For the engineers

Stack

Smart contracts
Solidity ^0.8.4 · Hardhat · viaIR + 200 optimization runs
Token standards
ERC-20 (USDC stablecoin) · ERC-721 + ERC-721URIStorage (tickets)
Randomness
Chainlink VRF v2.5 via VRFConsumerBaseV2Upgradeable
Automation
Chainlink Automation via AutomationCompatibleInterface
Upgrades
OpenZeppelin UUPS proxy pattern across all four contracts
Security
ReentrancyGuard · SafeERC20 for non-standard token transfer returns
Frontend
React 18 · TypeScript · ethers.js v5 · web3-react · Tailwind CSS
Error tracking
Sentry with sourcemap injection in production
Network
Ethereum Sepolia testnet (chain id 11155111)

Architecture

Three contracts separated by concern. CryptoMillions.sol holds the core lottery logic — ticket purchase, draw initiation, prize claim. CryptoMillionsDrawManager.sol isolates draw state, history and VRF request tracking so the main contract stays focused on user flow. CryptoMillionsNFT.sol mints the ERC-721 tickets with deterministic URI metadata. A fourth CryptoMillionsUtils contract holds the pure functions — number generation, match counting, sorting — so they can be tested in isolation and reused.

UUPS upgradeable everywhere. All four contracts use OpenZeppelin's UUPS proxy pattern. Storage layout follows the compatibility guidelines so upgrades do not corrupt existing tickets or prize pools. The proxy admin is the only point that can authorise an upgrade.

Async randomness with a graceful state machine. When a draw fires the contract requests randomness from Chainlink VRF and transitions DrawState to Drawing. When the VRF callback arrives (fulfillRandomWords), the utils contract generates six winning numbers, the draw manager records them, and the state returns to Pending for the next round. Players cannot buy tickets during the Drawing window — no race between purchase and reveal.

Pull-based payouts. Winners call claimReward(ticketId) themselves rather than the contract pushing prizes out. This is cheaper and safer: one greedy winner cannot DOS the payout loop, gas spikes are absorbed by the winner, and unclaimed prizes (30-day window) roll into the next jackpot automatically.

Provider-aware frontend. React contexts split concerns — WalletContext for connection state, DrawContext for draw history, TicketContext for the user's tickets, TransactionContext as a transaction-state machine. ethers.js v5 talks to the contracts, web3-react manages the MetaMask connector, and Sentry catches any frontend error with sourcemaps injected at build time.

Notable details