1use light_compressed_account::instruction_data::{
2 compressed_proof::ValidityProof, traits::LightInstructionData,
3};
4use light_compressed_token_sdk::compressed_token::mint_action::MintActionMetaConfig;
5use light_token_interface::instructions::mint_action::{
6 CpiContext, DecompressMintAction, MintActionCompressedInstructionData, MintWithContext,
7};
8use solana_account_info::AccountInfo;
9use solana_cpi::{invoke, invoke_signed};
10use solana_instruction::Instruction;
11use solana_program_error::ProgramError;
12use solana_pubkey::Pubkey;
13
14use crate::{
15 constants::{config_pda, rent_sponsor_pda},
16 instruction::SystemAccountInfos,
17};
18
19#[derive(Debug, Clone)]
39pub struct DecompressMint {
40 pub payer: Pubkey,
42 pub authority: Pubkey,
44 pub state_tree: Pubkey,
46 pub input_queue: Pubkey,
48 pub output_queue: Pubkey,
50 pub compressed_mint_with_context: MintWithContext,
52 pub proof: ValidityProof,
54 pub rent_payment: u8,
56 pub write_top_up: u32,
58}
59
60impl DecompressMint {
61 pub fn instruction(self) -> Result<Instruction, ProgramError> {
62 let mint_data = self
64 .compressed_mint_with_context
65 .mint
66 .as_ref()
67 .ok_or(ProgramError::InvalidInstructionData)?;
68 let mint_pda = Pubkey::from(mint_data.metadata.mint.to_bytes());
69
70 let action = DecompressMintAction {
72 rent_payment: self.rent_payment,
73 write_top_up: self.write_top_up,
74 };
75
76 let instruction_data = MintActionCompressedInstructionData::new(
78 self.compressed_mint_with_context,
79 self.proof.0,
80 )
81 .with_decompress_mint(action);
82
83 let meta_config = MintActionMetaConfig::new(
85 self.payer,
86 self.authority,
87 self.state_tree,
88 self.input_queue,
89 self.output_queue,
90 )
91 .with_compressible_mint(mint_pda, config_pda(), rent_sponsor_pda());
92
93 let account_metas = meta_config.to_account_metas();
94
95 let data = instruction_data
96 .data()
97 .map_err(|e| ProgramError::BorshIoError(e.to_string()))?;
98
99 Ok(Instruction {
100 program_id: Pubkey::new_from_array(light_token_interface::LIGHT_TOKEN_PROGRAM_ID),
101 accounts: account_metas,
102 data,
103 })
104 }
105}
106
107pub struct DecompressMintCpi<'info> {
136 pub authority: AccountInfo<'info>,
138 pub payer: AccountInfo<'info>,
140 pub mint: AccountInfo<'info>,
142 pub compressible_config: AccountInfo<'info>,
144 pub rent_sponsor: AccountInfo<'info>,
146 pub state_tree: AccountInfo<'info>,
148 pub input_queue: AccountInfo<'info>,
150 pub output_queue: AccountInfo<'info>,
152 pub system_accounts: SystemAccountInfos<'info>,
154 pub compressed_mint_with_context: MintWithContext,
156 pub proof: ValidityProof,
158 pub rent_payment: u8,
160 pub write_top_up: u32,
162}
163
164impl<'info> DecompressMintCpi<'info> {
165 pub fn instruction(&self) -> Result<Instruction, ProgramError> {
166 DecompressMint::try_from(self)?.instruction()
167 }
168
169 pub fn invoke(self) -> Result<(), ProgramError> {
170 let instruction = self.instruction()?;
171
172 let account_infos = self.build_account_infos();
189 invoke(&instruction, &account_infos)
190 }
191
192 pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> {
193 let instruction = self.instruction()?;
194 let account_infos = self.build_account_infos();
195 invoke_signed(&instruction, &account_infos, signer_seeds)
196 }
197
198 fn build_account_infos(&self) -> Vec<AccountInfo<'info>> {
199 vec![
200 self.system_accounts.light_system_program.clone(),
201 self.authority.clone(),
202 self.compressible_config.clone(),
203 self.mint.clone(),
204 self.rent_sponsor.clone(),
205 self.payer.clone(),
206 self.system_accounts.cpi_authority_pda.clone(),
207 self.system_accounts.registered_program_pda.clone(),
208 self.system_accounts.account_compression_authority.clone(),
209 self.system_accounts.account_compression_program.clone(),
210 self.system_accounts.system_program.clone(),
211 self.output_queue.clone(),
212 self.state_tree.clone(),
213 self.input_queue.clone(),
214 ]
215 }
216}
217
218impl<'info> TryFrom<&DecompressMintCpi<'info>> for DecompressMint {
219 type Error = ProgramError;
220
221 fn try_from(cpi: &DecompressMintCpi<'info>) -> Result<Self, Self::Error> {
222 Ok(Self {
223 payer: *cpi.payer.key,
224 authority: *cpi.authority.key,
225 state_tree: *cpi.state_tree.key,
226 input_queue: *cpi.input_queue.key,
227 output_queue: *cpi.output_queue.key,
228 compressed_mint_with_context: cpi.compressed_mint_with_context.clone(),
229 proof: cpi.proof,
230 rent_payment: cpi.rent_payment,
231 write_top_up: cpi.write_top_up,
232 })
233 }
234}
235
236#[derive(Debug, Clone)]
241pub struct DecompressCMintWithCpiContext {
242 pub mint_seed_pubkey: Pubkey,
244 pub payer: Pubkey,
246 pub authority: Pubkey,
248 pub state_tree: Pubkey,
250 pub input_queue: Pubkey,
252 pub output_queue: Pubkey,
254 pub compressed_mint_with_context: MintWithContext,
256 pub proof: ValidityProof,
258 pub rent_payment: u8,
260 pub write_top_up: u32,
262 pub cpi_context_pubkey: Pubkey,
264 pub cpi_context: CpiContext,
266 pub compressible_config: Pubkey,
268 pub rent_sponsor: Pubkey,
270}
271
272impl DecompressCMintWithCpiContext {
273 pub fn instruction(self) -> Result<Instruction, ProgramError> {
274 let (mint_pda, _cmint_bump) = crate::instruction::find_mint_address(&self.mint_seed_pubkey);
276
277 let action = DecompressMintAction {
279 rent_payment: self.rent_payment,
280 write_top_up: self.write_top_up,
281 };
282
283 let instruction_data = MintActionCompressedInstructionData::new(
285 self.compressed_mint_with_context,
286 self.proof.0,
287 )
288 .with_decompress_mint(action)
289 .with_cpi_context(self.cpi_context.clone());
290
291 let mut meta_config = MintActionMetaConfig::new(
294 self.payer,
295 self.authority,
296 self.state_tree,
297 self.input_queue,
298 self.output_queue,
299 )
300 .with_compressible_mint(mint_pda, self.compressible_config, self.rent_sponsor);
301
302 meta_config.cpi_context = Some(self.cpi_context_pubkey);
303
304 let account_metas = meta_config.to_account_metas();
305
306 let data = instruction_data
307 .data()
308 .map_err(|e| ProgramError::BorshIoError(e.to_string()))?;
309
310 Ok(Instruction {
311 program_id: Pubkey::new_from_array(light_token_interface::LIGHT_TOKEN_PROGRAM_ID),
312 accounts: account_metas,
313 data,
314 })
315 }
316}
317
318pub struct DecompressCMintCpiWithContext<'info> {
320 pub mint_seed: AccountInfo<'info>,
322 pub authority: AccountInfo<'info>,
324 pub payer: AccountInfo<'info>,
326 pub mint: AccountInfo<'info>,
328 pub compressible_config: AccountInfo<'info>,
330 pub rent_sponsor: AccountInfo<'info>,
332 pub state_tree: AccountInfo<'info>,
334 pub input_queue: AccountInfo<'info>,
336 pub output_queue: AccountInfo<'info>,
338 pub cpi_context_account: AccountInfo<'info>,
340 pub system_accounts: SystemAccountInfos<'info>,
342 pub light_token_cpi_authority: AccountInfo<'info>,
345 pub compressed_mint_with_context: MintWithContext,
347 pub proof: ValidityProof,
349 pub rent_payment: u8,
351 pub write_top_up: u32,
353 pub cpi_context: CpiContext,
355}
356
357impl<'info> DecompressCMintCpiWithContext<'info> {
358 pub fn instruction(&self) -> Result<Instruction, ProgramError> {
359 DecompressCMintWithCpiContext {
360 mint_seed_pubkey: *self.mint_seed.key,
361 payer: *self.payer.key,
362 authority: *self.authority.key,
363 state_tree: *self.state_tree.key,
364 input_queue: *self.input_queue.key,
365 output_queue: *self.output_queue.key,
366 compressed_mint_with_context: self.compressed_mint_with_context.clone(),
367 proof: self.proof,
368 rent_payment: self.rent_payment,
369 write_top_up: self.write_top_up,
370 cpi_context_pubkey: *self.cpi_context_account.key,
371 cpi_context: self.cpi_context.clone(),
372 compressible_config: *self.compressible_config.key,
373 rent_sponsor: *self.rent_sponsor.key,
374 }
375 .instruction()
376 }
377
378 pub fn invoke(self) -> Result<(), ProgramError> {
379 let instruction = self.instruction()?;
380 let account_infos = self.build_account_infos();
381 invoke(&instruction, &account_infos)
382 }
383
384 pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> {
385 let instruction = self.instruction()?;
386 let account_infos = self.build_account_infos();
387 invoke_signed(&instruction, &account_infos, signer_seeds)
388 }
389
390 fn build_account_infos(&self) -> Vec<AccountInfo<'info>> {
391 vec![
392 self.system_accounts.light_system_program.clone(),
393 self.mint_seed.clone(),
394 self.authority.clone(),
395 self.compressible_config.clone(),
396 self.mint.clone(),
397 self.rent_sponsor.clone(),
398 self.payer.clone(),
399 self.light_token_cpi_authority.clone(),
401 self.system_accounts.registered_program_pda.clone(),
402 self.system_accounts.account_compression_authority.clone(),
403 self.system_accounts.account_compression_program.clone(),
404 self.system_accounts.system_program.clone(),
405 self.cpi_context_account.clone(),
406 self.output_queue.clone(),
407 self.state_tree.clone(),
408 self.input_queue.clone(),
409 ]
410 }
411}
412
413pub fn create_decompress_mint_cpi_context_first(
415 address_tree_pubkey: [u8; 32],
416 tree_index: u8,
417 queue_index: u8,
418) -> CpiContext {
419 CpiContext {
420 first_set_context: true,
421 set_context: false,
422 in_tree_index: tree_index,
423 in_queue_index: queue_index,
424 out_queue_index: queue_index,
425 token_out_queue_index: 0,
426 assigned_account_index: 0,
427 read_only_address_trees: [0; 4],
428 address_tree_pubkey,
429 }
430}
431
432pub fn create_decompress_mint_cpi_context_set(
434 address_tree_pubkey: [u8; 32],
435 tree_index: u8,
436 queue_index: u8,
437) -> CpiContext {
438 CpiContext {
439 first_set_context: false,
440 set_context: true,
441 in_tree_index: tree_index,
442 in_queue_index: queue_index,
443 out_queue_index: queue_index,
444 token_out_queue_index: 0,
445 assigned_account_index: 0,
446 read_only_address_trees: [0; 4],
447 address_tree_pubkey,
448 }
449}
450
451pub fn create_decompress_mint_cpi_context_execute(
453 address_tree_pubkey: [u8; 32],
454 tree_index: u8,
455 queue_index: u8,
456) -> CpiContext {
457 CpiContext {
458 first_set_context: false,
459 set_context: false,
460 in_tree_index: tree_index,
461 in_queue_index: queue_index,
462 out_queue_index: queue_index,
463 token_out_queue_index: 0,
464 assigned_account_index: 0,
465 read_only_address_trees: [0; 4],
466 address_tree_pubkey,
467 }
468}