Wagering System
How USDC wagering works in PokeDexter.
Wagering System
PokeDexter's wagering system lets players stake real USDC on Pokémon battles. This page explains the complete flow from challenge to payout.
Overview
- Player A challenges Player B with a wager amount
- Player B accepts the challenge
- Both players deposit to a shared escrow wallet
- Battle happens like normal Pokémon Showdown
- Winner receives the pot (minus house fee) automatically
The Challenge Flow
Creating a Challenge
What happens:
- Server validates challenger has a connected wallet
- Server validates amount is within limits ($1-$100 by default)
- Challenge is stored in pending state
- Target user receives notification
- Challenge auto-expires after 5 minutes
Example:
Accepting a Challenge
What happens:
- Server validates accepter has a connected wallet
- Server generates a new escrow Keypair
- Both players receive deposit instructions
- Challenge moves from "pending" to "awaiting_deposits"
The Deposit Process
Escrow Wallet Generation
When a wager is accepted, the server creates a fresh Solana Keypair:
This escrow wallet:
- Is unique to this specific match
- Holds both players' deposits
- Is controlled by the server (private key server-side only)
Deposit Instructions
Both players see:
Deposit Verification
The server monitors the escrow wallet's USDC balance:
Deposit Timeout
If both deposits aren't received within a timeout period:
- Wager is cancelled
- Any received deposits should be refunded
- Players are notified
Battle Phase
Once both deposits are confirmed:
- Battle room created automatically
- Both players joined to the room
- Normal battle rules apply
- Timer active (turn timer, total timer)
The battle proceeds exactly like any Pokémon Showdown match. The wager doesn't affect gameplay.
Special Cases
Forfeit: If a player forfeits, they lose the wager.
Disconnect: If a player disconnects and doesn't return before timeout, they lose.
Timer loss: Running out of time = loss.
Draw: In the rare case of a draw (both last Pokémon faint simultaneously), special handling is needed (currently: investigate manually).
Settlement
When the battle ends, settlement happens automatically.
Winner Determination
The game server already determines winners - we hook into the existing onBattleEnd handler:
Payout Calculation
Example:
- Wager: $10 each
- Total pot: $20
- House fee (5%): $1
- Winner receives: $19
Settlement Transaction
The server builds and signs the transaction:
Player Notification
Winner:
Loser:
House Fee
The house fee is configurable via environment variable:
Where it goes:
- Sent to
HOUSE_WALLET_ADDRESSin the same settlement transaction - If not configured, entire pot goes to winner
Why a house fee?
- Covers operational costs
- Funds future development
- Standard practice in competitive gaming
Facilitator Integration
After settlement, the wager is registered as an x402 payment event:
This enables:
- Tracking in Dexter marketplace stats
- Future spectator betting features
- Transaction history and auditing
Limits and Configuration
| Setting | Default | Environment Variable |
|---|---|---|
| Minimum wager | $1 | MIN_WAGER_USD |
| Maximum wager | $100 | MAX_WAGER_USD |
| House fee | 5% | HOUSE_CUT_PERCENT |
| Challenge timeout | 5 min | Hardcoded |
| Deposit timeout | TBD | Not yet implemented |
Security Considerations
Escrow Safety
- Fresh keypair per match = isolated risk
- Server-side keys = users can't steal from escrow
- On-chain verification = transparent payouts
Throwing Prevention
- Random Battle format = can't pre-select bad team
- Timer rules = can't stall indefinitely
- Future: Pattern detection for suspicious losses
Dispute Resolution
Currently manual. If something goes wrong:
- Check on-chain transaction history
- Verify battle outcome in logs
- Manual intervention if needed

Wagering System