use arrayref::{array_ref, array_refs};
use solana_program::{
account_info::AccountInfo, program_error::ProgramError, program_option::COption, pubkey::Pubkey,
};
use spl_token_2022::extension::{BaseState, StateWithExtensions};
pub fn unpack<S: BaseState>(
account_data: &[u8],
) -> Result<StateWithExtensions<'_, S>, ProgramError> {
StateWithExtensions::<S>::unpack(account_data)
}
pub fn unpack_initialized<S: BaseState>(
account_data: &[u8],
error: impl Into<ProgramError>,
) -> Result<StateWithExtensions<'_, S>, ProgramError> {
let unpacked = unpack::<S>(account_data)?;
if unpacked.base.is_initialized() {
Ok(unpacked)
} else {
Err(error.into())
}
}
fn unpack_coption_key(src: &[u8; 36]) -> Result<COption<Pubkey>, ProgramError> {
let (tag, body) = array_refs![src, 4, 32];
match *tag {
[0, 0, 0, 0] => Ok(COption::None),
[1, 0, 0, 0] => Ok(COption::Some(Pubkey::new_from_array(*body))),
_ => Err(ProgramError::InvalidAccountData),
}
}
pub fn get_owner_from_token_account(
token_account_info: &AccountInfo,
) -> Result<Pubkey, ProgramError> {
let data = token_account_info.try_borrow_data()?;
let owner_data = array_ref![data, 32, 32];
Ok(Pubkey::new_from_array(*owner_data))
}
pub fn get_mint_authority(account_info: &AccountInfo) -> Result<COption<Pubkey>, ProgramError> {
let data = account_info.try_borrow_data().unwrap();
let authority_bytes = array_ref![data, 0, 36];
unpack_coption_key(authority_bytes)
}
pub fn get_mint_freeze_authority(
account_info: &AccountInfo,
) -> Result<COption<Pubkey>, ProgramError> {
let data = account_info.try_borrow_data().unwrap();
let authority_bytes = array_ref![data, 36 + 8 + 1 + 1, 36];
unpack_coption_key(authority_bytes)
}
pub fn get_mint_supply(account_info: &AccountInfo) -> Result<u64, ProgramError> {
let data = account_info.try_borrow_data()?;
if data.is_empty() {
return Err(ProgramError::InvalidAccountData);
}
let bytes = array_ref![data, 36, 8];
Ok(u64::from_le_bytes(*bytes))
}
pub fn get_mint_decimals(account_info: &AccountInfo) -> Result<u8, ProgramError> {
let data = account_info.try_borrow_data()?;
if data.is_empty() {
return Err(ProgramError::InvalidAccountData);
}
Ok(data[44])
}