Skip to main content

Prize Pool System

Trustless, contract-held tournament prize pools with third-party funding support.


Purpose

The prize pool system allows anyone — game operators, sponsors, guilds, streamers, or individual players — to fund competitive events. It exists because:

  • Players and sponsors must trust that prize money will be paid out
  • Game developers holding prize funds creates a single point of failure
  • Smart contract custody removes the need for trust in any individual party
  • Third-party funding (guilds, streamers, sponsors) requires a neutral mechanism

Design Principles

PrincipleImplementation
Developer never holds fundsAll funds go directly to/from the contract
Winners claim directlyNo admin intermediary for payout
Multiple funding sourcesAny address can deposit into a pool
Refundable on cancellationIf event is cancelled, depositors can reclaim
Transparent pool balanceAnyone can query the contract for current pool state

Architecture

              ┌─────────────────────────────────────────────┐
│ Prize Pool Contract │
│ │
Sponsor A ──►│ pool_balance: 100 AVAX │
Sponsor B ──►│ status: ACTIVE │
Entry Fees ─►│ participants: [addr1, addr2, ...] │
│ prize_split: [60%, 30%, 10%] │
│ results: [] (pending) │
│ │
│ fund() ← anyone │
│ register() ← players │
│ submit() ← game server (authorized) │
│ claim() ← verified winners │
│ refund() ← depositors (if cancelled) │
└─────────────────────────────────────────────┘

Pool Lifecycle

┌───────────┐     ┌───────────┐     ┌───────────┐     ┌───────────┐
│ CREATED │────►│ FUNDED │────►│ ACTIVE │────►│ FINALIZED │
│ │ │ │ │ │ │ │
│ pool ID │ │ deposits │ │ matches │ │ results │
│ rules set │ │ accepted │ │ in │ │ submitted │
│ │ │ players │ │ progress │ │ claims │
│ │ │ register │ │ │ │ open │
└───────────┘ └───────────┘ └───────────┘ └─────┬─────┘
│ │
▼ ▼
┌───────────┐ ┌───────────┐
│ CANCELLED │ │ COMPLETED │
│ │ │ │
│ refunds │ │ all │
│ available │ │ claimed │
└───────────┘ └───────────┘

State Transitions

FromToTriggered ByCondition
CREATEDFUNDEDFirst fund() callPool receives minimum balance
FUNDEDACTIVEGame serverStart signal from authorized key
ACTIVEFINALIZEDGame server submit()Results array submitted
FINALIZEDCOMPLETEDAll claim() processedAll winners have claimed
FUNDEDCANCELLEDAdmin / timeoutEvent not started within window
ACTIVECANCELLEDAdmin (emergency only)Requires multi-sig or timelock

Funding Sources

Entry Fees

Player pays entry fee (AVAX)


Contract splits fee:
├── 90% → prize pool
└── 10% → treasury (configurable)
Sponsor calls fund(poolId) with AVAX


Deposit added to pool_balance


Sponsor address recorded for refund eligibility

Third-Party Funding Types

Funder TypeMotivationHow They Fund
GuildsPromote their members, brand visibilityDirect fund() call
StreamersContent, community engagementVia streamer tournament UI
SponsorsBrand exposure, marketingDirect fund() call
PlayersIncreased prize pool for their eventVia entry fee + optional extra

Prize Distribution

Split Configuration

Defined at pool creation:

{
pool_id: 42,
prize_split: [
{ rank: 1, percent: 50 },
{ rank: 2, percent: 25 },
{ rank: 3, percent: 15 },
{ rank: 4, percent: 10 }
],
entry_fee: "2.0 AVAX",
fee_split: {
prize: 90, // % of entry fee added to prize pool
treasury: 10 // % to treasury
}
}

Claim Process

Game server submits results:
results = [(addr1, rank1), (addr2, rank2), ...]


Contract calculates each winner's share:
share = pool_balance * prize_split[rank] / 100


Winner calls claim(poolId)


Contract verifies:
• caller is in results
• caller hasn't already claimed
• pool is in FINALIZED state


AVAX transferred to winner

Security Properties

PropertyImplementation
No admin withdrawal of prizesOnly verified winners can call claim()
Double-claim preventionhasClaimed[poolId][address] mapping
Depositor refund on cancelrefund(poolId) returns proportional deposit
Result submission authorizationOnly authorized game server key can call submit()
Overflow protectionSplit percentages must sum to 100%
No fund mixingEach pool has isolated balance

Contract Interface

interface IPrizePool {
// Pool management
function createPool(
uint256 entryFee,
uint8[] calldata prizeSplitPercents,
uint256 startDeadline
) external returns (uint256 poolId);

// Funding
function fund(uint256 poolId) external payable;

// Registration
function register(uint256 poolId) external payable;

// Results (authorized only)
function submitResults(
uint256 poolId,
address[] calldata winners,
uint8[] calldata ranks
) external;

// Claims
function claim(uint256 poolId) external;

// Refunds
function refund(uint256 poolId) external;

// View
function getPool(uint256 poolId) external view returns (PoolData memory);
function getBalance(uint256 poolId) external view returns (uint256);
}

Integration Guide for Other Games

Step 1: Deploy Prize Pool Contract

  • Configure default fee split (prize vs treasury)
  • Set authorized server address for result submission
  • Set cancellation policy (timeout, multi-sig)

Step 2: Integrate with Game Server

  • Game server creates pools when tournaments are scheduled
  • Game server submits results when tournaments complete
  • Provide player-facing UI for registration and claiming

Step 3: Enable Third-Party Funding

  • Expose fund() for sponsors, guilds, and streamers
  • Build a sponsor dashboard showing pool status and branding
  • Optionally: create a widget streamers can embed

Step 4: Monitor

  • Track pool balances and claim rates
  • Alert on pools stuck in ACTIVE state (stale tournaments)
  • Monitor treasury accumulation for economic health