anchor_lang/accounts/
account.rs

1//! Account container that checks ownership on deserialization.
2
3use crate::bpf_writer::BpfWriter;
4use crate::error::{Error, ErrorCode};
5use crate::{
6    AccountDeserialize, AccountSerialize, Accounts, AccountsClose, AccountsExit, Key, Owner,
7    Result, ToAccountInfo, ToAccountInfos, ToAccountMetas,
8};
9use solana_program::account_info::AccountInfo;
10use solana_program::instruction::AccountMeta;
11use solana_program::pubkey::Pubkey;
12use solana_program::system_program;
13use std::collections::BTreeSet;
14use std::fmt;
15use std::ops::{Deref, DerefMut};
16
17/// Wrapper around [`AccountInfo`](crate::solana_program::account_info::AccountInfo)
18/// that verifies program ownership and deserializes underlying data into a Rust type.
19///
20/// # Table of Contents
21/// - [Basic Functionality](#basic-functionality)
22/// - [Using Account with non-anchor types](#using-account-with-non-anchor-types)
23/// - [Out of the box wrapper types](#out-of-the-box-wrapper-types)
24///
25/// # Basic Functionality
26///
27/// Account checks that `Account.info.owner == T::owner()`.
28/// This means that the data type that Accounts wraps around (`=T`) needs to
29/// implement the [Owner trait](crate::Owner).
30/// The `#[account]` attribute implements the Owner trait for
31/// a struct using the `crate::ID` declared by [`declare_id`](crate::declare_id)
32/// in the same program. It follows that Account can also be used
33/// with a `T` that comes from a different program.
34///
35/// Checks:
36///
37/// - `Account.info.owner == T::owner()`
38/// - `!(Account.info.owner == SystemProgram && Account.info.lamports() == 0)`
39///
40/// # Example
41/// ```ignore
42/// use anchor_lang::prelude::*;
43/// use other_program::Auth;
44///
45/// declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
46///
47/// #[program]
48/// mod hello_anchor {
49///     use super::*;
50///     pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
51///         if (*ctx.accounts.auth_account).authorized {
52///             (*ctx.accounts.my_account).data = data;
53///         }
54///         Ok(())
55///     }
56/// }
57///
58/// #[account]
59/// #[derive(Default)]
60/// pub struct MyData {
61///     pub data: u64
62/// }
63///
64/// #[derive(Accounts)]
65/// pub struct SetData<'info> {
66///     #[account(mut)]
67///     pub my_account: Account<'info, MyData> // checks that my_account.info.owner == Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS
68///     pub auth_account: Account<'info, Auth> // checks that auth_account.info.owner == FEZGUxNhZWpYPj9MJCrZJvUo1iF9ys34UHx52y4SzVW9
69/// }
70///
71/// // In a different program
72///
73/// ...
74/// declare_id!("FEZGUxNhZWpYPj9MJCrZJvUo1iF9ys34UHx52y4SzVW9");
75/// #[account]
76/// #[derive(Default)]
77/// pub struct Auth {
78///     pub authorized: bool
79/// }
80/// ...
81/// ```
82///
83/// # Using Account with non-anchor programs
84///
85/// Account can also be used with non-anchor programs. The data types from
86/// those programs are not annotated with `#[account]` so you have to
87/// - create a wrapper type around the structs you want to wrap with Account
88/// - implement the functions required by Account yourself
89///
90/// instead of using `#[account]`. You only have to implement a fraction of the
91/// functions `#[account]` generates. See the example below for the code you have
92/// to write.
93///
94/// The mint wrapper type that Anchor provides out of the box for the token program ([source](https://github.com/coral-xyz/anchor/blob/master/spl/src/token.rs))
95/// ```ignore
96/// #[derive(Clone)]
97/// pub struct Mint(spl_token::state::Mint);
98///
99/// // This is necessary so we can use "anchor_spl::token::Mint::LEN"
100/// // because rust does not resolve "anchor_spl::token::Mint::LEN" to
101/// // "spl_token::state::Mint::LEN" automatically
102/// impl Mint {
103///     pub const LEN: usize = spl_token::state::Mint::LEN;
104/// }
105///
106/// // You don't have to implement the "try_deserialize" function
107/// // from this trait. It delegates to
108/// // "try_deserialize_unchecked" by default which is what we want here
109/// // because non-anchor accounts don't have a discriminator to check
110/// impl anchor_lang::AccountDeserialize for Mint {
111///     fn try_deserialize_unchecked(buf: &mut &[u8]) -> Result<Self> {
112///         spl_token::state::Mint::unpack(buf).map(Mint)
113///     }
114/// }
115/// // AccountSerialize defaults to a no-op which is what we want here
116/// // because it's a foreign program, so our program does not
117/// // have permission to write to the foreign program's accounts anyway
118/// impl anchor_lang::AccountSerialize for Mint {}
119///
120/// impl anchor_lang::Owner for Mint {
121///     fn owner() -> Pubkey {
122///         // pub use spl_token::ID is used at the top of the file
123///         ID
124///     }
125/// }
126///
127/// // Implement the "std::ops::Deref" trait for better user experience
128/// impl Deref for Mint {
129///     type Target = spl_token::state::Mint;
130///
131///     fn deref(&self) -> &Self::Target {
132///         &self.0
133///     }
134/// }
135/// ```
136///
137/// ## Out of the box wrapper types
138///
139/// ### Accessing BPFUpgradeableLoader Data
140///
141/// Anchor provides wrapper types to access data stored in programs owned by the BPFUpgradeableLoader
142/// such as the upgrade authority. If you're interested in the data of a program account, you can use
143/// ```ignore
144/// Account<'info, BpfUpgradeableLoaderState>
145/// ```
146/// and then match on its contents inside your instruction function.
147///
148/// Alternatively, you can use
149/// ```ignore
150/// Account<'info, ProgramData>
151/// ```
152/// to let anchor do the matching for you and return the ProgramData variant of BpfUpgradeableLoaderState.
153///
154/// # Example
155/// ```ignore
156/// use anchor_lang::prelude::*;
157/// use crate::program::MyProgram;
158///
159/// declare_id!("Cum9tTyj5HwcEiAmhgaS7Bbj4UczCwsucrCkxRECzM4e");
160///
161/// #[program]
162/// pub mod my_program {
163///     use super::*;
164///
165///     pub fn set_initial_admin(
166///         ctx: Context<SetInitialAdmin>,
167///         admin_key: Pubkey
168///     ) -> Result<()> {
169///         ctx.accounts.admin_settings.admin_key = admin_key;
170///         Ok(())
171///     }
172///
173///     pub fn set_admin(...){...}
174///
175///     pub fn set_settings(...){...}
176/// }
177///
178/// #[account]
179/// #[derive(Default, Debug)]
180/// pub struct AdminSettings {
181///     admin_key: Pubkey
182/// }
183///
184/// #[derive(Accounts)]
185/// pub struct SetInitialAdmin<'info> {
186///     #[account(init, payer = authority, seeds = [b"admin"], bump)]
187///     pub admin_settings: Account<'info, AdminSettings>,
188///     #[account(mut)]
189///     pub authority: Signer<'info>,
190///     #[account(constraint = program.programdata_address()? == Some(program_data.key()))]
191///     pub program: Program<'info, MyProgram>,
192///     #[account(constraint = program_data.upgrade_authority_address == Some(authority.key()))]
193///     pub program_data: Account<'info, ProgramData>,
194///     pub system_program: Program<'info, System>,
195/// }
196/// ```
197///
198/// This example solves a problem you may face if your program has admin settings: How do you set the
199/// admin key for restricted functionality after deployment? Setting the admin key itself should
200/// be a restricted action but how do you restrict it without having set an admin key?
201/// You're stuck in a loop.
202/// One solution is to use the upgrade authority of the program as the initial
203/// (or permanent) admin key.
204///
205/// ### SPL Types
206///
207/// Anchor provides wrapper types to access accounts owned by the token program. Use
208/// ```ignore
209/// use anchor_spl::token::TokenAccount;
210///
211/// #[derive(Accounts)]
212/// pub struct Example {
213///     pub my_acc: Account<'info, TokenAccount>
214/// }
215/// ```
216/// to access token accounts and
217/// ```ignore
218/// use anchor_spl::token::Mint;
219///
220/// #[derive(Accounts)]
221/// pub struct Example {
222///     pub my_acc: Account<'info, Mint>
223/// }
224/// ```
225/// to access mint accounts.
226#[derive(Clone)]
227pub struct Account<'info, T: AccountSerialize + AccountDeserialize + Clone> {
228    account: T,
229    info: &'info AccountInfo<'info>,
230}
231
232impl<T: AccountSerialize + AccountDeserialize + Clone + fmt::Debug> fmt::Debug for Account<'_, T> {
233    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234        self.fmt_with_name("Account", f)
235    }
236}
237
238impl<T: AccountSerialize + AccountDeserialize + Clone + fmt::Debug> Account<'_, T> {
239    pub(crate) fn fmt_with_name(&self, name: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240        f.debug_struct(name)
241            .field("account", &self.account)
242            .field("info", &self.info)
243            .finish()
244    }
245}
246
247impl<'a, T: AccountSerialize + AccountDeserialize + Clone> Account<'a, T> {
248    pub(crate) fn new(info: &'a AccountInfo<'a>, account: T) -> Account<'a, T> {
249        Self { info, account }
250    }
251
252    pub(crate) fn exit_with_expected_owner(
253        &self,
254        expected_owner: &Pubkey,
255        program_id: &Pubkey,
256    ) -> Result<()> {
257        // Only persist if the owner is the current program and the account is not closed.
258        if expected_owner == program_id && !crate::common::is_closed(self.info) {
259            let mut data = self.info.try_borrow_mut_data()?;
260            let dst: &mut [u8] = &mut data;
261            let mut writer = BpfWriter::new(dst);
262            self.account.try_serialize(&mut writer)?;
263        }
264        Ok(())
265    }
266
267    /// Reloads the account from storage. This is useful, for example, when
268    /// observing side effects after CPI.
269    pub fn reload(&mut self) -> Result<()> {
270        let mut data: &[u8] = &self.info.try_borrow_data()?;
271        self.account = T::try_deserialize(&mut data)?;
272        Ok(())
273    }
274
275    pub fn into_inner(self) -> T {
276        self.account
277    }
278
279    /// Sets the inner account.
280    ///
281    /// Instead of this:
282    /// ```ignore
283    /// pub fn new_user(ctx: Context<CreateUser>, new_user:User) -> Result<()> {
284    ///     (*ctx.accounts.user_to_create).name = new_user.name;
285    ///     (*ctx.accounts.user_to_create).age = new_user.age;
286    ///     (*ctx.accounts.user_to_create).address = new_user.address;
287    /// }
288    /// ```
289    /// You can do this:
290    /// ```ignore
291    /// pub fn new_user(ctx: Context<CreateUser>, new_user:User) -> Result<()> {
292    ///     ctx.accounts.user_to_create.set_inner(new_user);
293    /// }
294    /// ```
295    pub fn set_inner(&mut self, inner: T) {
296        self.account = inner;
297    }
298}
299
300impl<'a, T: AccountSerialize + AccountDeserialize + Owner + Clone> Account<'a, T> {
301    /// Deserializes the given `info` into a `Account`.
302    #[inline(never)]
303    pub fn try_from(info: &'a AccountInfo<'a>) -> Result<Account<'a, T>> {
304        if info.owner == &system_program::ID && info.lamports() == 0 {
305            return Err(ErrorCode::AccountNotInitialized.into());
306        }
307        if info.owner != &T::owner() {
308            return Err(Error::from(ErrorCode::AccountOwnedByWrongProgram)
309                .with_pubkeys((*info.owner, T::owner())));
310        }
311        let mut data: &[u8] = &info.try_borrow_data()?;
312        Ok(Account::new(info, T::try_deserialize(&mut data)?))
313    }
314
315    /// Deserializes the given `info` into a `Account` without checking
316    /// the account discriminator. Be careful when using this and avoid it if
317    /// possible.
318    #[inline(never)]
319    pub fn try_from_unchecked(info: &'a AccountInfo<'a>) -> Result<Account<'a, T>> {
320        if info.owner == &system_program::ID && info.lamports() == 0 {
321            return Err(ErrorCode::AccountNotInitialized.into());
322        }
323        if info.owner != &T::owner() {
324            return Err(Error::from(ErrorCode::AccountOwnedByWrongProgram)
325                .with_pubkeys((*info.owner, T::owner())));
326        }
327        let mut data: &[u8] = &info.try_borrow_data()?;
328        Ok(Account::new(info, T::try_deserialize_unchecked(&mut data)?))
329    }
330}
331
332impl<'info, B, T: AccountSerialize + AccountDeserialize + Owner + Clone> Accounts<'info, B>
333    for Account<'info, T>
334where
335    T: AccountSerialize + AccountDeserialize + Owner + Clone,
336{
337    #[inline(never)]
338    fn try_accounts(
339        _program_id: &Pubkey,
340        accounts: &mut &'info [AccountInfo<'info>],
341        _ix_data: &[u8],
342        _bumps: &mut B,
343        _reallocs: &mut BTreeSet<Pubkey>,
344    ) -> Result<Self> {
345        if accounts.is_empty() {
346            return Err(ErrorCode::AccountNotEnoughKeys.into());
347        }
348        let account = &accounts[0];
349        *accounts = &accounts[1..];
350        Account::try_from(account)
351    }
352}
353
354impl<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> AccountsExit<'info>
355    for Account<'info, T>
356{
357    fn exit(&self, program_id: &Pubkey) -> Result<()> {
358        self.exit_with_expected_owner(&T::owner(), program_id)
359    }
360}
361
362impl<'info, T: AccountSerialize + AccountDeserialize + Clone> AccountsClose<'info>
363    for Account<'info, T>
364{
365    fn close(&self, sol_destination: AccountInfo<'info>) -> Result<()> {
366        crate::common::close(self.to_account_info(), sol_destination)
367    }
368}
369
370impl<T: AccountSerialize + AccountDeserialize + Clone> ToAccountMetas for Account<'_, T> {
371    fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
372        let is_signer = is_signer.unwrap_or(self.info.is_signer);
373        let meta = match self.info.is_writable {
374            false => AccountMeta::new_readonly(*self.info.key, is_signer),
375            true => AccountMeta::new(*self.info.key, is_signer),
376        };
377        vec![meta]
378    }
379}
380
381impl<'info, T: AccountSerialize + AccountDeserialize + Clone> ToAccountInfos<'info>
382    for Account<'info, T>
383{
384    fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
385        vec![self.info.clone()]
386    }
387}
388
389impl<'info, T: AccountSerialize + AccountDeserialize + Clone> AsRef<AccountInfo<'info>>
390    for Account<'info, T>
391{
392    fn as_ref(&self) -> &AccountInfo<'info> {
393        self.info
394    }
395}
396
397impl<T: AccountSerialize + AccountDeserialize + Clone> AsRef<T> for Account<'_, T> {
398    fn as_ref(&self) -> &T {
399        &self.account
400    }
401}
402
403impl<T: AccountSerialize + AccountDeserialize + Clone> Deref for Account<'_, T> {
404    type Target = T;
405
406    fn deref(&self) -> &Self::Target {
407        &(self).account
408    }
409}
410
411impl<T: AccountSerialize + AccountDeserialize + Clone> DerefMut for Account<'_, T> {
412    fn deref_mut(&mut self) -> &mut Self::Target {
413        #[cfg(feature = "anchor-debug")]
414        if !self.info.is_writable {
415            solana_program::msg!("The given Account is not mutable");
416            panic!();
417        }
418        &mut self.account
419    }
420}
421
422impl<T: AccountSerialize + AccountDeserialize + Clone> Key for Account<'_, T> {
423    fn key(&self) -> Pubkey {
424        *self.info.key
425    }
426}