I'm learning Solana with Anchor and decided to implement Roshambo (rock, paper and scissors) game as part of my journey. I'd like to allow players to place some bid on game where winner collects all lamports that were placed by both players.

I'm stuck at place where I don't know what pattern should I go with when locking lamports transferred by players to attend a game. For now I have PDA account representing a game:

pub struct SetupGame<'info> {
    payer = player_one, 
    seeds = [b"game".as_ref(), player_one.key().as_ref()],
    space = 100)]
  pub game: Account<'info, Game>,

  pub player_one: Signer<'info>,

  pub system_program: Program<'info, System>,

pub struct Game {
  pub player_one: Pubkey,
  pub player_two: Pubkey,

impl Game {
  pub fn setup(&mut self, player_one: Pubkey) -> Result<()> {
    self.player_one = player_one;

  pub fn join(&mut self, player_two: Pubkey) -> Result<()> {
    self.player_two = player_two;

As you can see it's really simple and it's worth to mention that player_one inits the game. The way I'd like to go is where player_one places a lamports amount on, a game and player_two is required the transfer the very same lamports amount to join a game.

The thing is that I don't know how to collect and lock all lamports transferred by players and and allow to withdraw all by a winner.

Initially I wen't with approach were player_one is charged when callds setup_game instruction and lamports are transferred to Game PDA account:

pub fn setup_game(ctx: Context<SetupGame>, amount: u64) -> Result<()> {
  let player_one = &mut ctx.accounts.player_one;
  let game = &mut ctx.accounts.game;
  let ledger = &mut ctx.accounts.ledger;


    &system_instruction::transfer(&player_one.key(), &game.key(), amount.clone()), 
    &[player_one.to_account_info(), game.to_account_info()]


Qustion 1: What is a common design pattern to implement my case where game locks lamports and allows to withdraw to a winner? I'm confused since I've seen examples with TokenAccount and utilizing spl-token program but I believe they solve another case where users want to transfer minted tokens - in my case I base on SOL/Lamports transfers.

Qustion 2: My current example works and lamports are transferred to Game PDA account and when I check balance I see more lamports that I send. I'm guessing it's because balance shows a sum of lamports for rent exemption and lamports I sent. Is there a way do distinguish them? I'm guessing it's not but I'm wondering about my next step to require player_two to send exact amount and next allowing the winer to withdraw a correct amount of lamports deducted byt transactions fee etc.

1 Answer 1

  1. You can store the total lamports bid by the players in the PDA state. You can store it in the following way:
pub struct Game {
    pub total_bids: u64,

You can access this state in your Program easily.

You can transfer Sol from player to PDA by simple Transfer function. You can use the following function


Where User is the one who sends Lamports and game is the lamports.

You can withdraw from PDA using the following Code:

 **game.to_account_info().try_borrow_mut_lamports()? -= game.total_bid;
  **user.to_account_info().try_borrow_mut_lamports()? += game.total_bid;

This is the core functions that need to be called. Hope this helps

  • Thanks for that. It's nice that you confirmed that in such a case Sol can be keept by PDA account and next withdrawn from it. Additionally could you explain or share any source where I can read a bit more why for withdrawing the trick with try_borrow_mut_lamports() should work? And why it should not be a transfer like it was done for transferring Sol into PDA? Commented Oct 25, 2022 at 6:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.