use light_compressed_account::instruction_data::{
compressed_proof::ValidityProof, traits::LightInstructionData,
};
use light_compressed_token_sdk::compressed_token::mint_action::MintActionMetaConfig;
use light_token_interface::instructions::mint_action::{
CpiContext, DecompressMintAction, MintActionCompressedInstructionData, MintWithContext,
};
use solana_account_info::AccountInfo;
use solana_cpi::{invoke, invoke_signed};
use solana_instruction::Instruction;
use solana_program_error::ProgramError;
use solana_pubkey::Pubkey;
use crate::{
constants::{config_pda, rent_sponsor_pda},
instruction::SystemAccountInfos,
};
#[derive(Debug, Clone)]
pub struct DecompressMint {
pub payer: Pubkey,
pub authority: Pubkey,
pub state_tree: Pubkey,
pub input_queue: Pubkey,
pub output_queue: Pubkey,
pub compressed_mint_with_context: MintWithContext,
pub proof: ValidityProof,
pub rent_payment: u8,
pub write_top_up: u32,
}
impl DecompressMint {
pub fn instruction(self) -> Result<Instruction, ProgramError> {
let mint_data = self
.compressed_mint_with_context
.mint
.as_ref()
.ok_or(ProgramError::InvalidInstructionData)?;
let mint_pda = Pubkey::from(mint_data.metadata.mint.to_bytes());
let action = DecompressMintAction {
rent_payment: self.rent_payment,
write_top_up: self.write_top_up,
};
let instruction_data = MintActionCompressedInstructionData::new(
self.compressed_mint_with_context,
self.proof.0,
)
.with_decompress_mint(action);
let meta_config = MintActionMetaConfig::new(
self.payer,
self.authority,
self.state_tree,
self.input_queue,
self.output_queue,
)
.with_compressible_mint(mint_pda, config_pda(), rent_sponsor_pda());
let account_metas = meta_config.to_account_metas();
let data = instruction_data
.data()
.map_err(|e| ProgramError::BorshIoError(e.to_string()))?;
Ok(Instruction {
program_id: Pubkey::new_from_array(light_token_interface::LIGHT_TOKEN_PROGRAM_ID),
accounts: account_metas,
data,
})
}
}
pub struct DecompressMintCpi<'info> {
pub authority: AccountInfo<'info>,
pub payer: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
pub compressible_config: AccountInfo<'info>,
pub rent_sponsor: AccountInfo<'info>,
pub state_tree: AccountInfo<'info>,
pub input_queue: AccountInfo<'info>,
pub output_queue: AccountInfo<'info>,
pub system_accounts: SystemAccountInfos<'info>,
pub compressed_mint_with_context: MintWithContext,
pub proof: ValidityProof,
pub rent_payment: u8,
pub write_top_up: u32,
}
impl<'info> DecompressMintCpi<'info> {
pub fn instruction(&self) -> Result<Instruction, ProgramError> {
DecompressMint::try_from(self)?.instruction()
}
pub fn invoke(self) -> Result<(), ProgramError> {
let instruction = self.instruction()?;
let account_infos = self.build_account_infos();
invoke(&instruction, &account_infos)
}
pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> {
let instruction = self.instruction()?;
let account_infos = self.build_account_infos();
invoke_signed(&instruction, &account_infos, signer_seeds)
}
fn build_account_infos(&self) -> Vec<AccountInfo<'info>> {
vec![
self.system_accounts.light_system_program.clone(),
self.authority.clone(),
self.compressible_config.clone(),
self.mint.clone(),
self.rent_sponsor.clone(),
self.payer.clone(),
self.system_accounts.cpi_authority_pda.clone(),
self.system_accounts.registered_program_pda.clone(),
self.system_accounts.account_compression_authority.clone(),
self.system_accounts.account_compression_program.clone(),
self.system_accounts.system_program.clone(),
self.output_queue.clone(),
self.state_tree.clone(),
self.input_queue.clone(),
]
}
}
impl<'info> TryFrom<&DecompressMintCpi<'info>> for DecompressMint {
type Error = ProgramError;
fn try_from(cpi: &DecompressMintCpi<'info>) -> Result<Self, Self::Error> {
Ok(Self {
payer: *cpi.payer.key,
authority: *cpi.authority.key,
state_tree: *cpi.state_tree.key,
input_queue: *cpi.input_queue.key,
output_queue: *cpi.output_queue.key,
compressed_mint_with_context: cpi.compressed_mint_with_context.clone(),
proof: cpi.proof,
rent_payment: cpi.rent_payment,
write_top_up: cpi.write_top_up,
})
}
}
#[derive(Debug, Clone)]
pub struct DecompressCMintWithCpiContext {
pub mint_seed_pubkey: Pubkey,
pub payer: Pubkey,
pub authority: Pubkey,
pub state_tree: Pubkey,
pub input_queue: Pubkey,
pub output_queue: Pubkey,
pub compressed_mint_with_context: MintWithContext,
pub proof: ValidityProof,
pub rent_payment: u8,
pub write_top_up: u32,
pub cpi_context_pubkey: Pubkey,
pub cpi_context: CpiContext,
pub compressible_config: Pubkey,
pub rent_sponsor: Pubkey,
}
impl DecompressCMintWithCpiContext {
pub fn instruction(self) -> Result<Instruction, ProgramError> {
let (mint_pda, _cmint_bump) = crate::instruction::find_mint_address(&self.mint_seed_pubkey);
let action = DecompressMintAction {
rent_payment: self.rent_payment,
write_top_up: self.write_top_up,
};
let instruction_data = MintActionCompressedInstructionData::new(
self.compressed_mint_with_context,
self.proof.0,
)
.with_decompress_mint(action)
.with_cpi_context(self.cpi_context.clone());
let mut meta_config = MintActionMetaConfig::new(
self.payer,
self.authority,
self.state_tree,
self.input_queue,
self.output_queue,
)
.with_compressible_mint(mint_pda, self.compressible_config, self.rent_sponsor);
meta_config.cpi_context = Some(self.cpi_context_pubkey);
let account_metas = meta_config.to_account_metas();
let data = instruction_data
.data()
.map_err(|e| ProgramError::BorshIoError(e.to_string()))?;
Ok(Instruction {
program_id: Pubkey::new_from_array(light_token_interface::LIGHT_TOKEN_PROGRAM_ID),
accounts: account_metas,
data,
})
}
}
pub struct DecompressCMintCpiWithContext<'info> {
pub mint_seed: AccountInfo<'info>,
pub authority: AccountInfo<'info>,
pub payer: AccountInfo<'info>,
pub mint: AccountInfo<'info>,
pub compressible_config: AccountInfo<'info>,
pub rent_sponsor: AccountInfo<'info>,
pub state_tree: AccountInfo<'info>,
pub input_queue: AccountInfo<'info>,
pub output_queue: AccountInfo<'info>,
pub cpi_context_account: AccountInfo<'info>,
pub system_accounts: SystemAccountInfos<'info>,
pub light_token_cpi_authority: AccountInfo<'info>,
pub compressed_mint_with_context: MintWithContext,
pub proof: ValidityProof,
pub rent_payment: u8,
pub write_top_up: u32,
pub cpi_context: CpiContext,
}
impl<'info> DecompressCMintCpiWithContext<'info> {
pub fn instruction(&self) -> Result<Instruction, ProgramError> {
DecompressCMintWithCpiContext {
mint_seed_pubkey: *self.mint_seed.key,
payer: *self.payer.key,
authority: *self.authority.key,
state_tree: *self.state_tree.key,
input_queue: *self.input_queue.key,
output_queue: *self.output_queue.key,
compressed_mint_with_context: self.compressed_mint_with_context.clone(),
proof: self.proof,
rent_payment: self.rent_payment,
write_top_up: self.write_top_up,
cpi_context_pubkey: *self.cpi_context_account.key,
cpi_context: self.cpi_context.clone(),
compressible_config: *self.compressible_config.key,
rent_sponsor: *self.rent_sponsor.key,
}
.instruction()
}
pub fn invoke(self) -> Result<(), ProgramError> {
let instruction = self.instruction()?;
let account_infos = self.build_account_infos();
invoke(&instruction, &account_infos)
}
pub fn invoke_signed(self, signer_seeds: &[&[&[u8]]]) -> Result<(), ProgramError> {
let instruction = self.instruction()?;
let account_infos = self.build_account_infos();
invoke_signed(&instruction, &account_infos, signer_seeds)
}
fn build_account_infos(&self) -> Vec<AccountInfo<'info>> {
vec![
self.system_accounts.light_system_program.clone(),
self.mint_seed.clone(),
self.authority.clone(),
self.compressible_config.clone(),
self.mint.clone(),
self.rent_sponsor.clone(),
self.payer.clone(),
self.light_token_cpi_authority.clone(),
self.system_accounts.registered_program_pda.clone(),
self.system_accounts.account_compression_authority.clone(),
self.system_accounts.account_compression_program.clone(),
self.system_accounts.system_program.clone(),
self.cpi_context_account.clone(),
self.output_queue.clone(),
self.state_tree.clone(),
self.input_queue.clone(),
]
}
}
pub fn create_decompress_mint_cpi_context_first(
address_tree_pubkey: [u8; 32],
tree_index: u8,
queue_index: u8,
) -> CpiContext {
CpiContext {
first_set_context: true,
set_context: false,
in_tree_index: tree_index,
in_queue_index: queue_index,
out_queue_index: queue_index,
token_out_queue_index: 0,
assigned_account_index: 0,
read_only_address_trees: [0; 4],
address_tree_pubkey,
}
}
pub fn create_decompress_mint_cpi_context_set(
address_tree_pubkey: [u8; 32],
tree_index: u8,
queue_index: u8,
) -> CpiContext {
CpiContext {
first_set_context: false,
set_context: true,
in_tree_index: tree_index,
in_queue_index: queue_index,
out_queue_index: queue_index,
token_out_queue_index: 0,
assigned_account_index: 0,
read_only_address_trees: [0; 4],
address_tree_pubkey,
}
}
pub fn create_decompress_mint_cpi_context_execute(
address_tree_pubkey: [u8; 32],
tree_index: u8,
queue_index: u8,
) -> CpiContext {
CpiContext {
first_set_context: false,
set_context: false,
in_tree_index: tree_index,
in_queue_index: queue_index,
out_queue_index: queue_index,
token_out_queue_index: 0,
assigned_account_index: 0,
read_only_address_trees: [0; 4],
address_tree_pubkey,
}
}