1use light_compressed_account::instruction_data::{
2 compressed_proof::ValidityProof, traits::LightInstructionData,
3};
4use light_token_interface::instructions::mint_action::{
5 CpiContext, DecompressMintAction, MintActionCompressedInstructionData, MintWithContext,
6};
7use solana_account_info::AccountInfo;
8use solana_cpi::{invoke, invoke_signed};
9use solana_instruction::Instruction;
10use solana_program_error::ProgramError;
11use solana_pubkey::Pubkey;
12
13use crate::{
14 compressed_token::mint_action::MintActionMetaConfig,
15 instruction::{config_pda, rent_sponsor_pda, SystemAccountInfos},
16};
17
18#[derive(Debug, Clone)]
38pub struct DecompressMint {
39 pub payer: Pubkey,
41 pub authority: Pubkey,
43 pub state_tree: Pubkey,
45 pub input_queue: Pubkey,
47 pub output_queue: Pubkey,
49 pub compressed_mint_with_context: MintWithContext,
51 pub proof: ValidityProof,
53 pub rent_payment: u8,
55 pub write_top_up: u32,
57}
58
59impl DecompressMint {
60 pub fn instruction(self) -> Result<Instruction, ProgramError> {
61 let mint_data = self
63 .compressed_mint_with_context
64 .mint
65 .as_ref()
66 .ok_or(ProgramError::InvalidInstructionData)?;
67 let mint_pda = Pubkey::from(mint_data.metadata.mint.to_bytes());
68
69 let action = DecompressMintAction {
71 rent_payment: self.rent_payment,
72 write_top_up: self.write_top_up,
73 };
74
75 let instruction_data = MintActionCompressedInstructionData::new(
77 self.compressed_mint_with_context,
78 self.proof.0,
79 )
80 .with_decompress_mint(action);
81
82 let meta_config = MintActionMetaConfig::new(
84 self.payer,
85 self.authority,
86 self.state_tree,
87 self.input_queue,
88 self.output_queue,
89 )
90 .with_compressible_mint(mint_pda, config_pda(), rent_sponsor_pda());
91
92 let account_metas = meta_config.to_account_metas();
93
94 let data = instruction_data
95 .data()
96 .map_err(|e| ProgramError::BorshIoError(e.to_string()))?;
97
98 Ok(Instruction {
99 program_id: Pubkey::new_from_array(light_token_interface::LIGHT_TOKEN_PROGRAM_ID),
100 accounts: account_metas,
101 data,
102 })
103 }
104}
105
106pub struct DecompressMintCpi<'info> {
135 pub authority: AccountInfo<'info>,
137 pub payer: AccountInfo<'info>,
139 pub mint: AccountInfo<'info>,
141 pub compressible_config: AccountInfo<'info>,
143 pub rent_sponsor: AccountInfo<'info>,
145 pub state_tree: AccountInfo<'info>,
147 pub input_queue: AccountInfo<'info>,
149 pub output_queue: AccountInfo<'info>,
151 pub system_accounts: SystemAccountInfos<'info>,
153 pub compressed_mint_with_context: MintWithContext,
155 pub proof: ValidityProof,
157 pub rent_payment: u8,
159 pub write_top_up: u32,
161}
162
163impl<'info> DecompressMintCpi<'info> {
164 pub fn instruction(&self) -> Result<Instruction, ProgramError> {
165 DecompressMint::try_from(self)?.instruction()
166 }
167
168 pub fn invoke(self) -> Result<(), ProgramError> {
169 let instruction = self.instruction()?;
170
171 let account_infos = self.build_account_infos();
188 invoke(&instruction, &account_infos)
189 }
190
191 pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> {
192 let instruction = self.instruction()?;
193 let account_infos = self.build_account_infos();
194 invoke_signed(&instruction, &account_infos, signer_seeds)
195 }
196
197 fn build_account_infos(&self) -> Vec<AccountInfo<'info>> {
198 vec![
199 self.system_accounts.light_system_program.clone(),
200 self.authority.clone(),
201 self.compressible_config.clone(),
202 self.mint.clone(),
203 self.rent_sponsor.clone(),
204 self.payer.clone(),
205 self.system_accounts.cpi_authority_pda.clone(),
206 self.system_accounts.registered_program_pda.clone(),
207 self.system_accounts.account_compression_authority.clone(),
208 self.system_accounts.account_compression_program.clone(),
209 self.system_accounts.system_program.clone(),
210 self.output_queue.clone(),
211 self.state_tree.clone(),
212 self.input_queue.clone(),
213 ]
214 }
215}
216
217impl<'info> TryFrom<&DecompressMintCpi<'info>> for DecompressMint {
218 type Error = ProgramError;
219
220 fn try_from(cpi: &DecompressMintCpi<'info>) -> Result<Self, Self::Error> {
221 Ok(Self {
222 payer: *cpi.payer.key,
223 authority: *cpi.authority.key,
224 state_tree: *cpi.state_tree.key,
225 input_queue: *cpi.input_queue.key,
226 output_queue: *cpi.output_queue.key,
227 compressed_mint_with_context: cpi.compressed_mint_with_context.clone(),
228 proof: cpi.proof,
229 rent_payment: cpi.rent_payment,
230 write_top_up: cpi.write_top_up,
231 })
232 }
233}
234
235#[derive(Debug, Clone)]
240pub struct DecompressCMintWithCpiContext {
241 pub mint_seed_pubkey: Pubkey,
243 pub payer: Pubkey,
245 pub authority: Pubkey,
247 pub state_tree: Pubkey,
249 pub input_queue: Pubkey,
251 pub output_queue: Pubkey,
253 pub compressed_mint_with_context: MintWithContext,
255 pub proof: ValidityProof,
257 pub rent_payment: u8,
259 pub write_top_up: u32,
261 pub cpi_context_pubkey: Pubkey,
263 pub cpi_context: CpiContext,
265 pub compressible_config: Pubkey,
267 pub rent_sponsor: Pubkey,
269}
270
271impl DecompressCMintWithCpiContext {
272 pub fn instruction(self) -> Result<Instruction, ProgramError> {
273 let (mint_pda, _cmint_bump) = crate::instruction::find_mint_address(&self.mint_seed_pubkey);
275
276 let action = DecompressMintAction {
278 rent_payment: self.rent_payment,
279 write_top_up: self.write_top_up,
280 };
281
282 let instruction_data = MintActionCompressedInstructionData::new(
284 self.compressed_mint_with_context,
285 self.proof.0,
286 )
287 .with_decompress_mint(action)
288 .with_cpi_context(self.cpi_context.clone());
289
290 let mut meta_config = MintActionMetaConfig::new(
293 self.payer,
294 self.authority,
295 self.state_tree,
296 self.input_queue,
297 self.output_queue,
298 )
299 .with_compressible_mint(mint_pda, self.compressible_config, self.rent_sponsor);
300
301 meta_config.cpi_context = Some(self.cpi_context_pubkey);
302
303 let account_metas = meta_config.to_account_metas();
304
305 let data = instruction_data
306 .data()
307 .map_err(|e| ProgramError::BorshIoError(e.to_string()))?;
308
309 Ok(Instruction {
310 program_id: Pubkey::new_from_array(light_token_interface::LIGHT_TOKEN_PROGRAM_ID),
311 accounts: account_metas,
312 data,
313 })
314 }
315}
316
317pub struct DecompressCMintCpiWithContext<'info> {
319 pub mint_seed: AccountInfo<'info>,
321 pub authority: AccountInfo<'info>,
323 pub payer: AccountInfo<'info>,
325 pub mint: AccountInfo<'info>,
327 pub compressible_config: AccountInfo<'info>,
329 pub rent_sponsor: AccountInfo<'info>,
331 pub state_tree: AccountInfo<'info>,
333 pub input_queue: AccountInfo<'info>,
335 pub output_queue: AccountInfo<'info>,
337 pub cpi_context_account: AccountInfo<'info>,
339 pub system_accounts: SystemAccountInfos<'info>,
341 pub light_token_cpi_authority: AccountInfo<'info>,
344 pub compressed_mint_with_context: MintWithContext,
346 pub proof: ValidityProof,
348 pub rent_payment: u8,
350 pub write_top_up: u32,
352 pub cpi_context: CpiContext,
354}
355
356impl<'info> DecompressCMintCpiWithContext<'info> {
357 pub fn instruction(&self) -> Result<Instruction, ProgramError> {
358 DecompressCMintWithCpiContext {
359 mint_seed_pubkey: *self.mint_seed.key,
360 payer: *self.payer.key,
361 authority: *self.authority.key,
362 state_tree: *self.state_tree.key,
363 input_queue: *self.input_queue.key,
364 output_queue: *self.output_queue.key,
365 compressed_mint_with_context: self.compressed_mint_with_context.clone(),
366 proof: self.proof,
367 rent_payment: self.rent_payment,
368 write_top_up: self.write_top_up,
369 cpi_context_pubkey: *self.cpi_context_account.key,
370 cpi_context: self.cpi_context.clone(),
371 compressible_config: *self.compressible_config.key,
372 rent_sponsor: *self.rent_sponsor.key,
373 }
374 .instruction()
375 }
376
377 pub fn invoke(self) -> Result<(), ProgramError> {
378 let instruction = self.instruction()?;
379 let account_infos = self.build_account_infos();
380 invoke(&instruction, &account_infos)
381 }
382
383 pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> {
384 let instruction = self.instruction()?;
385 let account_infos = self.build_account_infos();
386 invoke_signed(&instruction, &account_infos, signer_seeds)
387 }
388
389 fn build_account_infos(&self) -> Vec<AccountInfo<'info>> {
390 vec![
391 self.system_accounts.light_system_program.clone(),
392 self.mint_seed.clone(),
393 self.authority.clone(),
394 self.compressible_config.clone(),
395 self.mint.clone(),
396 self.rent_sponsor.clone(),
397 self.payer.clone(),
398 self.light_token_cpi_authority.clone(),
400 self.system_accounts.registered_program_pda.clone(),
401 self.system_accounts.account_compression_authority.clone(),
402 self.system_accounts.account_compression_program.clone(),
403 self.system_accounts.system_program.clone(),
404 self.cpi_context_account.clone(),
405 self.output_queue.clone(),
406 self.state_tree.clone(),
407 self.input_queue.clone(),
408 ]
409 }
410}
411
412pub fn create_decompress_mint_cpi_context_first(
414 address_tree_pubkey: [u8; 32],
415 tree_index: u8,
416 queue_index: u8,
417) -> CpiContext {
418 CpiContext {
419 first_set_context: true,
420 set_context: false,
421 in_tree_index: tree_index,
422 in_queue_index: queue_index,
423 out_queue_index: queue_index,
424 token_out_queue_index: 0,
425 assigned_account_index: 0,
426 read_only_address_trees: [0; 4],
427 address_tree_pubkey,
428 }
429}
430
431pub fn create_decompress_mint_cpi_context_set(
433 address_tree_pubkey: [u8; 32],
434 tree_index: u8,
435 queue_index: u8,
436) -> CpiContext {
437 CpiContext {
438 first_set_context: false,
439 set_context: true,
440 in_tree_index: tree_index,
441 in_queue_index: queue_index,
442 out_queue_index: queue_index,
443 token_out_queue_index: 0,
444 assigned_account_index: 0,
445 read_only_address_trees: [0; 4],
446 address_tree_pubkey,
447 }
448}
449
450pub fn create_decompress_mint_cpi_context_execute(
452 address_tree_pubkey: [u8; 32],
453 tree_index: u8,
454 queue_index: u8,
455) -> CpiContext {
456 CpiContext {
457 first_set_context: false,
458 set_context: false,
459 in_tree_index: tree_index,
460 in_queue_index: queue_index,
461 out_queue_index: queue_index,
462 token_out_queue_index: 0,
463 assigned_account_index: 0,
464 read_only_address_trees: [0; 4],
465 address_tree_pubkey,
466 }
467}