diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..613bebb --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,147 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +**LottoLink** is a unified lottery infrastructure built on: +- **Flare Network (Coston2 testnet)** - Data Truth Layer for provably fair draws using Secure RNG, FTSO price feeds, and FDC for external lottery attestation +- **Plasma Network** - Money Movement Layer for instant zero-fee USDT payouts via EIP-3009 gasless transfers + +## Architecture + +### Multi-Package Monorepo Structure +``` +lottolink/ +├── contracts/ # Solidity smart contracts (Hardhat) +├── backend/ # Node.js + Express API with blockchain event listeners +├── frontend/ # Next.js 14 + Tailwind UI +└── package.json # Root scripts for unified commands +``` + +### Contract Architecture (contracts/flare/) +The contracts are split across two networks: + +**Flare Contracts (Coston2 testnet)**: +- `DrawManager.sol` - Manages lottery draws using Flare's Secure RNG (`RandomNumberV2` at `0x97702e350CaEda540935d92aAf213307e9069784`) +- `PayoutCalculator.sol` - Calculates winnings and authorizes payouts +- `LotteryRegistry.sol` - Registry of available lotteries +- `ResultAttestor.sol` - Uses FDC JsonApi to attest external Web2 lottery results +- Interfaces: `IRandomNumberV2.sol`, `IFtsoV2.sol` (for USD↔USDT price feeds), `IFdcVerification.sol` + +**Plasma Contracts**: +- `LottoEscrow.sol` - Handles USDT deposits and gasless withdrawals using EIP-3009 + +Hardhat config uses `viaIR: true` optimizer setting for Solidity 0.8.25. Sources are in `./flare` directory (not standard `./contracts`). + +### Backend Architecture (backend/src/) +Express API with three core components: +- `index.ts` - Main server with REST endpoints and in-memory data store (use DB in production) +- `listeners/` - Blockchain event listeners for Flare (draws, payouts) and Plasma (ticket purchases) +- `services/plasma.ts` - Handles gasless USDT payout execution via EIP-3009 + +The backend listens to smart contract events and coordinates cross-chain actions (Flare draws trigger Plasma payouts). + +### Frontend Architecture (frontend/app/) +Next.js 14 App Router structure: +- Uses wagmi v2 + viem v2 for Web3 interactions +- Tailwind CSS for styling +- React Query (`@tanstack/react-query`) for data fetching + +## Development Commands + +### From Root Directory +```bash +npm run install:all # Install all dependencies across packages +npm run dev # Run backend + frontend concurrently +npm run build # Compile contracts, build backend & frontend +npm run contracts:compile # Compile Solidity contracts +npm run contracts:test # Run Hardhat tests +npm run contracts:deploy:flare # Deploy to Flare Coston2 +npm run contracts:deploy:plasma # Deploy to Plasma +``` + +### Individual Packages +```bash +# Contracts (from ./contracts) +npm run compile # Compile with Hardhat +npm test # Run all tests +npx hardhat test test/FileName.ts # Run specific test file +npx hardhat run scripts/deploy-flare.ts --network coston2 + +# Backend (from ./backend) +npm run dev # Run with ts-node +npm run build # Compile TypeScript +npm start # Run compiled code + +# Frontend (from ./frontend) +npm run dev # Next.js dev server on port 3000 +npm run build # Production build +npm start # Serve production build +``` + +## Environment Variables + +### Backend (.env in backend/) +```bash +DRAW_MANAGER_ADDRESS # Flare DrawManager contract address +PAYOUT_CALC_ADDRESS # PayoutCalculator contract address +ESCROW_ADDRESS # Plasma LottoEscrow contract address +ESCROW_PRIVATE_KEY # Private key for signing gasless payouts +USDT_ADDRESS # Plasma USDT token (default: 0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb) +PORT # API port (default: 3001) +``` + +### Contracts (.env in contracts/) +```bash +PRIVATE_KEY # Deployment account private key +PLASMA_RPC_URL # Plasma RPC endpoint (default: https://rpc.plasma.to) +``` + +## Network Configuration + +| Network | Chain ID | RPC URL | +|---------|----------|---------| +| Flare Coston2 (testnet) | 114 | https://coston2-api.flare.network/ext/C/rpc | +| Plasma | — | https://rpc.plasma.to | + +**Important Flare Contracts**: +- RandomNumberV2: `0x97702e350CaEda540935d92aAf213307e9069784` +- ContractRegistry: `0xaD67FE66660Fb8dFE9d6b1b4240d8650e30F6019` + +## Technology Stack + +| Component | Stack | +|-----------|-------| +| Contracts | Solidity 0.8.25, Hardhat, OpenZeppelin 5.0, TypeChain | +| Backend | Node.js, Express, TypeScript 5.3, ethers.js v6 | +| Frontend | Next.js 14, React 18, wagmi v2, viem v2, Tailwind 3.4 | + +All packages use TypeScript with ES2022 target and strict mode enabled. + +## Docker & CI/CD + +- `docker-compose.yml` orchestrates frontend (port 3000) and backend (port 4000) +- Individual Dockerfiles in `./backend` and `./frontend` +- GitHub Actions workflow (`.github/workflows/workflow.yml`) builds Docker images on push/PR to main branch + +## Key Integration Points + +### Flare-Specific Features +1. **Secure RNG**: DrawManager requests random numbers from `RandomNumberV2` with `isSecureRandom: true` flag +2. **FTSO Price Feeds**: USD to USDT conversion at settlement time via `IFtsoV2` interface +3. **FDC JsonApi**: ResultAttestor uses Flare Data Connector to attest external Web2 lottery results + +### Cross-Chain Flow +1. User buys ticket on Plasma (USDT deposit to LottoEscrow) +2. LottoEscrow emits event → backend listener records ticket +3. DrawManager on Flare requests RNG and conducts draw +4. PayoutCalculator determines winners → emits PayoutAuthorized event +5. Backend listener executes gasless USDT transfer on Plasma using EIP-3009 + +## Code Conventions + +- Use ethers v6 patterns (not v5): `provider.getBlock()` instead of `provider.getBlockNumber()` +- Prefer `async/await` over raw Promises +- Backend uses in-memory storage - replace with database for production +- Contracts follow OpenZeppelin 5.0 patterns (constructor-based initialization, no initializers unless upgradeable) diff --git a/PLAN.md b/PLAN.md new file mode 100644 index 0000000..dc60ea7 --- /dev/null +++ b/PLAN.md @@ -0,0 +1,382 @@ +# LottoLink iBankroll POC - 5 Hour Hackathon Plan + +## Context + +**Problem:** 200+ US lottery operators hold massive reserves to back jackpots. This locks up funds that should go to charitable causes. + +**Solution:** Shared liquidity pool (iBankroll model) where: +- LPs deposit USDT → earn yield from operator premiums +- Operators pay premiums (% of ticket sales) → access to deep pool liquidity +- Small lotteries offer big jackpots without big reserves +- Pool absorbs variance across 200+ operators + +**Time Constraint:** 5 hours to build viable POC for hackathon demo + +--- + +## 5-Hour Sprint Breakdown + +### **Hour 1: Core Pool Contract** (60 min) +**Goal:** Build simplified `SharedLiquidityPool.sol` that proves the concept + +**File:** `contracts/flare/SharedLiquidityPool.sol` + +**Features:** +```solidity +// LP Functions +- depositLiquidity(uint256 usdtAmount) → mint ERC20 shares +- withdrawLiquidity(uint256 shares) → burn shares, return USDT +- getSharePrice() → calculate USDT value per share + +// Operator Functions +- collectPremium(address operator, uint256 amount) → operator pays into pool +- executePayout(address winner, uint256 amount) → pool pays winner + +// Stats +- getTVL() → total USDT in pool +- getUtilization() → % of pool backing active lotteries +- getLPYield(address lp) → claimable yield for LP +``` + +**Simplifications:** +- ❌ Skip complex premium calculations (just accept fixed %) +- ❌ Skip credit limits +- ❌ Skip withdrawal queues +- ❌ Skip operator accounting (just track basic stats) + +**Testing:** +```bash +cd contracts +npx hardhat test test/SharedLiquidityPool.test.ts +``` + +--- + +### **Hour 2: Wire Up Existing Contracts** (60 min) +**Goal:** Route payouts through pool instead of direct escrow + +**Files to Modify:** + +1. **`contracts/flare/PayoutCalculator.sol`** + ```solidity + // Add pool address in constructor + SharedLiquidityPool public pool; + + // In calculatePayouts(): + // Instead of emitting PayoutAuthorized, call: + pool.executePayout(winner, amount); + ``` + +2. **`contracts/flare/LotteryRegistry.sol`** + ```solidity + // Add field to Lottery struct: + uint256 premiumRate; // e.g., 500 = 5% + + // When operator registers lottery, they set premium rate + ``` + +3. **Deploy Script:** `contracts/scripts/deploy-pool.ts` + ```typescript + // Deploy SharedLiquidityPool with USDT address + // Deploy updated PayoutCalculator with pool address + // Deploy LotteryRegistry + ``` + +**Test Locally:** +```bash +npx hardhat node # Terminal 1 +npx hardhat run scripts/deploy-pool.ts --network localhost # Terminal 2 +``` + +--- + +### **Hour 3: Minimal Backend API** (60 min) +**Goal:** Expose pool stats to frontend + +**File:** `backend/src/routes/pool.ts` (NEW) + +**Endpoints:** +```typescript +GET /api/pool/stats +Response: { + tvl: "1000000", // Total USDT in pool + utilization: 0.45, // % of pool at risk + lpCount: 12, // Number of LPs + operatorCount: 5, // Number of operators + totalPremiums: "50000", // Cumulative premiums collected + totalPayouts: "30000" // Cumulative payouts distributed +} + +GET /api/pool/lp/:address +Response: { + shares: "10000", // LP's share balance + usdtValue: "11500", // Current USDT value of shares + claimableYield: "1500", // Yield earned + roi: 0.15 // 15% return +} +``` + +**File:** `backend/src/listeners/index.ts` (MODIFY) +```typescript +// Add listener for pool events +pool.on("LiquidityDeposited", (lp, amount) => { + console.log(`LP ${lp} deposited ${amount}`); +}); + +pool.on("PremiumCollected", (operator, amount) => { + console.log(`Operator ${operator} paid premium ${amount}`); +}); +``` + +**File:** `backend/src/index.ts` (MODIFY) +```typescript +// Import pool routes +import poolRoutes from "./routes/pool"; +app.use("/api/pool", poolRoutes); +``` + +**Test:** +```bash +cd backend +npm run dev +curl http://localhost:3001/api/pool/stats +``` + +--- + +### **Hour 4: Demo Frontend** (60 min) +**Goal:** Single page showing pool in action + +**File:** `frontend/app/pool/page.tsx` (NEW) + +**UI Components:** +1. **Pool Stats Card** + - TVL: $1,000,000 + - Utilization: 45% + - Current APY: 8.5% + - Number of LPs: 12 + - Number of Operators: 5 + +2. **LP Actions** + - "Deposit USDT" button → calls `pool.depositLiquidity()` + - "Withdraw" button → calls `pool.withdrawLiquidity()` + - Show user's LP position (shares, value, yield) + +3. **Operator Actions** + - "Pay Premium" button → calls `pool.collectPremium()` + - Show operator's total premiums paid + +4. **Recent Activity Feed** + - "Alice deposited $10,000" + - "Bob Lottery paid $500 premium" + - "Winner 0x123... received $5,000 payout from pool" + +**Styling:** Use existing Tailwind styles from `page.tsx` + +**Test:** +```bash +cd frontend +npm run dev +# Visit http://localhost:3000/pool +``` + +--- + +### **Hour 5: Deploy + Test + Demo Prep** (60 min) + +#### **Step 1: Deploy to Coston2** (20 min) +```bash +cd contracts +# Set .env with PRIVATE_KEY +npx hardhat run scripts/deploy-pool.ts --network coston2 + +# Note deployed addresses: +# SharedLiquidityPool: 0x... +# PayoutCalculator: 0x... +# LotteryRegistry: 0x... +``` + +#### **Step 2: Full Flow Test** (20 min) +```bash +# 1. LP deposits USDT into pool +npx hardhat console --network coston2 +> const pool = await ethers.getContractAt("SharedLiquidityPool", "0x...") +> await pool.depositLiquidity(ethers.parseUnits("10000", 6)) + +# 2. Operator registers lottery with 5% premium rate +> const registry = await ethers.getContractAt("LotteryRegistry", "0x...") +> await registry.registerLottery("Test Lottery", 5, 3600, 10, charityAddr, 49, 6, true, "", "", 500) + +# 3. Operator pays premium +> await pool.collectPremium(operatorAddr, ethers.parseUnits("500", 6)) + +# 4. Simulate draw and payout +> const draw = await drawManager.executeDraw(0) +> const payouts = await payoutCalc.calculatePayouts(0, 0, ethers.parseUnits("10000", 6)) +# Payout should come from pool! + +# 5. Check pool stats +> await pool.getTVL() // Should show 10000 + 500 - payout +``` + +#### **Step 3: Demo Prep** (20 min) + +**Demo Script:** + +1. **Show Problem (30 sec)** + - "200+ lottery operators in US hold $X billion in reserves" + - "Small charities can't compete because they can't bankroll big jackpots" + +2. **Show Solution (60 sec)** + - Open `/pool` page + - Point to TVL: "This is shared liquidity from LPs earning 8.5% yield" + - Point to operators: "5 small lotteries now have access to $1M in backing" + +3. **Live Demo (90 sec)** + - **Act as LP:** Click "Deposit $10,000" → show shares received + - **Act as Operator:** Click "Pay Premium $500" → show pool balance increase + - **Trigger Draw:** Run draw in console → show winner gets paid FROM POOL + - **Show LP Yield:** Point to claimable yield increasing + +4. **Flare Integration (30 sec)** + - "Uses Flare Secure RNG for provably fair draws" + - "Uses FDC to attest external lottery results" + - "Uses FTSO for USD price feeds" + - "Future: FAssets lets XRP/BTC holders become LPs" + +5. **Impact (30 sec)** + - "Unlocks $XM in trapped reserves" + - "Enables small charities to offer life-changing prizes" + - "LPs earn better yield than traditional DeFi" + +--- + +## What We're NOT Building (Out of Scope for 5 Hours) + +- ❌ Premium calculation engine (operators just pay fixed %) +- ❌ Operator credit limits +- ❌ LP withdrawal queues +- ❌ Advanced operator accounting +- ❌ Historical charts +- ❌ FAssets integration (USDT only) +- ❌ Separate operator/LP dashboards (one demo page) +- ❌ Mobile responsive design +- ❌ Error handling edge cases + +--- + +## Success Criteria for POC + +### Must Have (Demo Blockers): +✅ LP can deposit USDT and receive shares +✅ Operator can pay premium to pool +✅ Payout executes from pool (not operator wallet) +✅ Frontend shows pool TVL and stats +✅ Deployed to Coston2 and working + +### Nice to Have (If Time): +- LP can withdraw with yield +- Multiple operators in demo +- Activity feed showing transactions +- Prettier UI with Flare branding + +--- + +## Risk Mitigation + +### If Behind Schedule: + +**After Hour 2:** If contracts aren't deployed yet +- Use Hardhat console for demo instead of frontend +- Show contract interactions in terminal + +**After Hour 3:** If backend not ready +- Frontend can call contracts directly (skip API layer) +- Use wagmi hooks to read pool state + +**After Hour 4:** If frontend not done +- Demo using Hardhat console + backend API with curl +- Use Postman to show API responses + +--- + +## File Checklist + +### New Files to Create: +- [ ] `contracts/flare/SharedLiquidityPool.sol` ⭐ +- [ ] `contracts/test/SharedLiquidityPool.test.ts` +- [ ] `contracts/scripts/deploy-pool.ts` +- [ ] `backend/src/routes/pool.ts` +- [ ] `frontend/app/pool/page.tsx` + +### Files to Modify: +- [ ] `contracts/flare/PayoutCalculator.sol` (add pool integration) +- [ ] `contracts/flare/LotteryRegistry.sol` (add premium rate field) +- [ ] `backend/src/listeners/index.ts` (add pool events) +- [ ] `backend/src/index.ts` (add pool routes) +- [ ] `frontend/app/page.tsx` (add link to /pool) + +### Files to Leave Alone: +- ✅ `DrawManager.sol` (works as-is) +- ✅ `ResultAttestor.sol` (works as-is) +- ✅ `LottoEscrow.sol` (deprecated but don't delete) + +--- + +## Deployment Checklist + +```bash +# 1. Compile contracts +npm run contracts:compile + +# 2. Test contracts +cd contracts && npx hardhat test + +# 3. Deploy to Coston2 +npx hardhat run scripts/deploy-pool.ts --network coston2 + +# 4. Update backend .env with deployed addresses +POOL_ADDRESS=0x... +PAYOUT_CALC_ADDRESS=0x... +REGISTRY_ADDRESS=0x... + +# 5. Build backend +npm run backend:build + +# 6. Build frontend +npm run frontend:build + +# 7. Test full flow +# (See Hour 5 test steps above) +``` + +--- + +## Talking Points for Judges + +**Q: What's innovative here?** +A: We're applying the iBankroll model (proven in crypto casinos) to traditional lotteries. Instead of each operator holding idle reserves, they pool risk. Law of large numbers makes aggregate variance predictable. + +**Q: Why Flare?** +A: We need all four protocols: +- Secure RNG → provably fair draws +- FDC → attest external lottery results on-chain +- FTSO → USD price feeds for stable payouts +- FAssets → (future) XRP/BTC holders can become LPs + +**Q: What's the business model?** +A: Pool takes 10% of operator premiums. If operators pay 5% of ticket sales and pool earns $5M/year, protocol earns $500K while LPs earn $4.5M. + +**Q: How does this scale?** +A: More operators = more diversification = more stable returns. At 200+ operators, variance is extremely low. Pool becomes self-sustaining. + +**Q: Real-world adoption?** +A: State lotteries are regulated but can partner via licensed operators. Tribal gaming and charitable lotteries have more flexibility. Crypto-native lotteries can integrate immediately. + +--- + +## Next Immediate Step + +**START CODING:** Begin with `SharedLiquidityPool.sol` - this is the foundation everything else depends on. + +Ready to build when you are! 🚀