light_token/compressed_token/v2/update_compressed_mint/
instruction.rs

1use light_compressed_account::instruction_data::{
2    compressed_proof::CompressedProof, traits::LightInstructionData,
3};
4use light_token_interface::{
5    self,
6    instructions::mint_action::{CpiContext, MintWithContext},
7};
8use light_token_types::MintAuthorityType;
9use solana_instruction::Instruction;
10use solana_pubkey::Pubkey;
11
12use crate::{
13    compressed_token::mint_action::{
14        get_mint_action_instruction_account_metas_cpi_write, MintActionMetaConfig,
15        MintActionMetaConfigCpiWrite,
16    },
17    error::{Result, TokenSdkError},
18    AnchorDeserialize, AnchorSerialize,
19};
20
21pub const UPDATE_COMPRESSED_MINT_DISCRIMINATOR: u8 = 105;
22
23/// Input struct for updating a compressed mint instruction
24#[derive(Debug, Clone, AnchorDeserialize, AnchorSerialize)]
25pub struct UpdateMintInputs {
26    pub compressed_mint_inputs: MintWithContext,
27    pub authority_type: MintAuthorityType,
28    pub new_authority: Option<Pubkey>,
29    pub mint_authority: Option<Pubkey>, // Current mint authority (needed when updating freeze authority)
30    pub proof: Option<CompressedProof>,
31    pub payer: Pubkey,
32    pub authority: Pubkey,
33    pub in_merkle_tree: Pubkey,
34    pub in_output_queue: Pubkey,
35    pub out_output_queue: Pubkey,
36}
37
38/// Creates an update compressed mint instruction with CPI context support (now uses mint_action)
39pub fn update_compressed_mint_cpi(
40    input: UpdateMintInputs,
41    cpi_context: Option<CpiContext>,
42) -> Result<Instruction> {
43    let mut instruction_data =
44        light_token_interface::instructions::mint_action::MintActionCompressedInstructionData::new(
45            input.compressed_mint_inputs.clone(),
46            input.proof,
47        );
48
49    let update_authority = light_token_interface::instructions::mint_action::UpdateAuthority {
50        new_authority: input.new_authority.map(|auth| auth.to_bytes().into()),
51    };
52
53    instruction_data = match input.authority_type {
54        MintAuthorityType::MintTokens => {
55            instruction_data.with_update_mint_authority(update_authority)
56        }
57        MintAuthorityType::FreezeAccount => {
58            instruction_data.with_update_freeze_authority(update_authority)
59        }
60    };
61
62    if let Some(ctx) = cpi_context {
63        instruction_data = instruction_data.with_cpi_context(ctx);
64    }
65
66    let meta_config = MintActionMetaConfig::new(
67        input.payer,
68        input.authority,
69        input.in_merkle_tree,
70        input.in_output_queue,
71        input.out_output_queue,
72    );
73
74    let account_metas = meta_config.to_account_metas();
75
76    let data = instruction_data
77        .data()
78        .map_err(|_| TokenSdkError::SerializationError)?;
79
80    Ok(Instruction {
81        program_id: solana_pubkey::Pubkey::new_from_array(
82            light_token_interface::LIGHT_TOKEN_PROGRAM_ID,
83        ),
84        accounts: account_metas,
85        data,
86    })
87}
88
89/// Creates an update compressed mint instruction without CPI context
90pub fn update_compressed_mint(input: UpdateMintInputs) -> Result<Instruction> {
91    update_compressed_mint_cpi(input, None)
92}
93
94/// Input struct for creating an update compressed mint instruction with CPI context write
95#[derive(Debug, Clone)]
96pub struct UpdateMintInputsCpiWrite {
97    pub compressed_mint_inputs: MintWithContext,
98    pub authority_type: MintAuthorityType,
99    pub new_authority: Option<Pubkey>,
100    pub payer: Pubkey,
101    pub authority: Pubkey,
102    pub cpi_context: CpiContext,
103    pub cpi_context_pubkey: Pubkey,
104}
105
106/// Creates an update compressed mint instruction for CPI context writes (now uses mint_action)
107pub fn create_update_compressed_mint_cpi_write(
108    inputs: UpdateMintInputsCpiWrite,
109) -> Result<Instruction> {
110    if !inputs.cpi_context.first_set_context && !inputs.cpi_context.set_context {
111        return Err(TokenSdkError::InvalidCpiContext);
112    }
113
114    let mut instruction_data =
115        light_token_interface::instructions::mint_action::MintActionCompressedInstructionData::new(
116            inputs.compressed_mint_inputs.clone(),
117            None, // No proof for CPI write
118        );
119
120    let update_authority = light_token_interface::instructions::mint_action::UpdateAuthority {
121        new_authority: inputs.new_authority.map(|auth| auth.to_bytes().into()),
122    };
123
124    instruction_data = match inputs.authority_type {
125        MintAuthorityType::MintTokens => {
126            instruction_data.with_update_mint_authority(update_authority)
127        }
128        MintAuthorityType::FreezeAccount => {
129            instruction_data.with_update_freeze_authority(update_authority)
130        }
131    };
132
133    instruction_data = instruction_data.with_cpi_context(inputs.cpi_context);
134
135    let meta_config = MintActionMetaConfigCpiWrite {
136        fee_payer: inputs.payer,
137        mint_signer: None, // Not needed for authority updates
138        authority: inputs.authority,
139        cpi_context: inputs.cpi_context_pubkey,
140    };
141
142    let account_metas = get_mint_action_instruction_account_metas_cpi_write(meta_config);
143
144    let data = instruction_data
145        .data()
146        .map_err(|_| TokenSdkError::SerializationError)?;
147
148    Ok(Instruction {
149        program_id: solana_pubkey::Pubkey::new_from_array(
150            light_token_interface::LIGHT_TOKEN_PROGRAM_ID,
151        ),
152        accounts: account_metas,
153        data,
154    })
155}