smelter_utils/
loaders.rs

1#[cfg(feature = "spl")]
2use solana_program::program_pack::Pack;
3use solana_program::{
4    account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, system_program, sysvar,
5};
6#[cfg(feature = "spl")]
7use spl_token::state::Mint;
8
9/// Errors if:
10/// - Account is not a signer.
11pub fn load_signer<'a, 'info>(info: &'a AccountInfo<'info>) -> Result<(), ProgramError> {
12    if !info.is_signer {
13        return Err(ProgramError::MissingRequiredSignature);
14    }
15
16    Ok(())
17}
18
19/// Errors if:
20/// - Owner is not SPL token program.
21/// - Address does not match the expected mint address.
22/// - Data is empty.
23/// - Data cannot deserialize into a mint account.
24/// - Expected to be writable, but is not.
25#[cfg(feature = "spl")]
26pub fn load_mint<'a, 'info>(
27    info: &'a AccountInfo<'info>,
28    address: Pubkey,
29    is_writable: bool,
30) -> Result<(), ProgramError> {
31    if info.owner.ne(&spl_token::id()) {
32        return Err(ProgramError::InvalidAccountOwner);
33    }
34
35    if info.key.ne(&address) {
36        return Err(ProgramError::InvalidSeeds);
37    }
38
39    if info.data_is_empty() {
40        return Err(ProgramError::UninitializedAccount);
41    }
42
43    Mint::unpack(&info.data.borrow())?;
44
45    if is_writable && !info.is_writable {
46        return Err(ProgramError::InvalidAccountData);
47    }
48
49    Ok(())
50}
51
52/// Errors if:
53/// - Owner is not SPL token program.
54/// - Data is empty.
55/// - Data cannot deserialize into a token account.
56/// - Token account owner does not match the expected owner address.
57/// - Token account mint does not match the expected mint address.
58/// - Expected to be writable, but is not.
59#[cfg(feature = "spl")]
60pub fn load_token_account<'a, 'info>(
61    info: &'a AccountInfo<'info>,
62    owner: Option<&Pubkey>,
63    mint: &Pubkey,
64    is_writable: bool,
65) -> Result<(), ProgramError> {
66    if info.owner.ne(&spl_token::id()) {
67        return Err(ProgramError::InvalidAccountOwner);
68    }
69
70    if info.data_is_empty() {
71        return Err(ProgramError::UninitializedAccount);
72    }
73
74    let account_data = info.data.borrow();
75    let account = spl_token::state::Account::unpack(&account_data)?;
76
77    if account.mint.ne(&mint) {
78        return Err(ProgramError::InvalidAccountData);
79    }
80
81    if let Some(owner) = owner {
82        if account.owner.ne(owner) {
83            return Err(ProgramError::InvalidAccountData);
84        }
85    }
86
87    if is_writable && !info.is_writable {
88        return Err(ProgramError::InvalidAccountData);
89    }
90
91    Ok(())
92}
93
94/// Errors if:
95/// - Address does not match PDA derived from provided seeds.
96/// - Cannot load as an uninitialized account.
97pub fn load_uninitialized_pda<'a, 'info>(
98    info: &'a AccountInfo<'info>,
99    seeds: &[&[u8]],
100    bump: u8,
101    program_id: &Pubkey,
102) -> Result<(), ProgramError> {
103    let pda = Pubkey::find_program_address(seeds, program_id);
104
105    if info.key.ne(&pda.0) {
106        return Err(ProgramError::InvalidSeeds);
107    }
108
109    if bump.ne(&pda.1) {
110        return Err(ProgramError::InvalidSeeds);
111    }
112
113    load_system_account(info, true)
114}
115
116/// Errors if:
117/// - Owner is not the system program.
118/// - Data is not empty.
119/// - Account is not writable.
120pub fn load_system_account<'a, 'info>(
121    info: &'a AccountInfo<'info>,
122    is_writable: bool,
123) -> Result<(), ProgramError> {
124    if info.owner.ne(&system_program::id()) {
125        return Err(ProgramError::InvalidAccountOwner);
126    }
127
128    if !info.data_is_empty() {
129        return Err(ProgramError::AccountAlreadyInitialized);
130    }
131
132    if is_writable && !info.is_writable {
133        return Err(ProgramError::InvalidAccountData);
134    }
135
136    Ok(())
137}
138
139/// Errors if:
140/// - Owner is not the sysvar address.
141/// - Account cannot load with the expected address.
142pub fn load_sysvar<'a, 'info>(
143    info: &'a AccountInfo<'info>,
144    key: Pubkey,
145) -> Result<(), ProgramError> {
146    if info.owner.ne(&sysvar::id()) {
147        return Err(ProgramError::InvalidAccountOwner);
148    }
149
150    load_account(info, key, false)
151}
152
153/// Errors if:
154/// - Address does not match the expected value.
155/// - Expected to be writable, but is not.
156pub fn load_account<'a, 'info>(
157    info: &'a AccountInfo<'info>,
158    key: Pubkey,
159    is_writable: bool,
160) -> Result<(), ProgramError> {
161    if info.key.ne(&key) {
162        return Err(ProgramError::InvalidAccountData);
163    }
164
165    if is_writable && !info.is_writable {
166        return Err(ProgramError::InvalidAccountData);
167    }
168
169    Ok(())
170}
171
172/// Errors if:
173/// - Address does not match the expected value.
174/// - Account is not executable.
175pub fn load_program<'a, 'info>(
176    info: &'a AccountInfo<'info>,
177    key: Pubkey,
178) -> Result<(), ProgramError> {
179    if info.key.ne(&key) {
180        return Err(ProgramError::IncorrectProgramId);
181    }
182
183    if !info.executable {
184        return Err(ProgramError::InvalidAccountData);
185    }
186
187    Ok(())
188}
189
190/// Errors if:
191/// - Account is not writable.
192pub fn load_any<'a, 'info>(
193    info: &'a AccountInfo<'info>,
194    is_writable: bool,
195) -> Result<(), ProgramError> {
196    if is_writable && !info.is_writable {
197        return Err(ProgramError::InvalidAccountData);
198    }
199
200    Ok(())
201}