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
62#[cfg(feature = "idl-build")]
64impl anchor_lang::IdlBuild for Token {}
65
66#[cfg(feature = "idl-build")]
71impl Token {
72 #[doc(hidden)]
73 pub fn get_full_path() -> String {
74 std::any::type_name::<Self>().into()
75 }
76
77 #[doc(hidden)]
78 pub fn create_type() -> Option<anchor_lang::idl::types::IdlTypeDef> {
79 None
80 }
81
82 #[doc(hidden)]
83 pub fn insert_types(
84 _types: &mut std::collections::BTreeMap<String, anchor_lang::idl::types::IdlTypeDef>,
85 ) {
86 }
87}
88
89impl Token {
90 pub fn amount_from_slice(data: &[u8]) -> Result<u64, ZeroCopyError> {
93 const AMOUNT_OFFSET: usize = 64; check_token_account(data)?;
96
97 #[inline(always)]
98 fn check_token_account(bytes: &[u8]) -> Result<(), ZeroCopyError> {
99 if bytes.len() == 165 || (bytes.len() > 165 && bytes[165] == ACCOUNT_TYPE_TOKEN_ACCOUNT)
100 {
101 Ok(())
102 } else {
103 Err(ZeroCopyError::InvalidConversion)
104 }
105 }
106
107 let amount_bytes = &data[AMOUNT_OFFSET..AMOUNT_OFFSET + 8];
108 let amount = u64::from_le_bytes(amount_bytes.try_into().map_err(|_| ZeroCopyError::Size)?);
109
110 Ok(amount)
111 }
112
113 #[cfg(feature = "solana")]
115 pub fn amount_from_account_info(
116 account_info: &solana_account_info::AccountInfo,
117 ) -> Result<u64, ZeroCopyError> {
118 let data = account_info
119 .try_borrow_data()
120 .map_err(|_| ZeroCopyError::Size)?;
121 Self::amount_from_slice(&data)
122 }
123
124 pub fn is_frozen(&self) -> bool {
126 self.state == AccountState::Frozen
127 }
128
129 pub fn is_native(&self) -> bool {
131 self.is_native.is_some()
132 }
133
134 pub fn is_initialized(&self) -> bool {
136 self.state == AccountState::Initialized
137 }
138
139 #[inline(always)]
141 pub fn account_type(&self) -> u8 {
142 self.account_type
143 }
144
145 #[inline(always)]
147 pub fn is_token_account(&self) -> bool {
148 self.account_type == ACCOUNT_TYPE_TOKEN_ACCOUNT
149 }
150}