karima_anchor_lang/
state.rs1use crate::error::ErrorCode;
2#[allow(deprecated)]
3use crate::CpiAccount;
4use crate::{
5 AccountDeserialize, AccountSerialize, Accounts, AccountsExit, Key, ToAccountInfo,
6 ToAccountInfos, ToAccountMetas,
7};
8use solana_program::account_info::AccountInfo;
9use solana_program::entrypoint::ProgramResult;
10use solana_program::instruction::AccountMeta;
11use solana_program::program_error::ProgramError;
12use solana_program::pubkey::Pubkey;
13use std::ops::{Deref, DerefMut};
14
15pub const PROGRAM_STATE_SEED: &str = "unversioned";
16
17#[derive(Clone)]
19#[deprecated]
20pub struct ProgramState<'info, T: AccountSerialize + AccountDeserialize + Clone> {
21 inner: Box<Inner<'info, T>>,
22}
23
24#[derive(Clone)]
25struct Inner<'info, T: AccountSerialize + AccountDeserialize + Clone> {
26 info: AccountInfo<'info>,
27 account: T,
28}
29
30#[allow(deprecated)]
31
32impl<'a, T: AccountSerialize + AccountDeserialize + Clone> ProgramState<'a, T> {
33 fn new(info: AccountInfo<'a>, account: T) -> ProgramState<'a, T> {
34 Self {
35 inner: Box::new(Inner { info, account }),
36 }
37 }
38
39 #[inline(never)]
41 pub fn try_from(
42 program_id: &Pubkey,
43 info: &AccountInfo<'a>,
44 ) -> Result<ProgramState<'a, T>, ProgramError> {
45 if info.owner != program_id {
46 return Err(ErrorCode::AccountNotProgramOwned.into());
47 }
48 if info.key != &Self::address(program_id) {
49 solana_program::msg!("Invalid state address");
50 return Err(ErrorCode::StateInvalidAddress.into());
51 }
52 let mut data: &[u8] = &info.try_borrow_data()?;
53 Ok(ProgramState::new(
54 info.clone(),
55 T::try_deserialize(&mut data)?,
56 ))
57 }
58
59 pub fn seed() -> &'static str {
60 PROGRAM_STATE_SEED
61 }
62
63 pub fn address(program_id: &Pubkey) -> Pubkey {
64 address(program_id)
65 }
66}
67
68#[allow(deprecated)]
69impl<'info, T> Accounts<'info> for ProgramState<'info, T>
70where
71 T: AccountSerialize + AccountDeserialize + Clone,
72{
73 #[inline(never)]
74 fn try_accounts(
75 program_id: &Pubkey,
76 accounts: &mut &[AccountInfo<'info>],
77 _ix_data: &[u8],
78 ) -> Result<Self, ProgramError> {
79 if accounts.is_empty() {
80 return Err(ErrorCode::AccountNotEnoughKeys.into());
81 }
82 let account = &accounts[0];
83 *accounts = &accounts[1..];
84 ProgramState::try_from(program_id, account)
85 }
86}
87
88#[allow(deprecated)]
89impl<'info, T: AccountSerialize + AccountDeserialize + Clone> ToAccountMetas
90 for ProgramState<'info, T>
91{
92 fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
93 let is_signer = is_signer.unwrap_or(self.inner.info.is_signer);
94 let meta = match self.inner.info.is_writable {
95 false => AccountMeta::new_readonly(*self.inner.info.key, is_signer),
96 true => AccountMeta::new(*self.inner.info.key, is_signer),
97 };
98 vec![meta]
99 }
100}
101
102#[allow(deprecated)]
103impl<'info, T: AccountSerialize + AccountDeserialize + Clone> ToAccountInfos<'info>
104 for ProgramState<'info, T>
105{
106 fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
107 vec![self.inner.info.clone()]
108 }
109}
110
111#[allow(deprecated)]
112impl<'info, T: AccountSerialize + AccountDeserialize + Clone> ToAccountInfo<'info>
113 for ProgramState<'info, T>
114{
115 fn to_account_info(&self) -> AccountInfo<'info> {
116 self.inner.info.clone()
117 }
118}
119
120#[allow(deprecated)]
121impl<'info, T: AccountSerialize + AccountDeserialize + Clone> AsRef<AccountInfo<'info>>
122 for ProgramState<'info, T>
123{
124 fn as_ref(&self) -> &AccountInfo<'info> {
125 &self.inner.info
126 }
127}
128
129#[allow(deprecated)]
130impl<'a, T: AccountSerialize + AccountDeserialize + Clone> Deref for ProgramState<'a, T> {
131 type Target = T;
132
133 fn deref(&self) -> &Self::Target {
134 &(*self.inner).account
135 }
136}
137
138#[allow(deprecated)]
139impl<'a, T: AccountSerialize + AccountDeserialize + Clone> DerefMut for ProgramState<'a, T> {
140 fn deref_mut(&mut self) -> &mut Self::Target {
141 &mut DerefMut::deref_mut(&mut self.inner).account
142 }
143}
144
145#[allow(deprecated)]
146impl<'info, T> From<CpiAccount<'info, T>> for ProgramState<'info, T>
147where
148 T: AccountSerialize + AccountDeserialize + Clone,
149{
150 fn from(a: CpiAccount<'info, T>) -> Self {
151 Self::new(a.to_account_info(), Deref::deref(&a).clone())
152 }
153}
154
155#[allow(deprecated)]
156impl<'info, T: AccountSerialize + AccountDeserialize + Clone> AccountsExit<'info>
157 for ProgramState<'info, T>
158{
159 fn exit(&self, _program_id: &Pubkey) -> ProgramResult {
160 let info = self.to_account_info();
161 let mut data = info.try_borrow_mut_data()?;
162 let dst: &mut [u8] = &mut data;
163 let mut cursor = std::io::Cursor::new(dst);
164 self.inner.account.try_serialize(&mut cursor)?;
165 Ok(())
166 }
167}
168
169pub fn address(program_id: &Pubkey) -> Pubkey {
170 let (base, _nonce) = Pubkey::find_program_address(&[], program_id);
171 let seed = PROGRAM_STATE_SEED;
172 let owner = program_id;
173 Pubkey::create_with_seed(&base, seed, owner).unwrap()
174}
175
176#[allow(deprecated)]
177impl<'info, T: AccountSerialize + AccountDeserialize + Clone> Key for ProgramState<'info, T> {
178 fn key(&self) -> Pubkey {
179 *self.inner.info.key
180 }
181}