use light_compressed_account::compressed_account::CompressedAccountWithMerkleContext;
use light_sdk::light_hasher::{sha256::Sha256BE, HasherError};
use solana_program_error::ProgramError;
use solana_pubkey::Pubkey;
use crate::{AnchorDeserialize, AnchorSerialize};
#[derive(Clone, Copy, Debug, PartialEq, Eq, AnchorDeserialize, AnchorSerialize, Default)]
#[repr(u8)]
pub enum AccountState {
#[default]
Initialized = 0,
Frozen = 1,
}
impl From<AccountState> for light_token_interface::state::CompressedTokenAccountState {
fn from(state: AccountState) -> Self {
match state {
AccountState::Initialized => {
light_token_interface::state::CompressedTokenAccountState::Initialized
}
AccountState::Frozen => {
light_token_interface::state::CompressedTokenAccountState::Frozen
}
}
}
}
impl TryFrom<u8> for AccountState {
type Error = ProgramError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(AccountState::Initialized),
1 => Ok(AccountState::Frozen),
_ => Err(ProgramError::InvalidAccountData),
}
}
}
#[derive(Debug, PartialEq, Eq, AnchorDeserialize, AnchorSerialize, Clone, Default)]
pub struct TokenData {
pub mint: Pubkey,
pub owner: Pubkey,
pub amount: u64,
pub delegate: Option<Pubkey>,
pub state: AccountState,
pub tlv: Option<Vec<light_token_interface::state::ExtensionStruct>>,
}
impl TokenData {
#[inline(always)]
pub fn hash_sha_flat(&self) -> Result<[u8; 32], HasherError> {
use light_sdk::light_hasher::Hasher;
let bytes = self.try_to_vec().map_err(|_| HasherError::BorshError)?;
Sha256BE::hash(bytes.as_slice())
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TokenDataWithMerkleContext {
pub token_data: TokenData,
pub compressed_account: CompressedAccountWithMerkleContext,
}
impl TokenDataWithMerkleContext {
pub fn hash(&self) -> Result<[u8; 32], HasherError> {
if let Some(data) = self.compressed_account.compressed_account.data.as_ref() {
match data.discriminator {
[0, 0, 0, 0, 0, 0, 0, 4] => self.token_data.hash_sha_flat(),
_ => Err(HasherError::EmptyInput),
}
} else {
Err(HasherError::EmptyInput)
}
}
}
impl From<TokenData> for light_token_interface::state::TokenData {
fn from(data: TokenData) -> Self {
use light_token_interface::state::CompressedTokenAccountState;
Self {
mint: data.mint.to_bytes().into(),
owner: data.owner.to_bytes().into(),
amount: data.amount,
delegate: data.delegate.map(|d| d.to_bytes().into()),
state: match data.state {
AccountState::Initialized => CompressedTokenAccountState::Initialized as u8,
AccountState::Frozen => CompressedTokenAccountState::Frozen as u8,
},
tlv: data.tlv,
}
}
}
impl From<light_token_interface::state::TokenData> for TokenData {
fn from(data: light_token_interface::state::TokenData) -> Self {
Self {
mint: Pubkey::new_from_array(data.mint.to_bytes()),
owner: Pubkey::new_from_array(data.owner.to_bytes()),
amount: data.amount,
delegate: data.delegate.map(|d| Pubkey::new_from_array(d.to_bytes())),
state: AccountState::try_from(data.state).unwrap_or(AccountState::Initialized),
tlv: data.tlv,
}
}
}
pub type InputTokenDataCompressible =
light_token_interface::instructions::transfer2::MultiTokenTransferOutputData;