use light_compressed_account::Pubkey;
use light_program_profiler::profile;
use light_zero_copy::{num_trait::ZeroCopyNumTrait, ZeroCopy, ZeroCopyMut};
use crate::{
instructions::extensions::ZExtensionInstructionData,
state::extensions::{ExtensionStruct, ZExtensionStructMut},
AnchorDeserialize, AnchorSerialize, TokenError,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq, AnchorSerialize, AnchorDeserialize)]
#[repr(u8)]
pub enum CompressedTokenAccountState {
Initialized = 0,
Frozen = 1,
}
impl TryFrom<u8> for CompressedTokenAccountState {
type Error = TokenError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(CompressedTokenAccountState::Initialized),
1 => Ok(CompressedTokenAccountState::Frozen),
_ => Err(TokenError::InvalidAccountState),
}
}
}
#[derive(
Debug, PartialEq, Eq, AnchorSerialize, AnchorDeserialize, Clone, ZeroCopy, ZeroCopyMut,
)]
#[repr(C)]
pub struct TokenData {
pub mint: Pubkey,
pub owner: Pubkey,
pub amount: u64,
pub delegate: Option<Pubkey>,
pub state: u8,
pub tlv: Option<Vec<ExtensionStruct>>,
}
impl TokenData {
pub fn state(&self) -> Result<CompressedTokenAccountState, TokenError> {
CompressedTokenAccountState::try_from(self.state)
}
}
impl<'a> ZTokenDataMut<'a> {
#[inline]
#[profile]
pub fn set(
&mut self,
mint: Pubkey,
owner: Pubkey,
amount: impl ZeroCopyNumTrait,
delegate: Option<Pubkey>,
state: CompressedTokenAccountState,
tlv_data: Option<&[ZExtensionInstructionData<'_>]>,
) -> Result<(), TokenError> {
self.mint = mint;
self.owner = owner;
self.amount.set(amount.into());
if let Some(z_delegate) = self.delegate.as_deref_mut() {
*z_delegate = delegate.ok_or(TokenError::InstructionDataExpectedDelegate)?;
}
if self.delegate.is_none() && delegate.is_some() {
return Err(TokenError::ZeroCopyExpectedDelegate);
}
*self.state = state as u8;
match (self.tlv.as_mut(), tlv_data) {
(Some(tlv_vec), Some(exts)) => {
if tlv_vec.len() != 1 || exts.len() != 1 {
return Err(TokenError::TlvExtensionLengthMismatch);
}
for (tlv_ext, instruction_ext) in tlv_vec.iter_mut().zip(exts.iter()) {
match (tlv_ext, instruction_ext) {
(
ZExtensionStructMut::CompressedOnly(compressed_only),
ZExtensionInstructionData::CompressedOnly(data),
) => {
compressed_only.delegated_amount = data.delegated_amount;
compressed_only.withheld_transfer_fee = data.withheld_transfer_fee;
compressed_only.is_ata = if data.is_ata() { 1 } else { 0 };
}
_ => return Err(TokenError::UnsupportedTlvExtensionType),
}
}
}
(Some(_), None) | (None, Some(_)) => {
return Err(TokenError::TlvExtensionLengthMismatch);
}
(None, None) => {}
}
Ok(())
}
}