DUBS V2: Pool-Based Betting Protocol
Whitepaper v1.0 | January 2025Table of Contents
- Introduction
- System Overview
- Core Concepts
- Account Architecture
- Game Lifecycle
- Fee Structure
- Payout Mechanics
- Sponsored Betting
- Emergency Mechanisms
- Edge Cases
- Security Model
- Technical Specifications
1. Introduction
DUBS V2 is a decentralized pool-based (pari-mutuel) betting protocol built on Solana. It enables trustless, transparent wagering on sports events with automatic, proportional payouts to winners.1.1 Design Philosophy
- Trustless: No custody of funds by operators; all funds held in program-derived accounts
- Transparent: All pool sizes, stakes, and payouts verifiable on-chain
- Scalable: Position PDA architecture supports unlimited participants per game
- Fair: Proportional payouts ensure mathematical fairness regardless of pool imbalance
- Resilient: Multiple emergency mechanisms prevent permanent fund lockup
1.2 Key Features
2. System Overview
2.1 Participants
Player
Stakes SOL, claims payouts, wins or loses based on outcomes
Operator
Creates games, earns 4-5% fee
Oracle
Resolves game outcomes, earns 1% fee
Referrer
Brings players, earns 1% commission
Sponsor
Funds bets on behalf of players
Authority
Emergency controls and overrides
2.2 How It Works
1
Game Creation
Operator creates a game for a sports event with a lock time
2
Betting Period
Players stake SOL on Home, Away, or Draw outcomes
3
Lock
At lock time, no more bets accepted
4
Resolution
Oracle reports the winning outcome
5
Claims
Winners claim proportional share of the pool
3. Core Concepts
3.1 Pari-Mutuel Betting
Unlike fixed-odds betting where payouts are determined at bet time, pari-mutuel systems pool all stakes together. Winners share the pool proportionally based on their stake in the winning outcome.Example Calculation
Example Calculation
3.2 Implied Odds
The pool ratios create dynamic, market-driven odds:3.3 Position PDAs
Each playerโs stake is recorded in a unique Program Derived Address (PDA):- Enables unlimited participants per game
- Prevents vector growth attacks
- Allows parallel claim processing
- Provides clear ownership verification
4. Account Architecture
4.1 GameV2 Account
The central game account holding all pool funds and state.4.2 Position Account
Individual player stake record.4.3 Outcome Enum
5. Game Lifecycle
5.1 State Machine
5.2 Instructions
initialize_automatic_game_v2
initialize_automatic_game_v2
Creates a new game.Parameters:
game_id: u64- Unique identifierlock_timestamp: i64- When betting closes (must be โฅ2 minutes in future)sports_event_id: String- External event reference
- Lock time must be at least 2 minutes in the future
- Game ID must not already exist
stake_automatic_game
stake_automatic_game
Player places a bet.Parameters:
game_id: u64- Game to bet onoutcome: Outcome- Home, Away, or Drawamount: u64- Stake in lamports
- Transfers
amountfrom player to game account - Creates Position PDA for player
- Updates pool_totals and total_pool
- Increments position_count
- Game not locked or resolved
- Amount > 0
- Valid outcome (0, 1, or 2)
stake_automatic_game_sponsored
stake_automatic_game_sponsored
Sponsor funds a bet on behalf of a player.Parameters: Same as
stake_automatic_gameKey Difference:- Funds come from sponsor wallet, not player
- Position.sponsor is set
- On refund, funds return to sponsor (not player)
- Player still claims winnings if they win
resolve_automatic_game_v2
resolve_automatic_game_v2
Oracle resolves the game outcome.Parameters:
game_id: u64- Game to resolvewinning_outcome: Option<Outcome>- Winner, or None for refund
- Calculates and transfers fees
- Sets winning_outcome and net_pool
- Marks game as resolved
- Caller must be the designated oracle
- Game must be locked (or past lock time)
- Game not already resolved
claim_automatic_winnings_v2
claim_automatic_winnings_v2
Player claims their payout.Parameters:
game_id: u64- Game to claim from
- Calculates payout based on outcome
- Transfers payout from game to player (or sponsor for refunds)
- Marks position as claimed
- Winner: Proportional share of net_pool based on stake in winning pool
- Loser: 0 (position still marked claimed)
- Refund: Proportional share based on stake in total pool
emergency_refund_v2
emergency_refund_v2
Permissionless emergency refund after 24 hours.Parameters:
game_id: u64- Game to refund
- Game is locked but not resolved
- At least 24 hours have passed since lock time
- Sets winning_outcome = None (refund all)
- No fees collected
- All players can claim full refund
6. Fee Structure
6.1 Fee Breakdown
Total fee is 6% of the distributable pool (pool minus rent reserve).6.2 Fee Calculation
6.3 Rent-First Economics
Fees are calculated on the distributable amount, not total pool:7. Payout Mechanics
7.1 Winner Payout Formula
Winner Example
Winner Example
7.2 Refund Payout Formula
When winning_outcome = None (tie, cancellation, or emergency):- Normal Refund
- Emergency Refund
Fees collected (6%)
7.3 Remainder Handling
Due to integer division, small remainders may accumulate in the game account. These are not distributed and remain in the account after all claims.8. Sponsored Betting
8.1 Overview
Sponsors can fund bets on behalf of players, enabling:- Promotional free bets
- Onboarding campaigns
- Treasury-funded engagement
8.2 Mechanics
8.3 Refund Routing
9. Emergency Mechanisms
9.1 Oracle Failure Protection
If the oracle fails to resolve a game, funds are not locked forever.9.2 Authority Override
The program authority can trigger an emergency refund at any time. Use Cases:- Event cancellation before lock time
- Detected irregularities
- Oracle key compromise
- Any situation requiring immediate intervention
- No fees collected
- All players receive full refund
- Works even if game isnโt locked yet
9.3 Emergency Refund Comparison
10. Edge Cases
10.1 Single-Sided Pool
If all stakes are on one outcome (e.g., everyone bet Home): Problem: Winners would just get their money back (no profit) Solution: Auto-resolve to refund mode- winning_outcome = None
- Everyone gets proportional refund
- Fees still collected (normal refund)
10.2 Empty Winning Pool
If oracle selects a winner but no one bet on that outcome: Problem: Division by zero in payout calculation Solution: Auto-resolve to refund mode- Same as single-sided pool
- Detected at resolution time
10.3 Zero Stakes Game
If a game is resolved with no positions: Handling:- Game resolves normally
- No payouts to process
- Rent remains in account
10.4 Dust Amounts
Very small stakes may result in 0 payout due to integer division:11. Security Model
11.1 Trust Assumptions
11.2 Attack Mitigations
Double Claiming
Double Claiming
- Position.claimed flag prevents re-entry
- Checked before any transfer
Oracle Manipulation
Oracle Manipulation
- Hardcoded oracle address
- Cannot be changed per-game
- Authority can override via emergency refund
Front-Running
Front-Running
- Lock time prevents last-second stakes
- Pool totals visible on-chain (transparent)
Rent Drain
Rent Drain
- Rent reserved before fee calculation
- Account cannot go below rent-exempt minimum
Overflow/Underflow
Overflow/Underflow
- All arithmetic uses checked operations
- Errors returned on overflow
11.3 PDA Security
Game PDAs:- Seeds include game_id (unique per game)
- Cannot be forged without program signature
- Seeds include player pubkey
- One position per player per game enforced
- Cannot claim another playerโs position
12. Technical Specifications
12.1 Program Constants
12.2 Hardcoded Addresses
12.3 Account Sizes
12.4 Program ID
Appendix A: Example Game Flow
Scenario: NBA Game - Lakers vs Celtics
1
Game Creation
2
Betting Period
3
Lock
Game locks at 7:00 PM. No more bets accepted.
4
Resolution
Lakers win! Oracle calls resolve with outcome = Home
5
Claims
Appendix B: Comparison with V1
Appendix C: Glossary
Document Version: 1.0 Last Updated: January 2025 Program Version: V2
