1use arrayref::{array_ref, array_refs};
2use solana_program::program_pack::Pack;
3use solana_program::{
4 account_info::AccountInfo, program_error::ProgramError, program_option::COption, pubkey::Pubkey,
5};
6use spl_token_2022::extension::{BaseState, StateWithExtensions};
7
8pub fn unpack<S: BaseState + Pack>(
9 account_data: &[u8],
10) -> Result<StateWithExtensions<'_, S>, ProgramError> {
11 StateWithExtensions::<S>::unpack(account_data)
12}
13
14pub fn unpack_initialized<S: BaseState + Pack>(
15 account_data: &[u8],
16 error: impl Into<ProgramError>,
17) -> Result<StateWithExtensions<'_, S>, ProgramError> {
18 let unpacked = unpack::<S>(account_data)?;
19
20 if unpacked.base.is_initialized() {
21 Ok(unpacked)
22 } else {
23 Err(error.into())
24 }
25}
26
27fn unpack_coption_key(src: &[u8; 36]) -> Result<COption<Pubkey>, ProgramError> {
29 let (tag, body) = array_refs![src, 4, 32];
30 match *tag {
31 [0, 0, 0, 0] => Ok(COption::None),
32 [1, 0, 0, 0] => Ok(COption::Some(Pubkey::new_from_array(*body))),
33 _ => Err(ProgramError::InvalidAccountData),
34 }
35}
36
37pub fn get_owner_from_token_account(
39 token_account_info: &AccountInfo,
40) -> Result<Pubkey, ProgramError> {
41 let data = token_account_info.try_borrow_data()?;
43 let owner_data = array_ref![data, 32, 32];
44 Ok(Pubkey::new_from_array(*owner_data))
45}
46
47pub fn get_mint_authority(account_info: &AccountInfo) -> Result<COption<Pubkey>, ProgramError> {
48 let data = account_info.try_borrow_data().unwrap();
51 let authority_bytes = array_ref![data, 0, 36];
52
53 unpack_coption_key(authority_bytes)
54}
55
56pub fn get_mint_freeze_authority(
57 account_info: &AccountInfo,
58) -> Result<COption<Pubkey>, ProgramError> {
59 let data = account_info.try_borrow_data().unwrap();
60 let authority_bytes = array_ref![data, 36 + 8 + 1 + 1, 36];
61
62 unpack_coption_key(authority_bytes)
63}
64
65pub fn get_mint_supply(account_info: &AccountInfo) -> Result<u64, ProgramError> {
67 let data = account_info.try_borrow_data()?;
70
71 if data.is_empty() {
74 return Err(ProgramError::InvalidAccountData);
75 }
76
77 let bytes = array_ref![data, 36, 8];
78
79 Ok(u64::from_le_bytes(*bytes))
80}
81
82pub fn get_mint_decimals(account_info: &AccountInfo) -> Result<u8, ProgramError> {
84 let data = account_info.try_borrow_data()?;
87
88 if data.is_empty() {
91 return Err(ProgramError::InvalidAccountData);
92 }
93
94 Ok(data[44])
95}