pinocchio_token/state/
token.rs1use solana_account_view::{AccountView, Ref};
2use solana_address::Address;
3use solana_program_error::ProgramError;
4
5use crate::{state::AccountState, ID};
6
7#[repr(C)]
9pub struct TokenAccount {
10 mint: Address,
12
13 owner: Address,
15
16 amount: [u8; 8],
18
19 delegate_flag: [u8; 4],
21
22 delegate: Address,
25
26 state: u8,
28
29 is_native: [u8; 4],
31
32 native_amount: [u8; 8],
37
38 delegated_amount: [u8; 8],
40
41 close_authority_flag: [u8; 4],
43
44 close_authority: Address,
46}
47
48impl TokenAccount {
49 pub const LEN: usize = core::mem::size_of::<TokenAccount>();
50
51 #[inline]
56 pub fn from_account_view(
57 account_view: &AccountView,
58 ) -> Result<Ref<TokenAccount>, ProgramError> {
59 if account_view.data_len() != Self::LEN {
60 return Err(ProgramError::InvalidAccountData);
61 }
62 if !account_view.owned_by(&ID) {
63 return Err(ProgramError::InvalidAccountData);
64 }
65 Ok(Ref::map(account_view.try_borrow()?, |data| unsafe {
66 Self::from_bytes_unchecked(data)
67 }))
68 }
69
70 #[inline]
80 pub unsafe fn from_account_view_unchecked(
81 account_view: &AccountView,
82 ) -> Result<&TokenAccount, ProgramError> {
83 if account_view.data_len() != Self::LEN {
84 return Err(ProgramError::InvalidAccountData);
85 }
86 if account_view.owner() != &ID {
87 return Err(ProgramError::InvalidAccountData);
88 }
89 Ok(Self::from_bytes_unchecked(account_view.borrow_unchecked()))
90 }
91
92 #[inline(always)]
101 pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
102 &*(bytes.as_ptr() as *const TokenAccount)
103 }
104
105 pub fn mint(&self) -> &Address {
106 &self.mint
107 }
108
109 pub fn owner(&self) -> &Address {
110 &self.owner
111 }
112
113 pub fn amount(&self) -> u64 {
114 u64::from_le_bytes(self.amount)
115 }
116
117 #[inline(always)]
118 pub fn has_delegate(&self) -> bool {
119 self.delegate_flag[0] == 1
120 }
121
122 pub fn delegate(&self) -> Option<&Address> {
123 if self.has_delegate() {
124 Some(self.delegate_unchecked())
125 } else {
126 None
127 }
128 }
129
130 #[inline(always)]
132 pub fn delegate_unchecked(&self) -> &Address {
133 &self.delegate
134 }
135
136 #[inline(always)]
137 pub fn state(&self) -> AccountState {
138 self.state.into()
139 }
140
141 #[inline(always)]
142 pub fn is_native(&self) -> bool {
143 self.is_native[0] == 1
144 }
145
146 pub fn native_amount(&self) -> Option<u64> {
147 if self.is_native() {
148 Some(self.native_amount_unchecked())
149 } else {
150 None
151 }
152 }
153
154 #[inline(always)]
159 pub fn native_amount_unchecked(&self) -> u64 {
160 u64::from_le_bytes(self.native_amount)
161 }
162
163 pub fn delegated_amount(&self) -> u64 {
164 u64::from_le_bytes(self.delegated_amount)
165 }
166
167 #[inline(always)]
168 pub fn has_close_authority(&self) -> bool {
169 self.close_authority_flag[0] == 1
170 }
171
172 pub fn close_authority(&self) -> Option<&Address> {
173 if self.has_close_authority() {
174 Some(self.close_authority_unchecked())
175 } else {
176 None
177 }
178 }
179
180 #[inline(always)]
185 pub fn close_authority_unchecked(&self) -> &Address {
186 &self.close_authority
187 }
188
189 #[inline(always)]
190 pub fn is_initialized(&self) -> bool {
191 self.state != AccountState::Uninitialized as u8
192 }
193
194 #[inline(always)]
195 pub fn is_frozen(&self) -> bool {
196 self.state == AccountState::Frozen as u8
197 }
198}