interface_account.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. //! Account container that checks ownership on deserialization.
  2. use crate::accounts::account::Account;
  3. use crate::error::ErrorCode;
  4. use crate::solana_program::account_info::AccountInfo;
  5. use crate::solana_program::instruction::AccountMeta;
  6. use crate::solana_program::pubkey::Pubkey;
  7. use crate::solana_program::system_program;
  8. use crate::{
  9. AccountDeserialize, AccountSerialize, Accounts, AccountsClose, AccountsExit, CheckOwner, Key,
  10. Owners, Result, ToAccountInfos, ToAccountMetas,
  11. };
  12. use std::collections::BTreeSet;
  13. use std::fmt;
  14. use std::ops::{Deref, DerefMut};
  15. /// Wrapper around [`AccountInfo`](crate::solana_program::account_info::AccountInfo)
  16. /// that verifies program ownership and deserializes underlying data into a Rust type.
  17. ///
  18. /// # Table of Contents
  19. /// - [Basic Functionality](#basic-functionality)
  20. /// - [Using InterfaceAccount with non-anchor types](#using-interface-account-with-non-anchor-types)
  21. /// - [Out of the box wrapper types](#out-of-the-box-wrapper-types)
  22. ///
  23. /// # Basic Functionality
  24. ///
  25. /// InterfaceAccount checks that `T::owners().contains(Account.info.owner)`.
  26. /// This means that the data type that Accounts wraps around (`=T`) needs to
  27. /// implement the [Owners trait](crate::Owners).
  28. /// The `#[account]` attribute implements the Owners trait for
  29. /// a struct using multiple `crate::ID`s declared by [`declareId`](crate::declare_id)
  30. /// in the same program. It follows that InterfaceAccount can also be used
  31. /// with a `T` that comes from a different program.
  32. ///
  33. /// Checks:
  34. ///
  35. /// - `T::owners().contains(InterfaceAccount.info.owner)`
  36. /// - `!(InterfaceAccount.info.owner == SystemProgram && InterfaceAccount.info.lamports() == 0)`
  37. ///
  38. /// # Example
  39. /// ```ignore
  40. /// use anchor_lang::prelude::*;
  41. /// use other_program::Auth;
  42. ///
  43. /// declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
  44. ///
  45. /// #[program]
  46. /// mod hello_anchor {
  47. /// use super::*;
  48. /// pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
  49. /// if (*ctx.accounts.auth_account).authorized {
  50. /// (*ctx.accounts.my_account).data = data;
  51. /// }
  52. /// Ok(())
  53. /// }
  54. /// }
  55. ///
  56. /// #[account]
  57. /// #[derive(Default)]
  58. /// pub struct MyData {
  59. /// pub data: u64
  60. /// }
  61. ///
  62. /// #[derive(Accounts)]
  63. /// pub struct SetData<'info> {
  64. /// #[account(mut)]
  65. /// pub my_account: InterfaceAccount<'info, MyData> // checks that my_account.info.owner == Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS
  66. /// pub auth_account: InterfaceAccount<'info, Auth> // checks that auth_account.info.owner == FEZGUxNhZWpYPj9MJCrZJvUo1iF9ys34UHx52y4SzVW9
  67. /// }
  68. ///
  69. /// // In a different program
  70. ///
  71. /// ...
  72. /// declare_id!("FEZGUxNhZWpYPj9MJCrZJvUo1iF9ys34UHx52y4SzVW9");
  73. /// #[account]
  74. /// #[derive(Default)]
  75. /// pub struct Auth {
  76. /// pub authorized: bool
  77. /// }
  78. /// ...
  79. /// ```
  80. ///
  81. /// # Using InterfaceAccount with non-anchor programs
  82. ///
  83. /// InterfaceAccount can also be used with non-anchor programs. The data types from
  84. /// those programs are not annotated with `#[account]` so you have to
  85. /// - create a wrapper type around the structs you want to wrap with InterfaceAccount
  86. /// - implement the functions required by InterfaceAccount yourself
  87. ///
  88. /// instead of using `#[account]`. You only have to implement a fraction of the
  89. /// functions `#[account]` generates. See the example below for the code you have
  90. /// to write.
  91. ///
  92. /// 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))
  93. /// ```ignore
  94. /// #[derive(Clone)]
  95. /// pub struct Mint(spl_token::state::Mint);
  96. ///
  97. /// // This is necessary so we can use "anchor_spl::token::Mint::LEN"
  98. /// // because rust does not resolve "anchor_spl::token::Mint::LEN" to
  99. /// // "spl_token::state::Mint::LEN" automatically
  100. /// impl Mint {
  101. /// pub const LEN: usize = spl_token::state::Mint::LEN;
  102. /// }
  103. ///
  104. /// // You don't have to implement the "try_deserialize" function
  105. /// // from this trait. It delegates to
  106. /// // "try_deserialize_unchecked" by default which is what we want here
  107. /// // because non-anchor accounts don't have a discriminator to check
  108. /// impl anchor_lang::AccountDeserialize for Mint {
  109. /// fn try_deserialize_unchecked(buf: &mut &[u8]) -> Result<Self> {
  110. /// spl_token::state::Mint::unpack(buf).map(Mint)
  111. /// }
  112. /// }
  113. /// // AccountSerialize defaults to a no-op which is what we want here
  114. /// // because it's a foreign program, so our program does not
  115. /// // have permission to write to the foreign program's accounts anyway
  116. /// impl anchor_lang::AccountSerialize for Mint {}
  117. ///
  118. /// impl anchor_lang::Owner for Mint {
  119. /// fn owner() -> Pubkey {
  120. /// // pub use spl_token::ID is used at the top of the file
  121. /// ID
  122. /// }
  123. /// }
  124. ///
  125. /// // Implement the "std::ops::Deref" trait for better user experience
  126. /// impl Deref for Mint {
  127. /// type Target = spl_token::state::Mint;
  128. ///
  129. /// fn deref(&self) -> &Self::Target {
  130. /// &self.0
  131. /// }
  132. /// }
  133. /// ```
  134. ///
  135. /// ## Out of the box wrapper types
  136. ///
  137. /// ### SPL Types
  138. ///
  139. /// Anchor provides wrapper types to access accounts owned by the token programs. Use
  140. /// ```ignore
  141. /// use anchor_spl::token_interface::TokenAccount;
  142. ///
  143. /// #[derive(Accounts)]
  144. /// pub struct Example {
  145. /// pub my_acc: InterfaceAccount<'info, TokenAccount>
  146. /// }
  147. /// ```
  148. /// to access token accounts and
  149. /// ```ignore
  150. /// use anchor_spl::token_interface::Mint;
  151. ///
  152. /// #[derive(Accounts)]
  153. /// pub struct Example {
  154. /// pub my_acc: InterfaceAccount<'info, Mint>
  155. /// }
  156. /// ```
  157. /// to access mint accounts.
  158. #[derive(Clone)]
  159. pub struct InterfaceAccount<'info, T: AccountSerialize + AccountDeserialize + Clone> {
  160. account: Account<'info, T>,
  161. // The owner here is used to make sure that changes aren't incorrectly propagated
  162. // to an account with a modified owner
  163. owner: Pubkey,
  164. }
  165. impl<T: AccountSerialize + AccountDeserialize + Clone + fmt::Debug> fmt::Debug
  166. for InterfaceAccount<'_, T>
  167. {
  168. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  169. self.account.fmt_with_name("InterfaceAccount", f)
  170. }
  171. }
  172. impl<'a, T: AccountSerialize + AccountDeserialize + Clone> InterfaceAccount<'a, T> {
  173. fn new(info: &'a AccountInfo<'a>, account: T) -> Self {
  174. let owner = *info.owner;
  175. Self {
  176. account: Account::new(info, account),
  177. owner,
  178. }
  179. }
  180. /// Reloads the account from storage. This is useful, for example, when
  181. /// observing side effects after CPI.
  182. pub fn reload(&mut self) -> Result<()> {
  183. self.account.reload()
  184. }
  185. pub fn into_inner(self) -> T {
  186. self.account.into_inner()
  187. }
  188. /// Sets the inner account.
  189. ///
  190. /// Instead of this:
  191. /// ```ignore
  192. /// pub fn new_user(ctx: Context<CreateUser>, new_user:User) -> Result<()> {
  193. /// (*ctx.accounts.user_to_create).name = new_user.name;
  194. /// (*ctx.accounts.user_to_create).age = new_user.age;
  195. /// (*ctx.accounts.user_to_create).address = new_user.address;
  196. /// }
  197. /// ```
  198. /// You can do this:
  199. /// ```ignore
  200. /// pub fn new_user(ctx: Context<CreateUser>, new_user:User) -> Result<()> {
  201. /// ctx.accounts.user_to_create.set_inner(new_user);
  202. /// }
  203. /// ```
  204. pub fn set_inner(&mut self, inner: T) {
  205. self.account.set_inner(inner);
  206. }
  207. }
  208. impl<'a, T: AccountSerialize + AccountDeserialize + CheckOwner + Clone> InterfaceAccount<'a, T> {
  209. /// Deserializes the given `info` into a `InterfaceAccount`.
  210. #[inline(never)]
  211. pub fn try_from(info: &'a AccountInfo<'a>) -> Result<Self> {
  212. if info.owner == &system_program::ID && info.lamports() == 0 {
  213. return Err(ErrorCode::AccountNotInitialized.into());
  214. }
  215. T::check_owner(info.owner)?;
  216. let mut data: &[u8] = &info.try_borrow_data()?;
  217. Ok(Self::new(info, T::try_deserialize(&mut data)?))
  218. }
  219. /// Deserializes the given `info` into a `InterfaceAccount` without checking
  220. /// the account discriminator. Be careful when using this and avoid it if
  221. /// possible.
  222. #[inline(never)]
  223. pub fn try_from_unchecked(info: &'a AccountInfo<'a>) -> Result<Self> {
  224. if info.owner == &system_program::ID && info.lamports() == 0 {
  225. return Err(ErrorCode::AccountNotInitialized.into());
  226. }
  227. T::check_owner(info.owner)?;
  228. let mut data: &[u8] = &info.try_borrow_data()?;
  229. Ok(Self::new(info, T::try_deserialize_unchecked(&mut data)?))
  230. }
  231. }
  232. impl<'info, B, T: AccountSerialize + AccountDeserialize + CheckOwner + Clone> Accounts<'info, B>
  233. for InterfaceAccount<'info, T>
  234. {
  235. #[inline(never)]
  236. fn try_accounts(
  237. _program_id: &Pubkey,
  238. accounts: &mut &'info [AccountInfo<'info>],
  239. _ix_data: &[u8],
  240. _bumps: &mut B,
  241. _reallocs: &mut BTreeSet<Pubkey>,
  242. ) -> Result<Self> {
  243. if accounts.is_empty() {
  244. return Err(ErrorCode::AccountNotEnoughKeys.into());
  245. }
  246. let account = &accounts[0];
  247. *accounts = &accounts[1..];
  248. Self::try_from(account)
  249. }
  250. }
  251. impl<'info, T: AccountSerialize + AccountDeserialize + Owners + Clone> AccountsExit<'info>
  252. for InterfaceAccount<'info, T>
  253. {
  254. fn exit(&self, program_id: &Pubkey) -> Result<()> {
  255. self.account
  256. .exit_with_expected_owner(&self.owner, program_id)
  257. }
  258. }
  259. impl<'info, T: AccountSerialize + AccountDeserialize + Clone> AccountsClose<'info>
  260. for InterfaceAccount<'info, T>
  261. {
  262. fn close(&self, sol_destination: AccountInfo<'info>) -> Result<()> {
  263. self.account.close(sol_destination)
  264. }
  265. }
  266. impl<T: AccountSerialize + AccountDeserialize + Clone> ToAccountMetas for InterfaceAccount<'_, T> {
  267. fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
  268. self.account.to_account_metas(is_signer)
  269. }
  270. }
  271. impl<'info, T: AccountSerialize + AccountDeserialize + Clone> ToAccountInfos<'info>
  272. for InterfaceAccount<'info, T>
  273. {
  274. fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
  275. self.account.to_account_infos()
  276. }
  277. }
  278. impl<'info, T: AccountSerialize + AccountDeserialize + Clone> AsRef<AccountInfo<'info>>
  279. for InterfaceAccount<'info, T>
  280. {
  281. fn as_ref(&self) -> &AccountInfo<'info> {
  282. self.account.as_ref()
  283. }
  284. }
  285. impl<T: AccountSerialize + AccountDeserialize + Clone> AsRef<T> for InterfaceAccount<'_, T> {
  286. fn as_ref(&self) -> &T {
  287. self.account.as_ref()
  288. }
  289. }
  290. impl<T: AccountSerialize + AccountDeserialize + Clone> Deref for InterfaceAccount<'_, T> {
  291. type Target = T;
  292. fn deref(&self) -> &Self::Target {
  293. self.account.deref()
  294. }
  295. }
  296. impl<T: AccountSerialize + AccountDeserialize + Clone> DerefMut for InterfaceAccount<'_, T> {
  297. fn deref_mut(&mut self) -> &mut Self::Target {
  298. self.account.deref_mut()
  299. }
  300. }
  301. impl<T: AccountSerialize + AccountDeserialize + Clone> Key for InterfaceAccount<'_, T> {
  302. fn key(&self) -> Pubkey {
  303. self.account.key()
  304. }
  305. }