The standard stuff, assuming you already have your anchor dev enironment setup!
Node.js & npm:
Anchor Framework:
Solana CLI
The magic stuff..
For your anchor project
cargo add switchboard-on-demand
For your typescript client
npm i @switchboard-xyz/on-demand
Step 1: Spinning the Wheel of Randomness in Your Solana Program
Integrating randomness into your Solana program is akin to consulting an oracle - mysterious yet straightforward. Here’s how you infuse your Solana program with a dash of unpredictability
1.Define the Randomness Account: First, ensure your program knows about the randomness account. This account is your gateway to the oracle’s wisdom. In your program's context, it looks something like this:
#[account]pubstructPlayerState { allowed_user:Pubkey, latest_flip_result:bool, // Stores the result of the latest flip randomness_account:Pubkey, // Reference to the Switchboard randomness account current_guess:bool, // The current guess wager:u64, // The wager amount bump:u8,}
2.Summon the Oracle’s Power: When it's time to flip the coin, you commit to using a future slot's hash as your seed, essentially asking the oracle to predict the flip's outcome at that future moment. This randomness account that represents this needs to be stored and updated. The coin_flip function makes this commitment:
pubfncoin_flip(ctx:Context<CoinFlip>, randomness_account:Pubkey, guess:bool) ->Result<()> {...// Update the randomness account seed_slot you are committing tolet randomness_data =RandomnessAccountData::parse(ctx.accounts.randomness_account_data.data.borrow()).unwrap();if randomness_data.seed_slot != clock.slot -1 {msg!("seed_slot: {}", randomness_data.seed_slot);msg!("slot: {}", clock.slot);returnErr(ErrorCode::RandomnessAlreadyRevealed.into()); }// ***// IMPORTANT: Remember, in Switchboard Randomness, it's the responsibility of the caller to reveal the randomness.// Therefore, the game collateral MUST be taken upon randomness request, not on reveal.// ***transfer( ctx.accounts.system_program.to_account_info(), ctx.accounts.user.to_account_info(), // Include the user_account ctx.accounts.escrow_account.to_account_info(), player_state.wager,None, )?;// Store flip commitment to the future slot byt referencing the randomness account player_state.randomness_account = randomness_account;...}
3.Reveal the Oracle's Vision: Once the future becomes the present, and the slot arrives, you ask the oracle to reveal its prediction - the result of the coin flip. The settle_flip function is where the magic unfolds:
pubfnsettle_flip(ctx:Context<SettleFlip>) ->Result<()> {...// Parsing the oracle's scroll// call the switchboard on-demand parse function to get the randomness datalet randomness_data =RandomnessAccountData::parse(ctx.accounts.randomness_account_data.data.borrow()).unwrap();// call the switchboard on-demand get_value function to get the revealed random valuelet revealed_random_value = randomness_data.get_value(&clock).map_err(|_| ErrorCode::RandomnessNotResolved)?;...}
Step 2: Conjuring Randomness with a TypeScript Client
On the client side, engaging with the oracle isn't just about hitting the right keys—it's about knowing the secret handshake. Let's walk through the TypeScript moves to make the oracle dance:
Setup and Environment Configuration: Start by setting up your environment, ensuring you have access to the Solana network and the Switchboard program. You'll need the program IDs for both your Coin Flip game and the Switchboard Queue and On-demand program.
Creating a Randomness Account: Before flipping the coin, you must prepare a randomness account. This account is how you communicate your request to the oracle.
Committing to Randomness: With your randomness account at the ready, commit to the oracle's prediction. This is where you formally ask for the outcome based on a future slot.
constcommitIx=awaitrandomness.commitIx(sbQueue);// Add this instruction to your coinFlip transaction and send it
Revealing the Oracle’s Wisdom: After the slot passes, you ask the oracle to reveal its prediction. The response determines the fate of your coin flip.
constrevealIx=awaitrandomness.revealIx();// Execute the reveal instruction, followed by your program's settle_flip function
Note: as an added extra, you can save the revealIx()transaction for later use, using this neat command
Settling the Flip: Finally, call your Solana program's settle_flip function to officially record the coin flip result based on the oracle's revealed randomness.
constsettleFlipIx=awaitcoinFlipProgram.instruction.settleFlip( escrowBump, { accounts: { playerState: playerStateAccount, randomnessAccountData:randomness.pubkey, escrowAccount: escrowAccount, user:provider.wallet.publicKey, systemProgram:SystemProgram.programId, }, } );// Add the revealIx and this instruction together and execute
And there you have it! You've just taken your first leap into the realm of randomness, flipping a coin with the finesse of a digital magician. With Switchboard's Randomness On-Demand, you're now equipped to bring the element of surprise into any Solana project. Who knew uncertainty could be so reliable? 😊