1

I'm looking for clarification on when and why I should use the 'AccountInfo' type instead of passing an account as a function parameter in anchor_lang.

For example:

Both following programs do the same thing. Both have been tested to work.

Using AccountInfo:

#[program]
mod hello_friend {
    use super::*;
    pub fn initialize(ctx: Context<Initialize>, friend_address: Pubkey) -> Result<()> {
        ctx.accounts.new_account.friend_address = friend_address;
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = signer, space = 8 + 32)]
    pub new_account: Account<'info, NewAccount>,
    #[account(mut)]
    pub signer: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[account]
pub struct NewAccount {
    friend_address: Pubkey,
}

Not using AccountInfo:

#[program]
mod hello_friend {
    use super::*;
    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        ctx.accounts.new_account.friend_address = ctx.accounts.friend_address.key();
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = signer, space = 8 + 32)]
    pub new_account: Account<'info, NewAccount>,
    /// CHECK: Your friend's wallet address
    pub friend_address: AccountInfo<'info>,
    #[account(mut)]
    pub signer: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[account]
pub struct NewAccount {
    friend_address: Pubkey,
}

Is there a reason why I would use one method over the other? Which one is best practice?

2 Answers 2

2

There is a difference between an 'account' and a 'public key'. In the given example, you are just saving the public key of friend_address account in your new_account so it can be achieved by simply passing the public key as an argument.

But if you want to read from or write to an account, you have to pass the account in the instruction. Suppose in the above case, instead of public key if you wanted to read the data field of friend_address account, you can't do that by simply passing the public key of the account as argument, but had to pass the account in the instruction.

1
  • That makes a lot of sense, thank you! This was on my mind for a while. This was the answer I was looking for. Feb 6 at 21:26
2

It's usually preferable to validate an account using one of the supported types, which is one of the benefits of using Anchor.

Using AccountInfo performs no addition checks on the account provided to the instruction:

pub new_account: AccountInfo<'info>,

Anchor provides an UncheckedAccount type which is the equivalent of using AccountInfo:

pub new_account: UncheckedAccount<'info>,

If you use the Account wrapper like this:

pub new_account: Account<'info, NewAccount>

Then Anchor will automatically try to validate the account (new_account) provided to the instruction and deserialize the account data (as NewAccount type).

pub struct AccountInfo<'a> {
    pub key: &'a Pubkey,
    pub is_signer: bool,
    pub is_writable: bool,
    pub lamports: Rc<RefCell<&'a mut u64>>,
    pub data: Rc<RefCell<&'a mut [u8]>>,    // <---- deserializes account data
    pub owner: &'a Pubkey,    // <---- checks owner program
    pub executable: bool,
    pub rent_epoch: u64,
}

Here is a list of Account types that can be used in the account validation struct: https://docs.rs/anchor-lang/latest/anchor_lang/accounts/index.html

You can also use the anchor_spl crate for working with the token program in Anchor: https://docs.rs/anchor-spl/latest/anchor_spl/

3
  • Thanks for your answer. I'm trying to understand why the AccountInfo and UncheckedAccount types are actually needed though. Why even use the account type if you don't want anchor to perform checks? Why not just pass it as a function parameter? Feb 6 at 21:06
  • Any accounts used in the instruction would need to be included in the account validation struct. When to use the UncheckedAccount type would be dependent on the program, which you can use ///Check: to leave a comment for why the account is unchecked. You might see something like /// CHECK: This is not dangerous because we don't read or write from this account
    – john
    Feb 6 at 22:21
  • 1
    If you are passing accounts to another instruction via CPI, you might accept them in your program as UncheckedAccount or AccountInfo, since the other program will perform those Anchor checks anyways.
    – Whiteseal
    Feb 6 at 23:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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