pub struct Account<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> { /* private fields */ }
Expand description

Wrapper around AccountInfo that verifies program ownership and deserializes underlying data into a Rust type.

Table of Contents

Basic Functionality

Account checks that Account.info.owner == T::owner(). This means that the data type that Accounts wraps around (=T) needs to implement the Owner trait. The #[account] attribute implements the Owner trait for a struct using the crate::ID declared by declareId in the same program. It follows that Account can also be used with a T that comes from a different program.

Checks:

  • Account.info.owner == T::owner()
  • !(Account.info.owner == SystemProgram && Account.info.lamports() == 0)

Example

use anchor_lang::prelude::*;
use other_program::Auth;

declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");

#[program]
mod hello_anchor {
    use super::*;
    pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
        if (*ctx.accounts.auth_account).authorized {
            (*ctx.accounts.my_account).data = data;
        }
        Ok(())
    }
}

#[account]
#[derive(Default)]
pub struct MyData {
    pub data: u64
}

#[derive(Accounts)]
pub struct SetData<'info> {
    #[account(mut)]
    pub my_account: Account<'info, MyData> // checks that my_account.info.owner == Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS
    pub auth_account: Account<'info, Auth> // checks that auth_account.info.owner == FEZGUxNhZWpYPj9MJCrZJvUo1iF9ys34UHx52y4SzVW9
}

// In a different program

...
declare_id!("FEZGUxNhZWpYPj9MJCrZJvUo1iF9ys34UHx52y4SzVW9");
#[account]
#[derive(Default)]
pub struct Auth {
    pub authorized: bool
}
...

Using Account with non-anchor programs

Account can also be used with non-anchor programs. The data types from those programs are not annotated with #[account] so you have to

  • create a wrapper type around the structs you want to wrap with Account
  • implement the functions required by Account yourself instead of using #[account]. You only have to implement a fraction of the functions #[account] generates. See the example below for the code you have to write.

The mint wrapper type that Anchor provides out of the box for the token program (source)

#[derive(Clone)]
pub struct Mint(spl_token::state::Mint);

// This is necessary so we can use "anchor_spl::token::Mint::LEN"
// because rust does not resolve "anchor_spl::token::Mint::LEN" to
// "spl_token::state::Mint::LEN" automatically
impl Mint {
    pub const LEN: usize = spl_token::state::Mint::LEN;
}

// You don't have to implement the "try_deserialize" function
// from this trait. It delegates to
// "try_deserialize_unchecked" by default which is what we want here
// because non-anchor accounts don't have a discriminator to check
impl anchor_lang::AccountDeserialize for Mint {
    fn try_deserialize_unchecked(buf: &mut &[u8]) -> Result<Self> {
        spl_token::state::Mint::unpack(buf).map(Mint)
    }
}
// AccountSerialize defaults to a no-op which is what we want here
// because it's a foreign program, so our program does not
// have permission to write to the foreign program's accounts anyway
impl anchor_lang::AccountSerialize for Mint {}

impl anchor_lang::Owner for Mint {
    fn owner() -> Pubkey {
        // pub use spl_token::ID is used at the top of the file
        ID
    }
}

// Implement the "std::ops::Deref" trait for better user experience
impl Deref for Mint {
    type Target = spl_token::state::Mint;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

Out of the box wrapper types

Accessing BPFUpgradeableLoader Data

Anchor provides wrapper types to access data stored in programs owned by the BPFUpgradeableLoader such as the upgrade authority. If you’re interested in the data of a program account, you can use

Account<'info, BpfUpgradeableLoaderState>

and then match on its contents inside your instruction function.

Alternatively, you can use

Account<'info, ProgramData>

to let anchor do the matching for you and return the ProgramData variant of BpfUpgradeableLoaderState.

Example

use anchor_lang::prelude::*;
use crate::program::MyProgram;

declare_id!("Cum9tTyj5HwcEiAmhgaS7Bbj4UczCwsucrCkxRECzM4e");

#[program]
pub mod my_program {
    use super::*;

    pub fn set_initial_admin(
        ctx: Context<SetInitialAdmin>,
        admin_key: Pubkey
    ) -> Result<()> {
        ctx.accounts.admin_settings.admin_key = admin_key;
        Ok(())
    }

    pub fn set_admin(...){...}

    pub fn set_settings(...){...}
}

#[account]
#[derive(Default, Debug)]
pub struct AdminSettings {
    admin_key: Pubkey
}

#[derive(Accounts)]
pub struct SetInitialAdmin<'info> {
    #[account(init, payer = authority, seeds = [b"admin"], bump)]
    pub admin_settings: Account<'info, AdminSettings>,
    #[account(mut)]
    pub authority: Signer<'info>,
    #[account(constraint = program.programdata_address()? == Some(program_data.key()))]
    pub program: Program<'info, MyProgram>,
    #[account(constraint = program_data.upgrade_authority_address == Some(authority.key()))]
    pub program_data: Account<'info, ProgramData>,
    pub system_program: Program<'info, System>,
}

This example solves a problem you may face if your program has admin settings: How do you set the admin key for restricted functionality after deployment? Setting the admin key itself should be a restricted action but how do you restrict it without having set an admin key? You’re stuck in a loop. One solution is to use the upgrade authority of the program as the initial (or permanent) admin key.

SPL Types

Anchor provides wrapper types to access accounts owned by the token program. Use

use anchor_spl::token::TokenAccount;

#[derive(Accounts)]
pub struct Example {
    pub my_acc: Account<'info, TokenAccount>
}

to access token accounts and

use anchor_spl::token::Mint;

#[derive(Accounts)]
pub struct Example {
    pub my_acc: Account<'info, Mint>
}

to access mint accounts.

Implementations

Deserializes the given info into a Account.

Deserializes the given info into a Account without checking the account discriminator. Be careful when using this and avoid it if possible.

Reloads the account from storage. This is useful, for example, when observing side effects after CPI.

Sets the inner account.

Instead of this:

pub fn new_user(ctx: Context<CreateUser>, new_user:User) -> Result<()> {
    (*ctx.accounts.user_to_create).name = new_user.name;
    (*ctx.accounts.user_to_create).age = new_user.age;
    (*ctx.accounts.user_to_create).address = new_user.address;
}

You can do this:

pub fn new_user(ctx: Context<CreateUser>, new_user:User) -> Result<()> {
    ctx.accounts.user_to_create.set_inner(new_user);
}

Trait Implementations

Returns the validated accounts struct. What constitutes “valid” is program dependent. However, users of these types should never have to worry about account substitution attacks. For example, if a program expects a Mint account from the SPL token program in a particular field, then it should be impossible for this method to return Ok if any other account type is given–from the SPL token program or elsewhere. Read more

This function is for INTERNAL USE ONLY. Do NOT use this function in a program. Manual closing of Account<'info, T> types is NOT supported.

Details: Using close with Account<'info, T> is not safe because it requires the mut constraint but for that type the constraint overwrites the “closed account” discriminator at the end of the instruction.

program_id is the currently executing program.

Converts this type into a shared reference of the (usually inferred) input type.

Converts this type into a shared reference of the (usually inferred) input type.

Returns a copy of the value. Read more

Performs copy-assignment from source. Read more

Formats the value using the given formatter. Read more

The resulting type after dereferencing.

Dereferences the value.

Mutably dereferences the value.

is_signer is given as an optional override for the signer meta field. This covers the edge case when a program-derived-address needs to relay a transaction from a client to another program but sign the transaction before the relay. The client cannot mark the field as a signer, and so we have to override the is_signer meta field given by the client. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The alignment of pointer.

The type for initializers.

Initializes a with the given initializer. Read more

Dereferences the given pointer. Read more

Mutably dereferences the given pointer. Read more

Drops the object pointed to by the given pointer. Read more

Should always be Self

The resulting type after obtaining ownership.

Creates owned data from borrowed data, usually by cloning. Read more

Uses borrowed data to replace owned data, usually by cloning. Read more

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.