coral-xyz / anchor

⚓ Solana Sealevel Framework
https://anchor-lang.com
Apache License 2.0
3.36k stars 1.25k forks source link

bug: Wrong order parsing of arguments when using instruction constraint #2985

Closed cryptopapi997 closed 1 month ago

cryptopapi997 commented 1 month ago

If we define an instruction like this

#[derive(Accounts)]
#[instruction(_num1 : u64)]
pub struct Demo<'info> {
    #[account(mut)]
    pub user: Signer<'info>,
    #[account(seeds = [b"Demo".as_ref(), _num1.to_le_bytes().as_ref()], bump)]
    pub demo: Account<'info, DemoAccount>,
}

pub fn demo(_ctx: Context<Demo>, _num0: u64, _num1: u64) -> Result<()> {
    Ok(())
}

and then try to call it like this (assuming num1 in typescript is the num1 that was used to derive demoAcc)

    await program.methods.demo(num0, num1,).accounts({
      user: myKp.publicKey,
      demo: demoAcc,
    }).signers([myKp]).rpc();

We get the following error

Error: AnchorError caused by account: demo. Error Code: ConstraintSeeds. Error Number: 2006. Error Message: A seeds constraint was violated.
Program log: Left:
Program log: GpDu71LGcRtfqeUJTF9iW4TGmosmkJBqouHgQTaHa7c6
Program log: Right:
Program log: 4zBsh8sitoS6HBWKG6BPwbtuEUGRYgc8cPS2PsYMh55W

On the other hand, if we switch the parameter that's used in the PDA derivation to come first (even though that's the wrong order for the instruction) like below, it works fine.

    await program.methods.demo(num1,num0).accounts({
      user: myKp.publicKey,
      demo: demoAcc,
    }).signers([myKp]).rpc();

This is a bug, as from reading the instruction function you'd think the right way to do it would be to pass num0 as the first param. I've created an MRE here: https://github.com/cryptopapi997/anchor-mre

acheroncrypto commented 1 month ago

This is a known limitation and is documented in #[instruction] attribute's documentation.

You can access the instruction’s arguments with the #[instruction(..)] attribute. You have to list them in the same order as in the instruction but you can omit all arguments after the last one you need.

As the documentation suggests, you have to list num0 and then num1 to make it work as expected. If you were using num0 instead, you could have ommitted num1.

cryptopapi997 commented 1 month ago

My mistake, thank you for clarifying