light_token_interface/state/token/
token_struct.rs1use light_compressed_account::Pubkey;
2use light_zero_copy::errors::ZeroCopyError;
3
4use crate::{state::ExtensionStruct, AnchorDeserialize, AnchorSerialize, TokenError};
5
6pub const ACCOUNT_TYPE_TOKEN_ACCOUNT: u8 = 2;
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, AnchorSerialize, AnchorDeserialize)]
10#[repr(u8)]
11pub enum AccountState {
12 Uninitialized = 0,
13 Initialized = 1,
14 Frozen = 2,
15}
16
17impl TryFrom<u8> for AccountState {
18 type Error = TokenError;
19
20 fn try_from(value: u8) -> Result<Self, Self::Error> {
21 match value {
22 0 => Ok(AccountState::Uninitialized),
23 1 => Ok(AccountState::Initialized),
24 2 => Ok(AccountState::Frozen),
25 _ => Err(TokenError::InvalidAccountState),
26 }
27 }
28}
29
30#[derive(Debug, PartialEq, Eq, Hash, Clone)]
34pub struct Token {
35 pub mint: Pubkey,
37 pub owner: Pubkey,
39 pub amount: u64,
41 pub delegate: Option<Pubkey>,
44 pub state: AccountState,
46 pub is_native: Option<u64>,
51 pub delegated_amount: u64,
53 pub close_authority: Option<Pubkey>,
55 pub account_type: u8,
58 pub extensions: Option<Vec<ExtensionStruct>>,
60}
61
62impl Token {
63 pub fn amount_from_slice(data: &[u8]) -> Result<u64, ZeroCopyError> {
66 const AMOUNT_OFFSET: usize = 64; check_token_account(data)?;
69
70 #[inline(always)]
71 fn check_token_account(bytes: &[u8]) -> Result<(), ZeroCopyError> {
72 if bytes.len() == 165 || (bytes.len() > 165 && bytes[165] == ACCOUNT_TYPE_TOKEN_ACCOUNT)
73 {
74 Ok(())
75 } else {
76 Err(ZeroCopyError::InvalidConversion)
77 }
78 }
79
80 let amount_bytes = &data[AMOUNT_OFFSET..AMOUNT_OFFSET + 8];
81 let amount = u64::from_le_bytes(amount_bytes.try_into().map_err(|_| ZeroCopyError::Size)?);
82
83 Ok(amount)
84 }
85
86 #[cfg(feature = "solana")]
88 pub fn amount_from_account_info(
89 account_info: &solana_account_info::AccountInfo,
90 ) -> Result<u64, ZeroCopyError> {
91 let data = account_info
92 .try_borrow_data()
93 .map_err(|_| ZeroCopyError::Size)?;
94 Self::amount_from_slice(&data)
95 }
96
97 pub fn is_frozen(&self) -> bool {
99 self.state == AccountState::Frozen
100 }
101
102 pub fn is_native(&self) -> bool {
104 self.is_native.is_some()
105 }
106
107 pub fn is_initialized(&self) -> bool {
109 self.state == AccountState::Initialized
110 }
111
112 #[inline(always)]
114 pub fn account_type(&self) -> u8 {
115 self.account_type
116 }
117
118 #[inline(always)]
120 pub fn is_token_account(&self) -> bool {
121 self.account_type == ACCOUNT_TYPE_TOKEN_ACCOUNT
122 }
123}