Double your BUX! Play Now →
Technical · Smart contracts

Blockster Bankroll — full reference.

The Anchor program backing every bet and every pool. Every instruction, every account, every PDA seed, every error code. Built to be read end-to-end by auditors and integrators.

01

Program overview

Identity
Program ID
49up2uzZANpjTC3sgggbZazdHBii2vY9mVK3vk5dT2tm
Cluster
mainnet
Framework
Anchor 0.30+ (Rust)
Crate
contracts/blockster-bankroll/programs/blockster-bankroll
Settler service
contracts/blockster-settler (Node/TypeScript)
IDL
contracts/blockster-bankroll/target/idl/blockster_bankroll.json
Number of instructions
22
Number of account structs
7
Number of error codes
32
Number of emitted events
14

The program is a single crate — no cross-program call chains that aren't standard CPIs (System, SPL Token, Metaplex Token Metadata). It holds two vaults (SOL + BUX), mints two LP tokens (SOL-LP + BUX-LP), registers up to 10 games with parametric multipliers, implements a commit-reveal settlement scheme, and supports a two-tier referral programme.

02

Authority model

Roles
authority
Set once at initialize_registry, never changeable on-chain. Registers games, updates per-game config, toggles the global pause flag, creates LP metadata.
settler
Submits commitments, settles bets, pays the PDA rent for BetOrder accounts. Rotated via update_config.
upgrade_authority
Standard Solana upgrade authority on the program loader. Held off-chain, not referenced in program code.
player
Signs deposits, withdrawals, reclaims. No persistent privilege; the sender of each instruction.
03

PDAs and seeds

PDA Seeds Owner Purpose
Game registry [b"game_registry"] Program Singleton; holds authority, settler, game table, bumps, pause flag
SOL vault [b"sol_vault"] System Holds raw SOL lamports
SOL vault state [b"sol_vault_state"] Program Accounting: liability, house_profit, volume, stats
BUX vault state [b"bux_vault_state"] Program Accounting for the BUX pool
BUX token account [b"bux_token_account"] SPL Token Holds BUX tokens; authority = itself
SOL-LP mint [b"bsol_mint"] SPL Token LP token mint for the SOL pool
SOL-LP mint authority [b"bsol_mint_authority"] Program Signs SOL-LP mint/burn via CPI
BUX-LP mint [b"bbux_mint"] SPL Token LP token mint for the BUX pool
BUX-LP mint authority [b"bbux_mint_authority"] Program Signs BUX-LP mint/burn via CPI
Player state [b"player", player_pubkey] Program Per-player: pending commitment, nonce, referrer, lifetime stats
Bet order [b"bet", player_pubkey, nonce.to_le_bytes()] Program Per-bet: amount, max_payout, commitment, status; closes on settle/reclaim
Referral state [b"referral", referrer_pubkey] Program Per-referrer: cumulative rewards, referral count
04

Account structures

GameRegistry

state/game_registry.rs
rust
#[account]
pub struct GameRegistry {
    pub authority: Pubkey,             // 32 — set once at init
    pub settler: Pubkey,               // 32 — rotatable via update_config
    pub bux_mint: Pubkey,              // 32
    pub paused: bool,                  // 1
    pub bet_timeout: i64,              // 8  — seconds before reclaim eligible
    pub referral_bps: u16,             // 2  — tier-1 rate
    pub tier2_referral_bps: u16,       // 2  — tier-2 rate
    pub sol_vault_bump: u8,            // 1
    pub sol_vault_state_bump: u8,      // 1
    pub bux_vault_state_bump: u8,      // 1
    pub bux_token_account_bump: u8,    // 1
    pub bsol_mint_bump: u8,            // 1
    pub bsol_mint_authority_bump: u8,  // 1
    pub bbux_mint_bump: u8,            // 1
    pub bbux_mint_authority_bump: u8,  // 1
    pub game_count: u64,               // 8
    pub games: [GameEntry; 10],        // 730
    pub _reserved: [u8; 128],          // 128
}

pub struct GameEntry {
    pub game_id: u64,                  // 8
    pub name: [u8; 32],                // 32 — padded ASCII, e.g. b"coin_flip\0\0..."
    pub active: bool,                  // 1
    pub min_bet: u64,                  // 8  — lamports or BUX base units
    pub max_bet_bps: u16,              // 2  — cap 500 (= 5%)
    pub fee_bps: u16,                  // 2  — cap 1000 (= 10%), currently unused in settlement
    pub multipliers: [u16; 9],         // 18 — stored as bps/100; e.g. 198 → 1.98×
    pub _reserved: [u8; 2],            // 2
}

SolVaultState and BuxVaultState

Parallel structures — one per vault. Same fields, different account type for Anchor type safety.

state/sol_vault.rs (BuxVaultState is identical)
rust
#[account]
pub struct SolVaultState {
    pub total_deposited: u64,          // Cumulative deposits by LPs
    pub total_withdrawn: u64,          // Cumulative withdrawals
    pub total_liability: u64,          // Sum of max_payout for pending bets
    pub unsettled_count: u64,          // Number of pending bets
    pub unsettled_bets: u64,           // Sum of wager amounts for pending bets
    pub house_profit: i64,             // Net vault P&L (signed, can be negative)
    pub total_bets: u64,               // Lifetime settled bet count (excludes reclaimed)
    pub total_volume: u64,             // Lifetime sum of settled wagers
    pub total_payout: u64,             // Lifetime sum of paid-out winnings
    pub largest_bet: u64,
    pub largest_payout: u64,
    pub lp_deposits_count: u64,
    pub lp_withdrawals_count: u64,
    pub total_referral_paid: u64,
    pub _reserved: [u8; 128],
}

PlayerState

state/player_state.rs
rust
#[account]
pub struct PlayerState {
    pub player: Pubkey,                // 32
    pub pending_commitment: [u8; 32],  // SHA256 of server seed for pending_nonce
    pub pending_nonce: u64,
    pub nonce: u64,                    // Next nonce to use
    pub has_active_order: bool,        // Reserved; currently not read or written

    // Referrals
    pub referrer: Pubkey,              // Tier-1; Pubkey::default if none
    pub tier2_referrer: Pubkey,        // Auto-resolved at set_referrer

    // Lifetime stats
    pub total_orders: u64,
    pub total_wagered_sol: u64,
    pub total_wagered_bux: u64,
    pub net_pnl_sol: i64,              // Can be negative
    pub net_pnl_bux: i64,

    pub bump: u8,
    pub _reserved: [u8; 64],
}

BetOrder

state/bet_order.rs
rust
pub enum BetOrderStatus { Pending, Settled, Expired }
pub enum VaultType       { Sol, Bux }

#[account]
pub struct BetOrder {
    pub player: Pubkey,
    pub game_id: u64,
    pub vault_type: VaultType,
    pub amount: u64,                   // Wager
    pub max_payout: u64,               // amount × multiplier_bps / 10_000
    pub commitment_hash: [u8; 32],     // Copied from PlayerState at placement
    pub nonce: u64,
    pub status: BetOrderStatus,        // Always Pending while live
    pub created_at: i64,               // unix_timestamp
    pub bump: u8,
    pub rent_payer: Pubkey,            // Locked at placement to game_registry.settler
}

BetOrder accounts close on settle_bet or reclaim_expired. The rent rebate goes back to rent_payer — the settler keypair in force at placement. Rotating the settler does not rotate rent_payer on already-placed bets.

ReferralState

state/referral_state.rs
rust
#[account]
pub struct ReferralState {
    pub referrer: Pubkey,
    pub total_referrals: u64,          // Unique players who chose this referrer
    pub total_earnings_sol: u64,
    pub total_earnings_bux: u64,
    pub bump: u8,
    pub _reserved: [u8; 32],
}
05

Constants

MINIMUM_LIQUIDITY
10_000 — base units burned on first deposit (donation-attack defence)
MAX_GAMES
10 — maximum registered games in the registry array
BPS_DENOMINATOR
10_000 — 100% in basis points
MAX_FEE_BPS
1_000 — 10% cap on per-game fee_bps
MAX_SPLIT_BPS
500 — 5% cap on each referral tier
MAX_BET_BPS
500 — 5% cap on per-game max_bet_bps
MIN_BET_TIMEOUT
60 seconds — floor on game_registry.bet_timeout
LP_PRICE_PRECISION
1_000_000_000 (1e9) — scaling factor for LP price display
MULTIPLIER_SCALE
100 — multipliers are stored as bps/100 to fit u16
06

Instructions

The program exposes 22 instructions organised into five groups. Each is listed below with signer requirements, arguments, side effects, and the errors it can raise.

Initialization (one-time, authority-only)

Instruction Args Purpose
initialize_registry bet_timeout: i64 Create GameRegistry, SolVaultState, BuxVaultState. Set authority, settler, bux_mint. Default referral_bps=100, tier2=50.
initialize_sol_pool Create SOL-LP mint with program-owned mint authority PDA.
initialize_bux_pool Create BUX-LP mint.
initialize_bux_vault Create BUX token account PDA. Emits BankrollInitialized.
register_game game_id, name, min_bet, max_bet_bps, fee_bps, multipliers[9] Add a game to the registry (idempotent fails). Enforces bps caps and minimum multiplier values.
create_lp_metadata vault_type, name, symbol, uri CPI to Metaplex to attach metadata to SOL-LP or BUX-LP mint.

Liquidity (anyone)

Instruction Args Purpose
deposit_sol amount: u64 Move SOL into sol_vault, mint SOL-LP to depositor. Rejects if paused.
withdraw_sol lp_amount: u64 Burn SOL-LP, move SOL out to withdrawer. Rejects if paused or if underlying > available_balance.
deposit_bux amount: u64 Move BUX into vault, mint BUX-LP.
withdraw_bux lp_amount: u64 Burn BUX-LP, move BUX out.

Betting (commit-reveal)

Instruction Signer Purpose
submit_commitment settler Write SHA256(server_seed) to PlayerState. Nonce must be ≥ current player nonce. init_if_needed creates PlayerState first time.
place_bet_sol player + settler (rent_payer) Transfer SOL wager, create BetOrder PDA, clear commitment, increment nonce. Enforces all placement guards.
place_bet_bux player + settler (rent_payer) Same as place_bet_sol, but moves BUX.
settle_bet settler Reveal server_seed (hash must match commitment). Pay player if won. Process referral rewards on loss. Close BetOrder and return rent.
reclaim_expired player After bet_timeout, refund wager to player. Close BetOrder and return rent. Does not touch total_bets / house_profit.

Referrals

Instruction Signer Purpose
set_referrer player One-time; set tier-1 referrer. Auto-resolves tier-2 from referrer's referrer. Blocks self-refer and two-hop loops. Creates ReferralState for the referrer if needed.

Admin (authority-only)

Instruction Args Purpose
update_config all Option; may update: settler, bet_timeout, referral_bps, tier2_referral_bps, per-game config Partial update with caps enforced (max fee 10%, max split 5%, max bet 5%, min timeout 60s).
pause paused: bool Toggle global paused flag. Blocks deposit/withdraw/place_bet/submit_commitment/set_referrer. Does NOT block settle_bet or reclaim_expired (intentional).
07

Error codes

All program errors (defined in errors.rs)
Code Name Meaning
6000 Paused Global pause flag is set.
6001 ZeroAmount Amount argument must be > 0.
6002 MathOverflow checked_* arithmetic overflowed/underflowed.
6003 InvalidConfig Configuration value out of valid range (e.g. multiplier < 100).
6004 FeeTooHigh fee_bps or referral_bps exceeds its cap.
6005 SplitTooHigh tier-1 + tier-2 referral_bps exceeds MAX_SPLIT_BPS (500).
6006 BetTimeoutTooShort bet_timeout below MIN_BET_TIMEOUT (60s).
6007 DepositTooSmall First deposit below MINIMUM_LIQUIDITY, or subsequent deposit that would mint 0 LP.
6008 InsufficientLiquidity Withdrawal would exceed available_balance (after rent and liability).
6009 WithdrawTooLarge lp_amount would redeem to 0 underlying (dust).
6010 GameRegistryFull Attempt to register an 11th game.
6011 GameAlreadyRegistered Duplicate game_id at registration.
6012 GameNotFound Game ID absent or inactive at bet placement.
6013 InvalidDifficulty difficulty index ≥ 9.
6014 MultipliersNotConfigured Requested difficulty has stored multiplier == 0.
6015 BetTooSmall amount < game.min_bet.
6016 BetTooLarge amount > per-difficulty max_bet.
6017 MaxPayoutExceedsCapacity potential profit > net_balance.
6018 ActiveBetExists Reserved. Not currently raised.
6019 NonceMismatch nonce arg ≠ player_state.pending_nonce (or < existing nonce in submit_commitment).
6020 NoCommitment player_state.pending_commitment is zeroed.
6021 CommitmentMismatch Reserved. Not currently raised (hash check uses InvalidServerSeed).
6022 InsufficientVaultBalance Vault lacks funds for payout (defence-in-depth; should be unreachable given placement guards).
6023 OrderNotPending BetOrder.status ≠ Pending.
6024 OrderExpired settle_bet called after bet_timeout elapsed. Use reclaim_expired.
6025 OrderNotExpired reclaim_expired called before bet_timeout elapsed.
6026 InvalidServerSeed SHA256(server_seed) ≠ bet_order.commitment_hash. Also reused for has_one=player mismatch (misleading message).
6027 PayoutExceedsMax settle_bet payout arg > bet_order.max_payout.
6028 SelfReferral Player tried to set self as referrer.
6029 ReferrerAlreadySet Player already has a tier-1 referrer.
6030 UnauthorizedSettler Signer is not the registry settler or authority, depending on instruction.
6031 InvalidVaultType vault_type mismatch at settlement (e.g. BUX bet with missing player_bux_account).
6032 InvalidMint Mint address doesn't match expected PDA.
6033 InvalidRentPayer rent_payer at placement ≠ game_registry.settler; or bet_order.rent_payer at settle/reclaim ≠ supplied account.
08

Events

All events (defined in events.rs)
Event Triggered by Fields
BankrollInitialized initialize_bux_vault authority, settler, sol_vault, bux_vault, bsol_mint, bbux_mint
GameRegistered register_game game_id, name, active
ConfigUpdated update_config field_id (1=settler, 2=timeout, 3=t1_bps, 4=t2_bps), old_value, new_value
PauseToggled pause paused
SolDeposited deposit_sol depositor, sol_amount, lp_minted, vault_balance, lp_supply
SolWithdrawn withdraw_sol withdrawer, sol_amount, lp_burned, vault_balance, lp_supply
BuxDeposited deposit_bux depositor, bux_amount, lp_minted, vault_balance, lp_supply
BuxWithdrawn withdraw_bux withdrawer, bux_amount, lp_burned, vault_balance, lp_supply
CommitmentSubmitted submit_commitment player, nonce, commitment_hash
BetPlaced place_bet_* player, game_id, vault_type, amount, max_payout, nonce
BetSettled settle_bet player, nonce, won, amount, payout, vault_type, server_seed
BetReclaimed reclaim_expired player, nonce, amount, vault_type
ReferrerSet set_referrer player, referrer, tier2_referrer
ReferralRewardPaid settle_bet (on loss) referrer, player, amount, vault_type, tier
ReferralRewardFailed settle_bet (on loss, transfer failed) referrer, player, amount, vault_type, tier
09

Pause behaviour

The authority can flip game_registry.paused at any time via the pause instruction. This is the emergency brake.

What pause does and doesn't block
Blocks
deposit_sol, withdraw_sol, deposit_bux, withdraw_bux, submit_commitment, place_bet_sol, place_bet_bux, set_referrer
Does not block
settle_bet, reclaim_expired — so any pending bet can always be resolved
Does not block
update_config, register_game, create_lp_metadata, pause itself — admin retains control during pause
10

Upgrade authority

The program is deployed with a standard Solana upgrade authority — an Ed25519 keypair that can redeploy the program bytecode at any time. This is orthogonal to the program-internal authority role; in principle they could be the same key or different.

Upgrade authority facts
Held by
Settler keypair; planned migration to 2-of-3 multisig
Rotation
Solana CLI solana program set-upgrade-authority
Disabling upgrades
Possible via solana program set-upgrade-authority --final (irreversible)
Compromise scenario
Attacker could redeploy malicious bytecode and drain vaults. Mitigated by multisig hold on mainnet.