pinocchio_token/state/
token.rs

1use super::AccountState;
2use pinocchio::{
3    account_info::{AccountInfo, Ref},
4    program_error::ProgramError,
5    pubkey::Pubkey,
6};
7
8use crate::ID;
9
10/// Token account data.
11#[repr(C)]
12pub struct TokenAccount {
13    /// The mint associated with this account
14    mint: Pubkey,
15
16    /// The owner of this account.
17    owner: Pubkey,
18
19    /// The amount of tokens this account holds.
20    amount: [u8; 8],
21
22    /// Indicates whether the delegate is present or not.
23    delegate_flag: [u8; 4],
24
25    /// If `delegate` is `Some` then `delegated_amount` represents
26    /// the amount authorized by the delegate.
27    delegate: Pubkey,
28
29    /// The account's state.
30    state: u8,
31
32    /// Indicates whether this account represents a native token or not.
33    is_native: [u8; 4],
34
35    /// If is_native.is_some, this is a native token, and the value logs the
36    /// rent-exempt reserve. An Account is required to be rent-exempt, so
37    /// the value is used by the Processor to ensure that wrapped SOL
38    /// accounts do not drop below this threshold.
39    native_amount: [u8; 8],
40
41    /// The amount delegated.
42    delegated_amount: [u8; 8],
43
44    /// Indicates whether the close authority is present or not.
45    close_authority_flag: [u8; 4],
46
47    /// Optional authority to close the account.
48    close_authority: Pubkey,
49}
50
51impl TokenAccount {
52    pub const LEN: usize = core::mem::size_of::<TokenAccount>();
53
54    /// Return a `TokenAccount` from the given account info.
55    ///
56    /// This method performs owner and length validation on `AccountInfo`, safe borrowing
57    /// the account data.
58    #[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(data)
70        }))
71    }
72
73    /// Return a `TokenAccount` from the given account info.
74    ///
75    /// This method performs owner and length validation on `AccountInfo`, but does not
76    /// perform the borrow check.
77    ///
78    /// # Safety
79    ///
80    /// The caller must ensure that it is safe to borrow the account data – e.g., there are
81    /// no mutable borrows of the account data.
82    #[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(account_info.borrow_data_unchecked()))
93    }
94
95    /// Return a `TokenAccount` from the given bytes.
96    ///
97    /// # Safety
98    ///
99    /// The caller must ensure that `bytes` contains a valid representation of `TokenAccount`.
100    #[inline(always)]
101    pub unsafe fn from_bytes(bytes: &[u8]) -> &Self {
102        &*(bytes.as_ptr() as *const TokenAccount)
103    }
104
105    pub fn mint(&self) -> &Pubkey {
106        &self.mint
107    }
108
109    pub fn owner(&self) -> &Pubkey {
110        &self.owner
111    }
112
113    pub fn amount(&self) -> u64 {
114        unsafe { core::ptr::read_unaligned(self.amount.as_ptr() as *const u64) }
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<&Pubkey> {
123        if self.has_delegate() {
124            Some(self.delegate_unchecked())
125        } else {
126            None
127        }
128    }
129
130    /// Use this when you know the account will have a delegate and want to skip the `Option` check.
131    #[inline(always)]
132    pub fn delegate_unchecked(&self) -> &Pubkey {
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    /// Return the native amount.
155    ///
156    /// This method should be used when the caller knows that the token is native since it
157    /// skips the `Option` check.
158    #[inline(always)]
159    pub fn native_amount_unchecked(&self) -> u64 {
160        unsafe { core::ptr::read_unaligned(self.native_amount.as_ptr() as *const u64) }
161    }
162
163    pub fn delegated_amount(&self) -> u64 {
164        unsafe { core::ptr::read_unaligned(self.delegated_amount.as_ptr() as *const u64) }
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<&Pubkey> {
173        if self.has_close_authority() {
174            Some(self.close_authority_unchecked())
175        } else {
176            None
177        }
178    }
179
180    /// Return the close authority.
181    ///
182    /// This method should be used when the caller knows that the token will have a close
183    /// authority set since it skips the `Option` check.
184    #[inline(always)]
185    pub fn close_authority_unchecked(&self) -> &Pubkey {
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}