pinocchio_token/state/
token.rs1use super::AccountState;
2use pinocchio::{
3 account_info::{AccountInfo, Ref},
4 program_error::ProgramError,
5 pubkey::Pubkey,
6};
7
8use crate::ID;
9
10#[repr(C)]
12pub struct TokenAccount {
13 mint: Pubkey,
15
16 owner: Pubkey,
18
19 amount: [u8; 8],
21
22 delegate_flag: [u8; 4],
24
25 delegate: Pubkey,
28
29 state: u8,
31
32 is_native: [u8; 4],
34
35 native_amount: [u8; 8],
40
41 delegated_amount: [u8; 8],
43
44 close_authority_flag: [u8; 4],
46
47 close_authority: Pubkey,
49}
50
51impl TokenAccount {
52 pub const LEN: usize = core::mem::size_of::<TokenAccount>();
53
54 #[inline]
59 pub fn from_account_info(
60 account_info: &AccountInfo,
61 ) -> Result<Ref<TokenAccount>, ProgramError> {
62 if account_info.data_len() != Self::LEN {
63 return Err(ProgramError::InvalidAccountData);
64 }
65 if !account_info.is_owned_by(&ID) {
66 return Err(ProgramError::InvalidAccountData);
67 }
68 Ok(Ref::map(account_info.try_borrow_data()?, |data| unsafe {
69 Self::from_bytes_unchecked(data)
70 }))
71 }
72
73 #[inline]
83 pub unsafe fn from_account_info_unchecked(
84 account_info: &AccountInfo,
85 ) -> Result<&TokenAccount, ProgramError> {
86 if account_info.data_len() != Self::LEN {
87 return Err(ProgramError::InvalidAccountData);
88 }
89 if account_info.owner() != &ID {
90 return Err(ProgramError::InvalidAccountData);
91 }
92 Ok(Self::from_bytes_unchecked(
93 account_info.borrow_data_unchecked(),
94 ))
95 }
96
97 #[inline(always)]
106 pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
107 &*(bytes.as_ptr() as *const TokenAccount)
108 }
109
110 pub fn mint(&self) -> &Pubkey {
111 &self.mint
112 }
113
114 pub fn owner(&self) -> &Pubkey {
115 &self.owner
116 }
117
118 pub fn amount(&self) -> u64 {
119 u64::from_le_bytes(self.amount)
120 }
121
122 #[inline(always)]
123 pub fn has_delegate(&self) -> bool {
124 self.delegate_flag[0] == 1
125 }
126
127 pub fn delegate(&self) -> Option<&Pubkey> {
128 if self.has_delegate() {
129 Some(self.delegate_unchecked())
130 } else {
131 None
132 }
133 }
134
135 #[inline(always)]
137 pub fn delegate_unchecked(&self) -> &Pubkey {
138 &self.delegate
139 }
140
141 #[inline(always)]
142 pub fn state(&self) -> AccountState {
143 self.state.into()
144 }
145
146 #[inline(always)]
147 pub fn is_native(&self) -> bool {
148 self.is_native[0] == 1
149 }
150
151 pub fn native_amount(&self) -> Option<u64> {
152 if self.is_native() {
153 Some(self.native_amount_unchecked())
154 } else {
155 None
156 }
157 }
158
159 #[inline(always)]
164 pub fn native_amount_unchecked(&self) -> u64 {
165 u64::from_le_bytes(self.native_amount)
166 }
167
168 pub fn delegated_amount(&self) -> u64 {
169 u64::from_le_bytes(self.delegated_amount)
170 }
171
172 #[inline(always)]
173 pub fn has_close_authority(&self) -> bool {
174 self.close_authority_flag[0] == 1
175 }
176
177 pub fn close_authority(&self) -> Option<&Pubkey> {
178 if self.has_close_authority() {
179 Some(self.close_authority_unchecked())
180 } else {
181 None
182 }
183 }
184
185 #[inline(always)]
190 pub fn close_authority_unchecked(&self) -> &Pubkey {
191 &self.close_authority
192 }
193
194 #[inline(always)]
195 pub fn is_initialized(&self) -> bool {
196 self.state != AccountState::Uninitialized as u8
197 }
198
199 #[inline(always)]
200 pub fn is_frozen(&self) -> bool {
201 self.state == AccountState::Frozen as u8
202 }
203}