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.