1

I'm trying to make a simple vault program. When testing the program, I receive the following error.

Error: AnchorError caused by account: vault. Error Code: AccountDidNotDeserialize. Error Number: 3003. Error Message: Failed to deserialize the account.

Here is my code for program:

#[derive(Accounts)]
pub struct InitializeGame<'info> {
    #[account(
        init,
        payer = player,
        space = Game::MAX_SIZE,
        seeds = [
            b"game_account",
        ],
        bump
    )]
    pub game_account: Account<'info, Game>,
    #[account(
        init,
        payer = player,
        space = Vault::MAX_SIZE,
        seeds = [
            b"vault",
        ],
        bump
    )]
    pub vault: Account<'info, Vault>,
    #[account(mut)]
    pub player: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[account]
pub struct Vault {
    pub creator: Pubkey,
    pub token_count: u16,
    pub authority: Pubkey,
    pub authority_seed: Pubkey,
    pub is_initialized: bool,
    bump: u8
}
impl Vault {
    const MAX_SIZE: usize = 32 + 2 + 32 + 32 + 1 + 1;
}

Here is code for my client tests:

const derivePda = async (seed: String) => {
    let [pda, bump] = await anchor.web3.PublicKey.findProgramAddress(
      [
        Buffer.from(seed),
      ],
      program.programId,
    )
    return {pda: pda, bump: bump};
  }

const initializeGameAccount = async (
    gameId: number,
    wallet: anchor.web3.Keypair,
    pda: anchor.web3.PublicKey,
    bump: number,
    v_pda: anchor.web3.PublicKey,
    amount: number,
  ) => {
    await program.methods.initializeGame(gameId, amount)
      .accounts({
        gameAccount: pda,
        vault: v_pda,
        player: wallet.publicKey,
      })
      .signers([wallet])
      .rpc();
}

it("Is initialized!", async () => {
    // Add your test here.
    const keypair1 = await getKeypair();
    const {pda, bump} = await derivePda("game_account");
    const {pda: v_pda} = await derivePda("vault");

    const tx = await initializeGameAccount(1, keypair1, pda, bump, v_pda, 3);

    console.log(`Your tx signature is: ${JSON.stringify(tx)}`);
    console.log(`Your tx signature is: ${tx}`);
}

My code used to work as intended when I would also use my pubkey as a seed for both game_account and vault. And subsequently, also using my pubkey as seeds from client side.

The reason why I changed the code was because intended behavior is for n<=50 players to transfer sol to the vault.

Maybe this is where my understanding of PDA's is flawed. But since new players won't know what the vault's creator's pubkey is, their client would have no way of generating the address needed for the ix?

Any help or explanation would be so so appreciated. Thanks!

2
  • Could you post your code for your Vault type? That is the account that is failing to deserialize, which means most likely one of two things: 1. Vault::LEN is the wrong value. 2. The account exists on the cluster you're targeting for your tests, but its data is an old, incompatible format compared to some alteration to the program.
    – HelmetFace
    Aug 13, 2022 at 19:25
  • Hi ser, made the edit above! I'll try using a fresh keypair to build, deploy, and to run the initialize ix
    – TLS
    Aug 13, 2022 at 19:32

1 Answer 1

6

Include an extra 8 bytes for the account discriminator that anchor adds when initializing a new account

Try:

#[account(
        init,
        payer = player,
        space = 8 + Vault::MAX_SIZE,
        seeds = [
            b"vault",
        ],
        bump
    )]
    pub vault: Account<'info, Vault>,

or

impl Vault {
    const MAX_SIZE: usize = 8 + 32 + 2 + 32 + 32 + 1 + 1;
}

From anchor-lang doc describing init:

When using the space constraint, one must remember to add 8 to it which is the size of the account discriminator. This only has to be done for accounts owned by anchor programs.

https://docs.rs/anchor-lang/latest/anchor_lang/derive.Accounts.html

From anchor-lang doc describing #[account]:

When implementing account serialization traits the first 8 bytes are reserved for a unique account discriminator, self described by the first 8 bytes of the SHA256 of the account’s Rust ident.

As a result, any calls to AccountDeserialize’s try_deserialize will check this discriminator. If it doesn’t match, an invalid account was given, and the account deserialization will exit with an error.

https://docs.rs/anchor-lang/latest/anchor_lang/attr.account.html

1
  • 1
    My goodness what an oversight on my part. Thank you good ser!
    – TLS
    Aug 13, 2022 at 20:23

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.