19 KiB
Blockchain Hybrid Architecture - Implementation Summary
Overview
This document summarizes the blockchain integration prototype created for the H2H betting platform. The implementation demonstrates a hybrid architecture where critical escrow and settlement operations occur on-chain for trustlessness, while maintaining fast queries through database caching.
What Has Been Built
Phase 1: Smart Contract Architecture ✅ COMPLETE
Location: backend/app/blockchain/contracts/
-
BetEscrow.pseudocode.md - Core betting smart contract
- Bet creation (no funds locked yet)
- Atomic escrow locking when bet accepted
- Oracle-based automatic settlement
- Manual settlement fallback
- Dispute mechanism with 48-hour window
- State machine: OPEN → MATCHED → PENDING_ORACLE → COMPLETED
-
BetOracle.pseudocode.md - Decentralized oracle network
- Multi-node consensus (3 of 5 nodes must agree)
- Cryptographic signature verification
- API adapters for sports/entertainment/politics
- Timeout and dispute handling
-
README.md - Complete architecture documentation
- System diagrams
- Data flow charts
- Integration points
- Security model
- Gas optimization strategies
Phase 2: Backend Blockchain Services ✅ COMPLETE
Location: backend/app/blockchain/services/
-
blockchain_service.py - Web3 Integration Layer
# Core functions: - create_bet_on_chain() # Create bet on blockchain - prepare_accept_bet_transaction() # Prepare tx for user signing - request_settlement() # Trigger oracle network - settle_bet_via_oracle() # Submit oracle consensus - get_bet_from_chain() # Fetch on-chain state - get_user_escrow() # Get locked funds - estimate_gas() # Calculate tx costs -
blockchain_indexer.py - Event Sync Service
# Functionality: - Polls blockchain every 10 seconds for new blocks - Indexes BetCreated, BetMatched, BetSettled, BetDisputed events - Syncs on-chain state to PostgreSQL database - Maintains fast queries while using blockchain as source of truth - Background worker process -
oracle_node.py - Decentralized Oracle Node
# Functionality: - Listens for OracleRequested events - Fetches data from external APIs (ESPN, Oscars, etc.) - Maps API results to bet winners - Signs results cryptographically - Submits to aggregator - Multiple independent nodes for decentralization -
oracle_aggregator.py - Consensus Coordinator
# Functionality: - Collects submissions from all oracle nodes - Verifies cryptographic signatures - Counts votes for each winner - Achieves 3/5 consensus threshold - Submits final result to blockchain - Handles disputes and timeouts -
config.py - Blockchain Configuration
- RPC endpoints (Ethereum, Polygon, Sepolia)
- Contract addresses per network
- Oracle node addresses
- Gas settings
- API endpoints
Phase 3: Frontend Web3 Integration ⚡ IN PROGRESS
Location: frontend/src/blockchain/
Hooks Created:
-
hooks/useWeb3Wallet.ts - MetaMask Connection
// Features: - Connect/disconnect wallet - Listen for account changes - Listen for network changes - Link wallet address to backend - Network switching -
hooks/useBlockchainBet.ts - Transaction Management
// Functions: - createBet() // Create bet on-chain - acceptBet() // Accept bet (user signs with MetaMask) - settleBet() // Request oracle settlement // State: - txStatus // Transaction status tracking - isProcessing // Loading state -
hooks/useGasEstimate.ts - Gas Cost Estimation
// Provides: - gasLimit // Estimated gas units - gasPriceGwei // Current gas price - costEth // Total cost in ETH - costUsd // Total cost in USD - Real-time updates every 30 seconds
Components Created:
-
components/BlockchainBadge.tsx - On-Chain Indicator
// Variants: - Confirmed: Green badge with "On-Chain ⛓️" - Pending: Yellow badge with spinner - Failed: Red badge with error icon // Features: - Links to block explorer (Etherscan) - Compact mode for lists - Transaction hash display -
components/TransactionModal.tsx - Transaction Status
// States: - Pending: Waiting for wallet signature - Confirming: Transaction submitted, awaiting blocks - Success: Confirmed with explorer link - Error: Failed with retry button // Features: - Auto-close on success - Animated loading states - "Do not close" warning
Architecture Diagram
┌────────────────────────────────────────────────────────────┐
│ FRONTEND (React + TypeScript) │
│ │
│ useWeb3Wallet() ─────> Connect MetaMask │
│ useBlockchainBet() ──> Sign Transactions │
│ useGasEstimate() ────> Show Gas Costs │
│ │
│ <BlockchainBadge /> ─> "On-Chain ⛓️" indicator │
│ <TransactionModal />─> Transaction progress │
└─────────────────────────┬───────────────────────────────────┘
│ Web3 / MetaMask
↓
┌────────────────────────────────────────────────────────────┐
│ BLOCKCHAIN (Smart Contracts) │
│ │
│ BetEscrow Contract BetOracle Contract │
│ ├─ createBet() ├─ requestSettlement() │
│ ├─ acceptBet() ├─ submitOracleResponse() │
│ ├─ settleBet() └─ checkConsensus() │
│ └─ disputeBet() │
│ │
│ Escrow: Holds ETH/MATIC Oracle Nodes: 5 nodes │
└─────────────────────────┬───────────────────────────────────┘
│ Events Emitted
↓
┌────────────────────────────────────────────────────────────┐
│ BACKEND (FastAPI + Python) │
│ │
│ BlockchainService Oracle Aggregator │
│ ├─ Web3 provider ├─ Collect node votes │
│ ├─ Contract calls ├─ Verify consensus │
│ └─ Gas estimation └─ Submit to chain │
│ │
│ BlockchainIndexer Oracle Nodes (3-5) │
│ ├─ Poll blocks ├─ Fetch ESPN API │
│ ├─ Index events ├─ Sign results │
│ └─ Sync to DB └─ Submit to aggregator │
└─────────────────────────┬───────────────────────────────────┘
│ Database Sync
↓
┌────────────────────────────────────────────────────────────┐
│ POSTGRESQL DATABASE │
│ │
│ Cached bet data for fast queries │
│ + blockchain_bet_id │
│ + blockchain_tx_hash │
│ + blockchain_status │
└────────────────────────────────────────────────────────────┘
Complete Bet Lifecycle Example
1. Create Bet (Alice)
User fills out CreateBetModal
↓
useBlockchainBet.createBet()
↓
MetaMask popup: Sign transaction
↓
BetEscrow.createBet() on blockchain
↓
BetCreated event emitted
↓
BlockchainIndexer picks up event
↓
Database updated with blockchain_bet_id
↓
Bet appears in marketplace with "On-Chain ⛓️" badge
2. Accept Bet (Bob)
Bob clicks "Accept Bet"
↓
GasFeeEstimate shows: "~$2.00" (on Polygon)
↓
Bob confirms
↓
useBlockchainBet.acceptBet()
↓
MetaMask popup: Sign transaction with stake
↓
TransactionModal: "Confirming... Do not close"
↓
BetEscrow.acceptBet() locks funds for both parties
↓
BetMatched event emitted
↓
TransactionModal: "Success!" with Etherscan link
↓
BlockchainIndexer syncs to database
↓
Both users see bet status: "Matched ⛓️"
↓
Escrow locked: Alice $100, Bob $100
3. Oracle Settlement (Automatic)
Real-world event ends (Super Bowl)
↓
BetEscrow.requestSettlement()
↓
OracleRequested event emitted
↓
5 Oracle Nodes:
Node 1: Fetch ESPN API → "49ers won" → Sign → Submit
Node 2: Fetch ESPN API → "49ers won" → Sign → Submit
Node 3: Fetch ESPN API → "49ers won" → Sign → Submit
Node 4: Fetch ESPN API → "49ers won" → Sign → Submit
Node 5: Fetch ESPN API → "49ers won" → Sign → Submit
↓
OracleAggregator:
- 5/5 nodes agree on "49ers won"
- Maps to Alice's address (she bet on 49ers)
- Consensus achieved (5 >= 3 threshold)
↓
BetOracle.fulfillSettlement(winner=Alice)
↓
BetEscrow.settleBet() transfers $200 to Alice
↓
BetSettled event emitted
↓
BlockchainIndexer updates database
↓
Alice's wallet: +$200 ETH
Bob's wallet: -$100 (lost from escrow)
↓
Frontend shows: "Completed ⛓️"
Visual UI Indicators
Where Blockchain Badges Appear:
-
Marketplace (BetCard)
┌─────────────────────────────────────┐ │ Super Bowl LVIII Winner │ │ ┌────────┐ ┌─────────────────────┐ │ │ │ MATCHED│ │ On-Chain ⛓️ │ │ │ └────────┘ └─────────────────────┘ │ │ Sports • $100 • 1.5x / 2x │ │ │ │ [View Details] │ └─────────────────────────────────────┘ -
Bet Details Page
Bet Details: Super Bowl LVIII Winner Status: MATCHED [On-Chain ⛓️] [View on Etherscan ↗] Escrow: $200 locked in smart contract -
Wallet Page
Wallet Balance ────────────────────────────────────── Available Balance: $725.00 Locked in Escrow: $175.00 [On-Chain ⛓️] Total: $900.00 On-Chain Escrow Details: - 2 active bets - Smart contract: 0x1234...
Transaction Flow Example:
User clicks "Accept Bet - $100"
↓
┌──────────────────────────────────────┐
│ Gas Fee Estimate │
├──────────────────────────────────────┤
│ Estimated Gas: 180,000 units │
│ Gas Price: 50 gwei │
│ │
│ Total Cost: 0.009 ETH ≈ $18.00 │
│ │
│ [Cancel] [Confirm] │
└──────────────────────────────────────┘
↓ User clicks Confirm
↓
┌──────────────────────────────────────┐
│ MetaMask popup appears │
│ "Confirm transaction in wallet..." │
└──────────────────────────────────────┘
↓ User signs in MetaMask
↓
┌──────────────────────────────────────┐
│ 🔄 Confirming Transaction │
│ │
│ Your transaction is being processed │
│ on the blockchain │
│ │
│ [Spinner animation] │
│ │
│ View on Etherscan ↗ │
│ │
│ Do not close this window │
└──────────────────────────────────────┘
↓ Wait 10-30 seconds
↓
┌──────────────────────────────────────┐
│ ✓ Transaction Confirmed! │
│ │
│ Your bet has been accepted │
│ │
│ TX: 0xabc123... │
│ View on Block Explorer ↗ │
│ │
│ [Close] │
└──────────────────────────────────────┘
File Structure
h2h-prototype/
├── backend/
│ └── app/
│ └── blockchain/
│ ├── __init__.py
│ ├── config.py [✅ DONE]
│ ├── contracts/
│ │ ├── BetEscrow.pseudocode.md [✅ DONE]
│ │ ├── BetOracle.pseudocode.md [✅ DONE]
│ │ └── README.md [✅ DONE]
│ └── services/
│ ├── __init__.py [✅ DONE]
│ ├── blockchain_service.py [✅ DONE]
│ ├── blockchain_indexer.py [✅ DONE]
│ ├── oracle_node.py [✅ DONE]
│ └── oracle_aggregator.py [✅ DONE]
│
└── frontend/
└── src/
└── blockchain/
├── hooks/
│ ├── useWeb3Wallet.ts [✅ DONE]
│ ├── useBlockchainBet.ts [✅ DONE]
│ └── useGasEstimate.ts [✅ DONE]
├── components/
│ ├── BlockchainBadge.tsx [✅ DONE]
│ ├── TransactionModal.tsx [✅ DONE]
│ ├── GasFeeEstimate.tsx [⏳ TODO]
│ ├── Web3WalletButton.tsx [⏳ TODO]
│ └── WalletBalanceBlockchain.tsx [⏳ TODO]
└── config/
└── contracts.ts [⏳ TODO]
Remaining Work
Phase 3 (Continued):
- Create GasFeeEstimate.tsx component
- Create Web3WalletButton.tsx component
- Create WalletBalanceBlockchain.tsx component
- Create contracts.ts configuration
Phase 4:
- Modify BetCard.tsx to add
- Modify CreateBetModal.tsx to add transaction flow
- Modify BetDetail.tsx to add gas estimate
- Modify WalletBalance.tsx to show on-chain escrow
- Modify Header.tsx to add wallet connect button
Phase 5:
- Update Bet model to add blockchain fields:
- blockchain_bet_id: int | None
- blockchain_tx_hash: str | None
- blockchain_status: str | None
- Create database migration
Key Design Decisions
Hybrid vs Pure On-Chain
| Aspect | On-Chain (Blockchain) | Off-Chain (Database) |
|---|---|---|
| Escrow funds | ✅ Smart contract holds ETH | ❌ |
| Bet status | ✅ Source of truth | ✅ Cached for speed |
| Settlement | ✅ Oracle-based | ❌ |
| User auth | ❌ | ✅ JWT tokens |
| Bet metadata | ❌ | ✅ Title, description |
| Search/filters | ❌ Too slow | ✅ PostgreSQL |
| Notifications | ❌ | ✅ WebSocket |
Rationale: Blockchain for trustlessness, database for performance.
Oracle Consensus
- Nodes: 5 independent servers
- Threshold: 3 of 5 must agree
- APIs: ESPN, Oscars, Election APIs
- Fallback: Manual settlement after 24 hours
- Dispute: 48-hour window for participants
Gas Optimization
- Layer 2: Deploy on Polygon for 90% lower fees
- Ethereum: ~$18 per bet acceptance
- Polygon: ~$2 per bet acceptance
- Batch Operations: Future enhancement
- Meta-Transactions: Backend pays gas (EIP-2771)
Security Considerations
-
Smart Contract
- Reentrancy guards
- Role-based access control
- Atomic transactions
- Security audit required before mainnet
-
Oracle Network
- Multi-node consensus (3/5)
- Cryptographic signatures
- Timeout handling
- Admin override for edge cases
-
Frontend
- Never expose private keys
- Verify contract addresses
- Show gas estimates before transactions
- Warn users about network fees
Next Steps
- Complete remaining frontend components
- Update database models with blockchain fields
- Integrate blockchain badges into existing UI
- Test on Sepolia testnet
- Security audit
- Deploy to Polygon mainnet
References
- Smart Contract Architecture:
backend/app/blockchain/contracts/README.md - Backend Services:
backend/app/blockchain/services/ - Frontend Integration:
frontend/src/blockchain/ - Implementation Plan:
/Users/liamdeez/.claude/plans/whimsical-napping-sedgewick.md
Status: Phase 1 ✅ Complete | Phase 2 ✅ Complete | Phase 3 ⚡ 75% Complete | Phase 4 ⏳ Pending | Phase 5 ⏳ Pending