use light_compressed_account::Pubkey;
use light_zero_copy::errors::ZeroCopyError;
use crate::{state::ExtensionStruct, AnchorDeserialize, AnchorSerialize, TokenError};
pub const ACCOUNT_TYPE_TOKEN_ACCOUNT: u8 = 2;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, AnchorSerialize, AnchorDeserialize)]
#[repr(u8)]
pub enum AccountState {
Uninitialized = 0,
Initialized = 1,
Frozen = 2,
}
impl TryFrom<u8> for AccountState {
type Error = TokenError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(AccountState::Uninitialized),
1 => Ok(AccountState::Initialized),
2 => Ok(AccountState::Frozen),
_ => Err(TokenError::InvalidAccountState),
}
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct Token {
pub mint: Pubkey,
pub owner: Pubkey,
pub amount: u64,
pub delegate: Option<Pubkey>,
pub state: AccountState,
pub is_native: Option<u64>,
pub delegated_amount: u64,
pub close_authority: Option<Pubkey>,
pub account_type: u8,
pub extensions: Option<Vec<ExtensionStruct>>,
}
#[cfg(feature = "idl-build")]
impl anchor_lang::IdlBuild for Token {}
#[cfg(feature = "idl-build")]
impl Token {
#[doc(hidden)]
pub fn get_full_path() -> String {
std::any::type_name::<Self>().into()
}
#[doc(hidden)]
pub fn create_type() -> Option<anchor_lang::idl::types::IdlTypeDef> {
None
}
#[doc(hidden)]
pub fn insert_types(
_types: &mut std::collections::BTreeMap<String, anchor_lang::idl::types::IdlTypeDef>,
) {
}
}
impl Token {
pub fn amount_from_slice(data: &[u8]) -> Result<u64, ZeroCopyError> {
const AMOUNT_OFFSET: usize = 64;
check_token_account(data)?;
#[inline(always)]
fn check_token_account(bytes: &[u8]) -> Result<(), ZeroCopyError> {
if bytes.len() == 165 || (bytes.len() > 165 && bytes[165] == ACCOUNT_TYPE_TOKEN_ACCOUNT)
{
Ok(())
} else {
Err(ZeroCopyError::InvalidConversion)
}
}
let amount_bytes = &data[AMOUNT_OFFSET..AMOUNT_OFFSET + 8];
let amount = u64::from_le_bytes(amount_bytes.try_into().map_err(|_| ZeroCopyError::Size)?);
Ok(amount)
}
#[cfg(feature = "solana")]
pub fn amount_from_account_info(
account_info: &solana_account_info::AccountInfo,
) -> Result<u64, ZeroCopyError> {
let data = account_info
.try_borrow_data()
.map_err(|_| ZeroCopyError::Size)?;
Self::amount_from_slice(&data)
}
pub fn is_frozen(&self) -> bool {
self.state == AccountState::Frozen
}
pub fn is_native(&self) -> bool {
self.is_native.is_some()
}
pub fn is_initialized(&self) -> bool {
self.state == AccountState::Initialized
}
#[inline(always)]
pub fn account_type(&self) -> u8 {
self.account_type
}
#[inline(always)]
pub fn is_token_account(&self) -> bool {
self.account_type == ACCOUNT_TYPE_TOKEN_ACCOUNT
}
}