light_token_interface/state/mint/
compressed_mint.rs1use borsh::{BorshDeserialize, BorshSerialize};
2use light_compressed_account::{address::derive_address, Pubkey};
3use light_compressible::compression_info::CompressionInfo;
4use light_hasher::{sha256::Sha256BE, Hasher};
5use light_zero_copy::{ZeroCopy, ZeroCopyMut};
6use pinocchio::account_info::AccountInfo;
7#[cfg(feature = "solana")]
8use solana_msg::msg;
9
10use crate::{
11 state::ExtensionStruct, AnchorDeserialize, AnchorSerialize, TokenError, LIGHT_TOKEN_PROGRAM_ID,
12 MINT_ADDRESS_TREE,
13};
14
15pub const ACCOUNT_TYPE_MINT: u8 = 1;
17
18#[repr(C)]
19#[derive(Debug, PartialEq, Eq, Clone, BorshSerialize, BorshDeserialize)]
20pub struct Mint {
21 pub base: BaseMint,
22 pub metadata: MintMetadata,
23 pub reserved: [u8; 16],
26 pub account_type: u8,
28 pub compression: CompressionInfo,
30 pub extensions: Option<Vec<ExtensionStruct>>,
31}
32
33impl Default for Mint {
34 fn default() -> Self {
35 Self {
36 base: BaseMint::default(),
37 metadata: MintMetadata::default(),
38 reserved: [0u8; 16],
39 account_type: ACCOUNT_TYPE_MINT,
40 compression: CompressionInfo::default(),
41 extensions: None,
42 }
43 }
44}
45
46#[repr(C)]
49#[derive(Debug, Default, PartialEq, Eq, Clone)]
50pub struct BaseMint {
51 pub mint_authority: Option<Pubkey>,
56 pub supply: u64,
58 pub decimals: u8,
60 pub is_initialized: bool,
62 pub freeze_authority: Option<Pubkey>,
64}
65
66#[repr(C)]
75#[derive(
76 Debug, Default, PartialEq, Eq, Clone, AnchorDeserialize, AnchorSerialize, ZeroCopyMut, ZeroCopy,
77)]
78pub struct MintMetadata {
79 pub version: u8,
81 pub mint_decompressed: bool,
84 pub mint: Pubkey,
86 pub mint_signer: [u8; 32],
88 pub bump: u8,
90}
91
92impl MintMetadata {
93 pub fn compressed_address(&self) -> [u8; 32] {
95 derive_address(
96 self.mint.array_ref(),
97 &MINT_ADDRESS_TREE,
98 &LIGHT_TOKEN_PROGRAM_ID,
99 )
100 }
101}
102
103impl ZMintMetadata<'_> {
104 pub fn compressed_address(&self) -> [u8; 32] {
106 derive_address(
107 self.mint.array_ref(),
108 &MINT_ADDRESS_TREE,
109 &LIGHT_TOKEN_PROGRAM_ID,
110 )
111 }
112}
113
114impl Mint {
115 pub fn hash(&self) -> Result<[u8; 32], TokenError> {
116 match self.metadata.version {
117 3 => Ok(Sha256BE::hash(
118 self.try_to_vec()
119 .map_err(|_| TokenError::BorshFailed)?
120 .as_slice(),
121 )?),
122 _ => Err(TokenError::InvalidTokenDataVersion),
123 }
124 }
125
126 pub fn from_account_info_checked(account_info: &AccountInfo) -> Result<Self, TokenError> {
135 if !account_info.is_owned_by(&LIGHT_TOKEN_PROGRAM_ID) {
137 #[cfg(feature = "solana")]
138 msg!("Mint account has invalid owner");
139 return Err(TokenError::InvalidMintOwner);
140 }
141
142 let data = account_info
144 .try_borrow_data()
145 .map_err(|_| TokenError::MintBorrowFailed)?;
146
147 let mint =
148 Self::try_from_slice(&data).map_err(|_| TokenError::MintDeserializationFailed)?;
149
150 if !mint.base.is_initialized {
152 #[cfg(feature = "solana")]
153 msg!("Mint account is not initialized");
154 return Err(TokenError::MintNotInitialized);
155 }
156
157 if !mint.is_mint_account() {
158 #[cfg(feature = "solana")]
159 msg!("Mint account is not a Mint account");
160 return Err(TokenError::MintMismatch);
161 }
162
163 Ok(mint)
164 }
165
166 #[inline(always)]
168 pub fn is_mint_account(&self) -> bool {
169 self.account_type == ACCOUNT_TYPE_MINT
170 }
171}