Skip to main content

karima_anchor_lang/
state.rs

1use 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/// Boxed container for the program state singleton.
18#[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    /// Deserializes the given `info` into a `ProgramState`.
40    #[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}