use light_compressed_account::{instruction_data::compressed_proof::CompressedProof, Pubkey};
use light_compressible::compression_info::CompressionInfo;
use light_zero_copy::ZeroCopy;
use super::{
CompressAndCloseMintAction, CpiContext, DecompressMintAction, MintToAction,
MintToCompressedAction, RemoveMetadataKeyAction, UpdateAuthority,
UpdateMetadataAuthorityAction, UpdateMetadataFieldAction,
};
use crate::{
instructions::extensions::{ExtensionInstructionData, ZExtensionInstructionData},
state::{AdditionalMetadata, BaseMint, ExtensionStruct, Mint, MintMetadata, TokenMetadata},
AnchorDeserialize, AnchorSerialize, TokenError,
};
#[repr(C)]
#[derive(Debug, Clone, AnchorSerialize, AnchorDeserialize, ZeroCopy)]
pub enum Action {
MintToCompressed(MintToCompressedAction),
UpdateMintAuthority(UpdateAuthority),
UpdateFreezeAuthority(UpdateAuthority),
MintTo(MintToAction),
UpdateMetadataField(UpdateMetadataFieldAction),
UpdateMetadataAuthority(UpdateMetadataAuthorityAction),
RemoveMetadataKey(RemoveMetadataKeyAction),
DecompressMint(DecompressMintAction),
CompressAndCloseMint(CompressAndCloseMintAction),
}
#[repr(C)]
#[derive(Debug, Clone, AnchorSerialize, AnchorDeserialize, ZeroCopy)]
pub struct MintActionCompressedInstructionData {
pub leaf_index: u32,
pub prove_by_index: bool,
pub root_index: u16,
pub max_top_up: u16,
pub create_mint: Option<CreateMint>,
pub actions: Vec<Action>,
pub proof: Option<CompressedProof>,
pub cpi_context: Option<CpiContext>,
pub mint: Option<MintInstructionData>,
}
#[repr(C)]
#[derive(Debug, Clone, AnchorSerialize, Default, AnchorDeserialize, ZeroCopy)]
pub struct CreateMint {
pub read_only_address_trees: [u8; 4],
pub read_only_address_tree_root_indices: [u16; 4],
}
#[repr(C)]
#[derive(Debug, Clone, AnchorSerialize, AnchorDeserialize, ZeroCopy, PartialEq)]
pub struct MintWithContext {
pub leaf_index: u32,
pub prove_by_index: bool,
pub root_index: u16,
pub address: [u8; 32],
pub mint: Option<MintInstructionData>,
}
#[repr(C)]
#[derive(Debug, PartialEq, Eq, Clone, AnchorSerialize, AnchorDeserialize, ZeroCopy)]
pub struct MintInstructionData {
pub supply: u64,
pub decimals: u8,
pub metadata: MintMetadata,
pub mint_authority: Option<Pubkey>,
pub freeze_authority: Option<Pubkey>,
pub extensions: Option<Vec<ExtensionInstructionData>>,
}
impl TryFrom<Mint> for MintInstructionData {
type Error = TokenError;
fn try_from(mint: Mint) -> Result<Self, Self::Error> {
let extensions = match mint.extensions {
Some(exts) if !exts.is_empty() => {
let mut extension_list = Vec::with_capacity(exts.len());
for ext in exts {
match ext {
ExtensionStruct::TokenMetadata(token_metadata) => {
extension_list.push(ExtensionInstructionData::TokenMetadata(
crate::instructions::extensions::token_metadata::TokenMetadataInstructionData {
update_authority: if token_metadata.update_authority == [0u8;32] {None}else {Some(token_metadata.update_authority)},
name: token_metadata.name,
symbol: token_metadata.symbol,
uri: token_metadata.uri,
additional_metadata: Some(token_metadata.additional_metadata),
},
));
}
_ => {
return Err(TokenError::UnsupportedExtension);
}
}
}
Some(extension_list)
}
_ => None,
};
Ok(Self {
supply: mint.base.supply,
decimals: mint.base.decimals,
metadata: mint.metadata,
mint_authority: mint.base.mint_authority,
freeze_authority: mint.base.freeze_authority,
extensions,
})
}
}
impl<'a> TryFrom<&ZMintInstructionData<'a>> for Mint {
type Error = TokenError;
fn try_from(instruction_data: &ZMintInstructionData<'a>) -> Result<Self, Self::Error> {
let extensions = match &instruction_data.extensions {
Some(exts) => {
let converted_exts: Vec<_> = exts
.iter()
.map(|ext| match ext {
ZExtensionInstructionData::TokenMetadata(token_metadata_data) => {
Ok(ExtensionStruct::TokenMetadata(TokenMetadata {
update_authority: token_metadata_data
.update_authority
.map(|p| *p)
.unwrap_or_else(|| Pubkey::from([0u8; 32])),
mint: instruction_data.metadata.mint, name: token_metadata_data.name.to_vec(),
symbol: token_metadata_data.symbol.to_vec(),
uri: token_metadata_data.uri.to_vec(),
additional_metadata: token_metadata_data
.additional_metadata
.as_ref()
.map(|ams| {
ams.iter()
.map(|am| AdditionalMetadata {
key: am.key.to_vec(),
value: am.value.to_vec(),
})
.collect()
})
.unwrap_or_else(Vec::new),
}))
}
_ => Err(TokenError::UnsupportedExtension),
})
.collect::<Result<Vec<_>, _>>()?;
if converted_exts.is_empty() {
None
} else {
Some(converted_exts)
}
}
None => None,
};
Ok(Self {
base: BaseMint {
mint_authority: instruction_data.mint_authority.map(|p| *p),
supply: instruction_data.supply.into(),
decimals: instruction_data.decimals,
is_initialized: true, freeze_authority: instruction_data.freeze_authority.map(|p| *p),
},
metadata: MintMetadata {
version: instruction_data.metadata.version,
mint_decompressed: instruction_data.metadata.mint_decompressed != 0,
mint: instruction_data.metadata.mint,
mint_signer: instruction_data.metadata.mint_signer,
bump: instruction_data.metadata.bump,
},
reserved: [0u8; 16],
account_type: crate::state::mint::ACCOUNT_TYPE_MINT,
compression: CompressionInfo::default(),
extensions,
})
}
}