Skip to main content
The SolBid program supports two main instructions for managing bidding games.

Instruction format

All instructions use Borsh serialization and are defined in the BiddingInstruction enum:
pub enum BiddingInstruction {
    CreateGame {
        game_id: u64,
        initial_bid_amount: u64,
    },
    PlaceBid {
        bid_amount: u64,
        bid_count: u64,
    },
}
See instructions/mod.rs:9-19 for the enum definition.

CreateGame

Creates a new bidding game with an initial bid. This instruction initializes the game state, creates the first player account, and records the first bid.

Parameters

game_id
u64
required
Unique identifier for the game. Must be unique across all games. Used as a seed for PDA derivation.
initial_bid_amount
u64
required
Initial bid amount in lamports. Must be at least 14,000,000 lamports (0.014 SOL).

Accounts

The CreateGame instruction requires the following accounts in order:
game_account
AccountInfo
required
The game PDA account to be created. Must be derived using seeds: ["game", game_id].
  • Writable: Yes
  • Signer: No
  • Size: 96 bytes
payer_account
AccountInfo
required
The account paying for rent and the initial bid. This becomes the first player.
  • Writable: Yes
  • Signer: Yes
system_program
AccountInfo
required
The Solana system program account.
  • Writable: No
  • Signer: No
  • Address: 11111111111111111111111111111111
player_account
AccountInfo
required
The player PDA account to be created for the initial bidder. Must be derived using seeds: ["player", game_id, payer_pubkey, bid_count] where bid_count is 1.
  • Writable: Yes
  • Signer: No
  • Size: 32 bytes
bid_account
AccountInfo
required
The bid PDA account to be created for the initial bid. Must be derived using seeds: ["bid", game_id, bid_number] where bid_number is 1.
  • Writable: Yes
  • Signer: No
  • Size: 48 bytes

Validation

The instruction performs the following validation:
  1. Initial bid amount must be ≥ 14,000,000 lamports (0.014 SOL)
  2. Game account must match expected PDA
  3. Player account must match expected PDA
  4. Bid account must match expected PDA
If initial_bid_amount < 14_000_000, the instruction fails with InsufficientInitialBid error.

State initialization

The instruction initializes three accounts with the following data: GameState (game_account):
  • game_id: provided game_id
  • initial_bid_amount: provided amount
  • highest_bid: initial_bid_amount
  • last_bid_time: current timestamp
  • total_bids: 1
  • last_bidder: payer pubkey
  • prize_pool: initial_bid_amount
  • platform_fee_percentage: 10 (hardcoded)
  • game_ended: false
PlayerState (player_account):
  • total_bid_amount: initial_bid_amount
  • safe: false
  • royalty_earned: 0
  • bid_count: 1
Bid (bid_account):
  • bidder: payer pubkey
  • amount: initial_bid_amount
  • timestamp: current timestamp
See instructions/create_game.rs:106-133 for initialization logic.

SOL transfers

The instruction transfers initial_bid_amount lamports from the payer to the game account after initialization.

Example usage

import { BorshSchema, serialize } from 'borsh';

const instruction = {
  CreateGame: {
    game_id: BigInt(1),
    initial_bid_amount: BigInt(14_000_000), // 0.014 SOL
  }
};

const instructionData = serialize(schema, instruction);

PlaceBid

Places a new bid on an existing game. Creates a new player state and bid record for the bidder.

Parameters

bid_amount
u64
required
Bid amount in lamports. Must be at least double the current highest bid.
bid_count
u64
required
Expected bid count after this bid (current total_bids + 1). Used to prevent race conditions.

Accounts

The PlaceBid instruction requires the following accounts in order:
system_program
AccountInfo
required
The Solana system program account.
  • Writable: No
  • Signer: No
platform_account
AccountInfo
required
The platform fee recipient account (used when game ends).
  • Writable: Yes
  • Signer: No
game_account
AccountInfo
required
The existing game PDA account.
  • Writable: Yes
  • Signer: No
bidder_account
AccountInfo
required
The account placing the bid and paying for it.
  • Writable: Yes
  • Signer: Yes
new_bid_account
AccountInfo
required
The new bid PDA account to be created. Must be derived using seeds: ["bid", game_id, new_bid_count].
  • Writable: Yes
  • Signer: No
new_player_account
AccountInfo
required
The new player PDA account to be created. Must be derived using seeds: ["player", game_id, bidder_pubkey, new_bid_count].
  • Writable: Yes
  • Signer: No

Validation

The instruction performs extensive validation:
  1. Game account must have correct size (96 bytes)
  2. Game must not have ended (game_ended == false)
  3. Current time must be within 600 seconds (10 minutes) of last bid
  4. Bid amount must be ≥ 2x current highest bid
  5. Bid count must equal current total_bids + 1
  6. New player account must match expected PDA
  7. New bid account must match expected PDA
If more than 600 seconds have elapsed since the last bid, the game automatically ends and the instruction calls end_game() instead.
The bid_count parameter prevents race conditions by ensuring the bidder knows the current game state.

State updates

The instruction updates and creates the following state: GameState (updated):
  • highest_bid: new bid_amount
  • last_bid_time: current timestamp
  • last_bidder: bidder pubkey
  • total_bids: incremented by 1
  • prize_pool: increased by bid_amount
PlayerState (new account created):
  • total_bid_amount: bid_amount
  • safe: false
  • royalty_earned: 0
  • bid_count: new_bid_count
Bid (new account created):
  • bidder: bidder pubkey
  • amount: bid_amount
  • timestamp: current timestamp
See instructions/place_bid.rs:116-139 for state update logic.

SOL transfers

The instruction transfers bid_amount lamports from the bidder to the game account.

Automatic game ending

If the 10-minute timeout has expired, the instruction automatically calls end_game() which:
  1. Fetches complete bid history
  2. Calculates and distributes platform fees (10%)
  3. Distributes royalties to early bidders (if ≥5 bids)
  4. Awards remaining balance to last bidder
  5. Marks game as ended
See instructions/place_bid.rs:153-236 for game ending logic.

Example usage

import { BorshSchema, serialize } from 'borsh';

const instruction = {
  PlaceBid: {
    bid_amount: BigInt(28_000_000), // 0.028 SOL (2x initial)
    bid_count: BigInt(2), // expecting to be bid #2
  }
};

const instructionData = serialize(schema, instruction);

Error handling

Both instructions return detailed error codes on failure. Common errors include:
  • InsufficientInitialBid - Initial bid < 0.014 SOL
  • InvalidGameAccount - Game PDA doesn’t match expected address
  • InvalidPlayerAccount - Player PDA doesn’t match expected address
  • InvalidBidAccount - Bid PDA doesn’t match expected address
  • GameEnded - Cannot bid on ended game
  • InsufficientBidAmount - Bid < 2x highest bid
  • BidCountMismatch - Provided bid_count doesn’t match expected value
See error.rs:4-50 for all error definitions.

Build docs developers (and LLMs) love