cpi_account.rs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. use crate::{
  2. AccountDeserialize, Accounts, AccountsExit, ToAccountInfo, ToAccountInfos, ToAccountMetas,
  3. };
  4. use solana_program::account_info::AccountInfo;
  5. use solana_program::entrypoint::ProgramResult;
  6. use solana_program::instruction::AccountMeta;
  7. use solana_program::program_error::ProgramError;
  8. use solana_program::pubkey::Pubkey;
  9. use std::ops::{Deref, DerefMut};
  10. /// Container for any account *not* owned by the current program.
  11. #[derive(Clone)]
  12. pub struct CpiAccount<'a, T: AccountDeserialize + Clone> {
  13. info: AccountInfo<'a>,
  14. account: Box<T>,
  15. }
  16. impl<'a, T: AccountDeserialize + Clone> CpiAccount<'a, T> {
  17. pub fn new(info: AccountInfo<'a>, account: Box<T>) -> CpiAccount<'a, T> {
  18. Self { info, account }
  19. }
  20. /// Deserializes the given `info` into a `CpiAccount`.
  21. pub fn try_from(info: &AccountInfo<'a>) -> Result<CpiAccount<'a, T>, ProgramError> {
  22. let mut data: &[u8] = &info.try_borrow_data()?;
  23. Ok(CpiAccount::new(
  24. info.clone(),
  25. Box::new(T::try_deserialize(&mut data)?),
  26. ))
  27. }
  28. /// Reloads the account from storage. This is useful, for example, when
  29. /// observing side effects after CPI.
  30. pub fn reload(&self) -> Result<CpiAccount<'a, T>, ProgramError> {
  31. let info = self.to_account_info();
  32. let mut data: &[u8] = &info.try_borrow_data()?;
  33. Ok(CpiAccount::new(
  34. info.clone(),
  35. Box::new(T::try_deserialize(&mut data)?),
  36. ))
  37. }
  38. }
  39. impl<'info, T> Accounts<'info> for CpiAccount<'info, T>
  40. where
  41. T: AccountDeserialize + Clone,
  42. {
  43. #[inline(never)]
  44. fn try_accounts(
  45. _program_id: &Pubkey,
  46. accounts: &mut &[AccountInfo<'info>],
  47. ) -> Result<Self, ProgramError> {
  48. if accounts.is_empty() {
  49. return Err(ProgramError::NotEnoughAccountKeys);
  50. }
  51. let account = &accounts[0];
  52. *accounts = &accounts[1..];
  53. let pa = CpiAccount::try_from(account)?;
  54. Ok(pa)
  55. }
  56. }
  57. impl<'info, T: AccountDeserialize + Clone> ToAccountMetas for CpiAccount<'info, T> {
  58. fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
  59. let is_signer = is_signer.unwrap_or(self.info.is_signer);
  60. let meta = match self.info.is_writable {
  61. false => AccountMeta::new_readonly(*self.info.key, is_signer),
  62. true => AccountMeta::new(*self.info.key, is_signer),
  63. };
  64. vec![meta]
  65. }
  66. }
  67. impl<'info, T: AccountDeserialize + Clone> ToAccountInfos<'info> for CpiAccount<'info, T> {
  68. fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
  69. vec![self.info.clone()]
  70. }
  71. }
  72. impl<'info, T: AccountDeserialize + Clone> ToAccountInfo<'info> for CpiAccount<'info, T> {
  73. fn to_account_info(&self) -> AccountInfo<'info> {
  74. self.info.clone()
  75. }
  76. }
  77. impl<'a, T: AccountDeserialize + Clone> Deref for CpiAccount<'a, T> {
  78. type Target = T;
  79. fn deref(&self) -> &Self::Target {
  80. &self.account
  81. }
  82. }
  83. impl<'a, T: AccountDeserialize + Clone> DerefMut for CpiAccount<'a, T> {
  84. fn deref_mut(&mut self) -> &mut Self::Target {
  85. &mut self.account
  86. }
  87. }
  88. impl<'info, T: AccountDeserialize + Clone> AccountsExit<'info> for CpiAccount<'info, T> {
  89. fn exit(&self, _program_id: &Pubkey) -> ProgramResult {
  90. // no-op
  91. Ok(())
  92. }
  93. }