Skip to main content

DUBS V2: Pool-Based Betting Protocol

Whitepaper v1.0 | January 2025

Table of Contents

  1. Introduction
  2. System Overview
  3. Core Concepts
  4. Account Architecture
  5. Game Lifecycle
  6. Fee Structure
  7. Payout Mechanics
  8. Sponsored Betting
  9. Emergency Mechanisms
  10. Edge Cases
  11. Security Model
  12. 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.

3.2 Implied Odds

The pool ratios create dynamic, market-driven odds:
Example:

3.3 Position PDAs

Each playerโ€™s stake is recorded in a unique Program Derived Address (PDA):
This architecture:
  • 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.
PDA Derivation:
Account Size: ~250 bytes (fixed, no vectors)

4.2 Position Account

Individual player stake record.
PDA Derivation:
Account Size: ~140 bytes (fixed)

4.3 Outcome Enum


5. Game Lifecycle

5.1 State Machine

5.2 Instructions

Creates a new game.Parameters:
  • game_id: u64 - Unique identifier
  • lock_timestamp: i64 - When betting closes (must be โ‰ฅ2 minutes in future)
  • sports_event_id: String - External event reference
Validation:
  • Lock time must be at least 2 minutes in the future
  • Game ID must not already exist
Player places a bet.Parameters:
  • game_id: u64 - Game to bet on
  • outcome: Outcome - Home, Away, or Draw
  • amount: u64 - Stake in lamports
Effects:
  1. Transfers amount from player to game account
  2. Creates Position PDA for player
  3. Updates pool_totals and total_pool
  4. Increments position_count
Validation:
  • Game not locked or resolved
  • Amount > 0
  • Valid outcome (0, 1, or 2)
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
Oracle resolves the game outcome.Parameters:
  • game_id: u64 - Game to resolve
  • winning_outcome: Option<Outcome> - Winner, or None for refund
Effects:
  1. Calculates and transfers fees
  2. Sets winning_outcome and net_pool
  3. Marks game as resolved
Validation:
  • Caller must be the designated oracle
  • Game must be locked (or past lock time)
  • Game not already resolved
Player claims their payout.Parameters:
  • game_id: u64 - Game to claim from
Effects:
  1. Calculates payout based on outcome
  2. Transfers payout from game to player (or sponsor for refunds)
  3. Marks position as claimed
Payout Logic:
  • 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
Permissionless emergency refund after 24 hours.Parameters:
  • game_id: u64 - Game to refund
Validation:
  • Game is locked but not resolved
  • At least 24 hours have passed since lock time
Effects:
  • Sets winning_outcome = None (refund all)
  • No fees collected
  • All players can claim full refund
Authority can trigger emergency refund at any time.Validation:
  • Caller must be program authority
  • Game not already resolved
Effects:
  • Same as emergency_refund_v2
  • No time restriction

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:
This ensures the game account remains rent-exempt throughout its lifecycle.

7. Payout Mechanics

7.1 Winner Payout Formula

7.2 Refund Payout Formula

When winning_outcome = None (tie, cancellation, or emergency):
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.
Permissionless Emergency Refund:
  • Available 24 hours after lock time
  • Anyone can trigger (not just oracle/authority)
  • No fees collected
  • All players receive full refund

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
Guarantees:
  • 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:
Example:
Mitigation: UI should warn users about minimum effective stakes

11. Security Model

11.1 Trust Assumptions

11.2 Attack Mitigations

  • Position.claimed flag prevents re-entry
  • Checked before any transfer
  • Hardcoded oracle address
  • Cannot be changed per-game
  • Authority can override via emergency refund
  • Lock time prevents last-second stakes
  • Pool totals visible on-chain (transparent)
  • Rent reserved before fee calculation
  • Account cannot go below rent-exempt minimum
  • 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
Position PDAs:
  • 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