anchor_lang/accounts/
interface_account.rs

1//! Account container that checks ownership on deserialization.
2
3use crate::accounts::account::Account;
4use crate::error::ErrorCode;
5use crate::{
6    AccountDeserialize, AccountSerialize, Accounts, AccountsClose, AccountsExit, CheckOwner, Key,
7    Owners, Result, 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 InterfaceAccount with non-anchor types](#using-interface-account-with-non-anchor-types)
23/// - [Out of the box wrapper types](#out-of-the-box-wrapper-types)
24///
25/// # Basic Functionality
26///
27/// InterfaceAccount checks that `T::owners().contains(Account.info.owner)`.
28/// This means that the data type that Accounts wraps around (`=T`) needs to
29/// implement the [Owners trait](crate::Owners).
30/// The `#[account]` attribute implements the Owners trait for
31/// a struct using multiple `crate::ID`s declared by [`declareId`](crate::declare_id)
32/// in the same program. It follows that InterfaceAccount can also be used
33/// with a `T` that comes from a different program.
34///
35/// Checks:
36///
37/// - `T::owners().contains(InterfaceAccount.info.owner)`
38/// - `!(InterfaceAccount.info.owner == SystemProgram && InterfaceAccount.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: InterfaceAccount<'info, MyData> // checks that my_account.info.owner == Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS
68///     pub auth_account: InterfaceAccount<'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 InterfaceAccount with non-anchor programs
84///
85/// InterfaceAccount 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 InterfaceAccount
88/// - implement the functions required by InterfaceAccount 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/// ### SPL Types
140///
141/// Anchor provides wrapper types to access accounts owned by the token programs. Use
142/// ```ignore
143/// use anchor_spl::token_interface::TokenAccount;
144///
145/// #[derive(Accounts)]
146/// pub struct Example {
147///     pub my_acc: InterfaceAccount<'info, TokenAccount>
148/// }
149/// ```
150/// to access token accounts and
151/// ```ignore
152/// use anchor_spl::token_interface::Mint;
153///
154/// #[derive(Accounts)]
155/// pub struct Example {
156///     pub my_acc: InterfaceAccount<'info, Mint>
157/// }
158/// ```
159/// to access mint accounts.
160#[derive(Clone)]
161pub struct InterfaceAccount<'info, T: AccountSerialize + AccountDeserialize + Clone> {
162    account: Account<'info, T>,
163    // The owner here is used to make sure that changes aren't incorrectly propagated
164    // to an account with a modified owner
165    owner: Pubkey,
166}
167
168impl<T: AccountSerialize + AccountDeserialize + Clone + fmt::Debug> fmt::Debug
169    for InterfaceAccount<'_, T>
170{
171    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172        self.account.fmt_with_name("InterfaceAccount", f)
173    }
174}
175
176impl<'a, T: AccountSerialize + AccountDeserialize + Clone> InterfaceAccount<'a, T> {
177    fn new(info: &'a AccountInfo<'a>, account: T) -> Self {
178        let owner = *info.owner;
179        Self {
180            account: Account::new(info, account),
181            owner,
182        }
183    }
184
185    /// Reloads the account from storage. This is useful, for example, when
186    /// observing side effects after CPI.
187    pub fn reload(&mut self) -> Result<()> {
188        self.account.reload()
189    }
190
191    pub fn into_inner(self) -> T {
192        self.account.into_inner()
193    }
194
195    /// Sets the inner account.
196    ///
197    /// Instead of this:
198    /// ```ignore
199    /// pub fn new_user(ctx: Context<CreateUser>, new_user:User) -> Result<()> {
200    ///     (*ctx.accounts.user_to_create).name = new_user.name;
201    ///     (*ctx.accounts.user_to_create).age = new_user.age;
202    ///     (*ctx.accounts.user_to_create).address = new_user.address;
203    /// }
204    /// ```
205    /// You can do this:
206    /// ```ignore
207    /// pub fn new_user(ctx: Context<CreateUser>, new_user:User) -> Result<()> {
208    ///     ctx.accounts.user_to_create.set_inner(new_user);
209    /// }
210    /// ```
211    pub fn set_inner(&mut self, inner: T) {
212        self.account.set_inner(inner);
213    }
214}
215
216impl<'a, T: AccountSerialize + AccountDeserialize + CheckOwner + Clone> InterfaceAccount<'a, T> {
217    /// Deserializes the given `info` into a `InterfaceAccount`.
218    #[inline(never)]
219    pub fn try_from(info: &'a AccountInfo<'a>) -> Result<Self> {
220        if info.owner == &system_program::ID && info.lamports() == 0 {
221            return Err(ErrorCode::AccountNotInitialized.into());
222        }
223        T::check_owner(info.owner)?;
224        let mut data: &[u8] = &info.try_borrow_data()?;
225        Ok(Self::new(info, T::try_deserialize(&mut data)?))
226    }
227
228    /// Deserializes the given `info` into a `InterfaceAccount` without checking
229    /// the account discriminator. Be careful when using this and avoid it if
230    /// possible.
231    #[inline(never)]
232    pub fn try_from_unchecked(info: &'a AccountInfo<'a>) -> Result<Self> {
233        if info.owner == &system_program::ID && info.lamports() == 0 {
234            return Err(ErrorCode::AccountNotInitialized.into());
235        }
236        T::check_owner(info.owner)?;
237        let mut data: &[u8] = &info.try_borrow_data()?;
238        Ok(Self::new(info, T::try_deserialize_unchecked(&mut data)?))
239    }
240}
241
242impl<'info, B, T: AccountSerialize + AccountDeserialize + CheckOwner + Clone> Accounts<'info, B>
243    for InterfaceAccount<'info, T>
244{
245    #[inline(never)]
246    fn try_accounts(
247        _program_id: &Pubkey,
248        accounts: &mut &'info [AccountInfo<'info>],
249        _ix_data: &[u8],
250        _bumps: &mut B,
251        _reallocs: &mut BTreeSet<Pubkey>,
252    ) -> Result<Self> {
253        if accounts.is_empty() {
254            return Err(ErrorCode::AccountNotEnoughKeys.into());
255        }
256        let account = &accounts[0];
257        *accounts = &accounts[1..];
258        Self::try_from(account)
259    }
260}
261
262impl<'info, T: AccountSerialize + AccountDeserialize + Owners + Clone> AccountsExit<'info>
263    for InterfaceAccount<'info, T>
264{
265    fn exit(&self, program_id: &Pubkey) -> Result<()> {
266        self.account
267            .exit_with_expected_owner(&self.owner, program_id)
268    }
269}
270
271impl<'info, T: AccountSerialize + AccountDeserialize + Clone> AccountsClose<'info>
272    for InterfaceAccount<'info, T>
273{
274    fn close(&self, sol_destination: AccountInfo<'info>) -> Result<()> {
275        self.account.close(sol_destination)
276    }
277}
278
279impl<T: AccountSerialize + AccountDeserialize + Clone> ToAccountMetas for InterfaceAccount<'_, T> {
280    fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
281        self.account.to_account_metas(is_signer)
282    }
283}
284
285impl<'info, T: AccountSerialize + AccountDeserialize + Clone> ToAccountInfos<'info>
286    for InterfaceAccount<'info, T>
287{
288    fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
289        self.account.to_account_infos()
290    }
291}
292
293impl<'info, T: AccountSerialize + AccountDeserialize + Clone> AsRef<AccountInfo<'info>>
294    for InterfaceAccount<'info, T>
295{
296    fn as_ref(&self) -> &AccountInfo<'info> {
297        self.account.as_ref()
298    }
299}
300
301impl<T: AccountSerialize + AccountDeserialize + Clone> AsRef<T> for InterfaceAccount<'_, T> {
302    fn as_ref(&self) -> &T {
303        self.account.as_ref()
304    }
305}
306
307impl<T: AccountSerialize + AccountDeserialize + Clone> Deref for InterfaceAccount<'_, T> {
308    type Target = T;
309
310    fn deref(&self) -> &Self::Target {
311        self.account.deref()
312    }
313}
314
315impl<T: AccountSerialize + AccountDeserialize + Clone> DerefMut for InterfaceAccount<'_, T> {
316    fn deref_mut(&mut self) -> &mut Self::Target {
317        self.account.deref_mut()
318    }
319}
320
321impl<T: AccountSerialize + AccountDeserialize + Clone> Key for InterfaceAccount<'_, T> {
322    fn key(&self) -> Pubkey {
323        self.account.key()
324    }
325}