2

I'm working on a simple proof of concept guessing game like Clue, written in Anchor Lang, and I'm having trouble getting one of my transactions to work correctly.

Here is the code in question:

// lib.rs
...
#[derive(Accounts)]
#[instruction(murderer: u8, weapon: u8, room: u8)]
pub struct Guess<'info> {
    #[account(seeds = [b"clue"], bump)]
    game: Account<'info, Game>, // initialized in previous instruction

    #[account(mut)]
    user: Signer<'info>,

    #[account(mut)]
    user_usdc_account: Account<'info, TokenAccount>,

    #[account(mut)]
    team_usdc_account: Account<'info, TokenAccount>,

    #[account(
        seeds = [usdc_mint.key().as_ref()], 
        bump, 
        token::mint = usdc_mint, 
        token::authority = game
    )]
    prize_pool: Account<'info, TokenAccount>, // this is a PDA and a TokenAccount, the goal is that the program holds a prize pool until someone guesses correctly.

    #[account(mut)]
    usdc_mint: Account<'info, Mint>,
    token_program: Program<'info, Token>,
    system_program: Program<'info, System>,
}
...

This is how I'm setting up the test:

// clue.ts
...
const user = Keypair.generate();
const team = Keypair.generate();

await airdrop(user.publicKey, connection);
await airdrop(team.publicKey, connection);

await mintTo(connection, user, usdcMint, user.publicKey, mintAuthority, 20);
await mintTo(connection, team, usdcMint, team.publicKey, mintAuthority, 20);

const userUsdcAccount = await getOrCreateAssociatedTokenAccount(
  connection,
  user,
  usdcMint,
  user.publicKey
);
const teamUsdcAccount = await getOrCreateAssociatedTokenAccount(
  connection,
  team,
  usdcMint,
  team.publicKey
);

try {
  await connection.confirmTransaction(
    await program.methods
      .guess(1, 0, 0)
      .accounts({
        game,
        user: user.publicKey,
        userUsdcAccount: userUsdcAccount.address,
        teamUsdcAccount: teamUsdcAccount.address,
        prizePool,
        usdcMint,
        tokenProgram: TOKEN_PROGRAM_ID,
        systemProgram: SystemProgram.programId,
      })
      .signers([user])
      .rpc(),
    "confirmed"
  );

  const gameAccount = (await program.account.game.all())[0].account;
  console.log("gameAccount:", gameAccount);
  console.log(await getAccount(connection, prizePool));
  assert.isTrue(true);
} catch (e) {
  assert.fail(e);
}
...

The error I'm getting is: Error: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: invalid account data for instruction

I'm not sure what's going on here. I'm initializing the game and prize_pool accounts earlier in the same test. I'm initializing them like this:

// clue.ts
...
let authority: Keypair;
let game: PublicKey;
let bump: number;
let usdcMint: PublicKey;
let prizePool: PublicKey;
const mintAuthority = Keypair.generate();

before(async () => {
  authority = (provider.wallet as NodeWallet).payer;

  const gPDA = PublicKey.findProgramAddressSync(
    [Buffer.from("clue")],
    program.programId
  );
  game = gPDA[0];
  bump = gPDA[1];

  usdcMint = await createMint(
    connection,
    authority,
    mintAuthority.publicKey,
    mintAuthority.publicKey,
    9
  );

  const pPool = PublicKey.findProgramAddressSync(
    [usdcMint.toBuffer()],
    program.programId
  );
  prizePool = pPool[0];
  console.log(`Prize Pool PubKey: ${prizePool.toString()}`);
});
...

My suspicion is that it is the PDA/TokenAccount prize_pool, but I'm unsure. The goal of the prize_pool is that it should be a TokenAccount owned by the program that can send and receive USDC.

Any and all help is appreciated. Thanks in advance.

1 Answer 1

2

The issue may be because the game and prize_pool token account haven't been created yet.

The code you've provided where you mention initializing the game and prizePool accounts only derives the PDAs. (findProgramAddressSync only derives the PDA, but does not initialize any accounts).

  const gPDA = PublicKey.findProgramAddressSync(
    [Buffer.from("clue")],
    program.programId
  );

  const pPool = PublicKey.findProgramAddressSync(
    [usdcMint.toBuffer()],
    program.programId
  );

Is there another instruction in your program that initializes the game account and the prize_pool token account?

1
  • Thanks for that. I'll make some updates and report back đź’Ş
    – mmelvin0x
    May 15, 2023 at 12:26

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.