Parimutuel
Parimutuel betting, also known as pool betting, is a unique betting system widely utilized across various sporting events. Unlike traditional fixed-odds betting where wagers are placed against a bookmaker, parimutuel betting involves participants betting against one another. All bets of a particular type are pooled together, and after the event concludes, the pool is divided among the winning bets.
How it works
- Pooling Bets: All wagers on a specific event are collected into a central pool.
- Deducting Fees: A configurable percentage of the total pools is deducted as a protocol fee.
- Calculating Payouts: The losing pools are distributed among the bettors who selected the winning outcome. The payout for each individual is determined by the proportion of their bet amount relative to the total pool amount of the winning selection.
Disadvantages
While parimutuel betting is fun, it’s important to consider its potential drawbacks:
- Uncertain Payouts: Payouts remain unknown until markets close, as they depend on the distribution of all bets placed on the market.
- Fluctuating Odds: Odds can change up until the event begins, potentially reducing expected returns if more bets are placed.
- Lower Payouts: When many bettors choose the same outcome, winnings are divided among more participants, resulting in smaller individual payouts.
- Impact of Large Bets: In smaller pools, significant bet sizes can heavily influence odds, affecting potential returns for all bettors.
Understanding these disadvantages helps bettors make informed decisions aligned with their risk tolerance and betting preferences.
Technical Details
Code ID
Mainnet: None
Testnet: 10681
Instantiate
The contract is instantiated with the following parameters:
- admin_addr (
Addr
): The address with administrative privileges. - treasury_addr (
Addr
): The address where fees will be sent. - fee_bps (
u64
): Fee expressed in basis points (1 basis point = 0.01%). - denom (
String
): The denomination of the token used for betting (e.g., “usdc
”). - denom_precision (
u32
): The number of decimal places for the token. - id (
String
): A unique identifier for the betting market. - label (
String
): A descriptive label for the market. - home_team (
String
): The name of the home team. - away_team (
String
): The name of the away team. - start_timestamp (
u64
): The UNIX timestamp indicating when the event starts. - is_drawable (
bool
): Indicates whether a draw is a valid outcome.
Example:
{ "admin_addr": "neutron1...", "treasury_addr": "neutron1...", "fee_bps": 500, "denom": "uusdc", "denom_precision": 6, "id": "match_123", "label": "Team A vs. Team B", "home_team": "Team A", "away_team": "Team B", "start_timestamp": 1672531200, "is_drawable": true}
Possible Errors:
- InvalidAddress: If the provided addresses (e.g.,
admin_addr
ortreasury_addr
) fail validation, this error is returned with the invalid address string. - InvalidFeeBps: If the provided fee in basis points exceeds the allowed maximum (1,000).
Query Messages
The contract provides several query endpoints to retrieve current state and betting information.
Config
Retrieves the current configuration of the market.
Example Request:
{ "config": {}}
Example Response:
{ "config": { "admin_addr": "neutron1...", "treasury_addr": "neutron1...", "fee_bps": 500, "denom": "uusdc", "denom_precision": 6 }}
Market
Retrieves details about the betting market.
Example Request:
{ "market": {}}
Example Response:
{ "market": { "id": "match_123", "label": "Team A vs. Team B", "home_team": "Team A", "away_team": "Team B", "start_timestamp": 1672531200, "status": "ACTIVE", "result": null, "is_drawable": true }}
Status: Represents the current state of the market.
pub enum Status { ACTIVE, CLOSED, CANCELLED,}
Result: Represents the final result of the market, if it has been settled.
pub enum MarketResult { HOME, AWAY, DRAW,}
Bets
Fetches the total bets placed in the market, aggregated by outcome.
Example Request:
{ "bets": {}}
Example Response:
{ "totals": { "home": 1000000, "away": 750000, "draw": 500000 }}
BetsByAddress
Retrieves the bets placed by a specific address.
Parameters:
- address (
Addr
): The address of the bettor.
Example Request:
{ "bets_by_address": { "address": "neutron1..." }}
Example Response:
{ "address": "neutron1...", "totals": { "home": 500000, "away": 0, "draw": 0 }}
EstimateWinnings
Calculates the estimated winnings for a specific bettor if a given outcome wins.
Parameters:
- address (
Addr
): The address of the bettor. - result (
MarketResult
): The outcome for which the winnings are being estimated.
Example Request:
{ "estimate_winnings": { "address": "neutron1...", "result": "HOME" }}
Example Response:
{ "estimate": 750000}
Execute Messages
The contract supports several executable actions.
PlaceBet
Allows a user to place a bet on a specific outcome.
Parameters:
- result (
MarketResult
): The chosen outcome; must be one of HOME, AWAY, or DRAW. - receiver (
Option<Addr>
): Optional address to receive winnings (defaults to the sender if omitted).
Funds (Coins
): The bet amount (in the configured denomination) is sent along with the message.
Example:
{ "place_bet": { "result": "HOME", "receiver": "neutron1..." }}
Possible Errors:
- MarketNotDrawable: Returned if a bet is placed on DRAW when the market is not drawable.
- MarketNotActive: If the market is not active.
- BetsNotAccepted: If the current block time is less than 5 minutes before the event start.
- PaymentError: If no funds are sent or if token transfer fails.
ClaimWinnings
Allows users to claim their winnings after the market outcome has been determined.
Parameters:
- receiver (
Option<Addr>
): Optional address to receive winnings (defaults to the sender if omitted).
Example:
{ "claim_winnings": { "receiver": "neutron1..." }}
Possible Errors:
- MarketNotClosed: If the market is still active.
- ClaimAlreadyMade: If the address has already claimed winnings.
- NoWinnings: If there are no winnings available for the address.
Update (Admin Only)
Enables the admin to update market parameters.
Parameters:
- admin_addr (
Option<Addr>
): New admin address. - treasury_addr (
Option<Addr>
): New treasury address. - fee_bps (
Option<u64>
): New fee in basis points. - start_timestamp (
Option<u64>
): Updated event start timestamp.
Example:
{ "update": { "admin_addr": "neutron1...", "fee_bps": 300 }}
Possible Errors:
- Unauthorized: If the sender is not the current admin.
- MarketNotActive: If the market is not active.
- InvalidAddress: If the provided addresses (e.g.,
admin_addr
ortreasury_addr
) fail validation, this error is returned with the invalid address string. - InvalidFeeBps: If the new fee in basis points is invalid.
Score (Admin Only)
Sets the final outcome for the market.
Parameters:
- result (
MarketResult
): The winning outcome, which can be HOME, AWAY, or DRAW.
Example:
{ "score": { "result": "HOME" }}
Possible Errors:
- Unauthorized: If the sender is not the current admin.
- MarketNotDrawable: If a DRAW result is provided for a non-drawable market.
- MarketNotActive: If the market is not active.
- MarketNotScoreable: If the current time is less than 30 minutes after the start.
- NoWinnings: If there are no winnings to process.
Cancel (Admin Only)
Cancels the market, resulting in refunds of all bets, no fees are captured.
Example:
{ "cancel": {}}
Possible Errors:
- Unauthorized: If the sender is not the current admin.
- MarketNotActive: If the market is not active.