use super::AccountState;
use hayabusa_ser::{FromBytesUnchecked, RawZcDeserialize, Deserialize, Zc};
use hayabusa_utility::fail_with_ctx;
use pinocchio::{
account_info::{AccountInfo, Ref}, hint::unlikely, program_error::ProgramError, pubkey::Pubkey
};
#[repr(C)]
pub struct TokenAccount {
mint: Pubkey,
owner: Pubkey,
amount: [u8; 8],
delegate_flag: [u8; 4],
delegate: Pubkey,
state: u8,
is_native: [u8; 4],
native_amount: [u8; 8],
delegated_amount: [u8; 8],
close_authority_flag: [u8; 4],
close_authority: Pubkey,
}
impl FromBytesUnchecked for TokenAccount {}
impl Zc for TokenAccount {}
impl Deserialize for TokenAccount {}
unsafe impl RawZcDeserialize for TokenAccount {
#[inline]
fn try_deserialize_raw<'a>(
account_info: &'a AccountInfo,
) -> Result<Ref<'a, Self>, ProgramError> {
if unlikely(account_info.data_len() != Self::LEN) {
fail_with_ctx!(
"HAYABUSA_SER_TOKEN_ACCOUNT_DATA_TOO_SHORT",
ProgramError::InvalidAccountData,
account_info.key(),
&u32::to_le_bytes(account_info.data_len() as u32),
&u32::to_le_bytes(Self::LEN as u32),
);
}
if unlikely(!account_info.is_owned_by(&crate::ID)) {
fail_with_ctx!(
"HAYABUSA_SER_TOKEN_ACCOUNT_INVALID_OWNER",
ProgramError::InvalidAccountOwner,
account_info.key(),
account_info.owner(),
&crate::ID,
);
}
Ok(Ref::map(account_info.try_borrow_data()?, |d| unsafe {
Self::from_bytes_unchecked(d)
}))
}
}
impl TokenAccount {
pub const LEN: usize = core::mem::size_of::<TokenAccount>();
pub fn mint(&self) -> &Pubkey {
&self.mint
}
pub fn owner(&self) -> &Pubkey {
&self.owner
}
pub fn amount(&self) -> u64 {
u64::from_le_bytes(self.amount)
}
#[inline(always)]
pub fn has_delegate(&self) -> bool {
self.delegate_flag[0] == 1
}
pub fn delegate(&self) -> Option<&Pubkey> {
if self.has_delegate() {
Some(self.delegate_unchecked())
} else {
None
}
}
#[inline(always)]
pub fn delegate_unchecked(&self) -> &Pubkey {
&self.delegate
}
#[inline(always)]
pub fn state(&self) -> AccountState {
self.state.into()
}
#[inline(always)]
pub fn is_native(&self) -> bool {
self.is_native[0] == 1
}
pub fn native_amount(&self) -> Option<u64> {
if self.is_native() {
Some(self.native_amount_unchecked())
} else {
None
}
}
#[inline(always)]
pub fn native_amount_unchecked(&self) -> u64 {
u64::from_le_bytes(self.native_amount)
}
pub fn delegated_amount(&self) -> u64 {
u64::from_le_bytes(self.delegated_amount)
}
#[inline(always)]
pub fn has_close_authority(&self) -> bool {
self.close_authority_flag[0] == 1
}
pub fn close_authority(&self) -> Option<&Pubkey> {
if self.has_close_authority() {
Some(self.close_authority_unchecked())
} else {
None
}
}
#[inline(always)]
pub fn close_authority_unchecked(&self) -> &Pubkey {
&self.close_authority
}
#[inline(always)]
pub fn is_initialized(&self) -> bool {
self.state != AccountState::Uninitialized as u8
}
#[inline(always)]
pub fn is_frozen(&self) -> bool {
self.state == AccountState::Frozen as u8
}
}