light_token/compressed_token/v2/create_compressed_mint/
instruction.rs1use light_compressed_account::instruction_data::{
2 compressed_proof::CompressedProof, traits::LightInstructionData,
3};
4use light_token_interface::{
5 self,
6 instructions::{
7 extensions::ExtensionInstructionData,
8 mint_action::{CpiContext, MintInstructionData},
9 },
10 COMPRESSED_MINT_SEED,
11};
12use solana_instruction::Instruction;
13use solana_msg::msg;
14use solana_pubkey::Pubkey;
15
16use crate::{
17 compressed_token::mint_action::{
18 get_mint_action_instruction_account_metas_cpi_write, MintActionMetaConfig,
19 MintActionMetaConfigCpiWrite,
20 },
21 error::{Result, TokenSdkError},
22 AnchorDeserialize, AnchorSerialize,
23};
24
25#[derive(Debug, Clone, AnchorDeserialize, AnchorSerialize)]
27pub struct CreateMintInputs {
28 pub decimals: u8,
29 pub mint_authority: Pubkey,
30 pub freeze_authority: Option<Pubkey>,
31 pub proof: CompressedProof,
32 pub address_merkle_tree_root_index: u16,
33 pub mint_signer: Pubkey,
34 pub payer: Pubkey,
35 pub address_tree_pubkey: Pubkey,
36 pub output_queue: Pubkey,
37 pub extensions: Option<Vec<ExtensionInstructionData>>,
38 pub version: u8,
39}
40
41pub fn create_compressed_mint_cpi(
43 input: CreateMintInputs,
44 cpi_context: Option<CpiContext>,
45 cpi_context_pubkey: Option<Pubkey>,
46) -> Result<Instruction> {
47 let (mint_pda, bump) = find_mint_address(&input.mint_signer);
48 let compressed_mint_instruction_data = MintInstructionData {
49 supply: 0,
50 decimals: input.decimals,
51 metadata: light_token_interface::state::MintMetadata {
52 version: input.version,
53 mint: mint_pda.to_bytes().into(),
54 mint_decompressed: false,
55 mint_signer: input.mint_signer.to_bytes(),
56 bump,
57 },
58 mint_authority: Some(input.mint_authority.to_bytes().into()),
59 freeze_authority: input.freeze_authority.map(|auth| auth.to_bytes().into()),
60 extensions: input.extensions,
61 };
62
63 let mut instruction_data = light_token_interface::instructions::mint_action::MintActionCompressedInstructionData::new_mint(
64 input.address_merkle_tree_root_index,
65 input.proof,
66 compressed_mint_instruction_data,
67 );
68
69 if let Some(ctx) = cpi_context {
70 instruction_data = instruction_data.with_cpi_context(ctx);
71 }
72
73 let meta_config = if cpi_context_pubkey.is_some() {
74 MintActionMetaConfig::new_cpi_context(
75 &instruction_data,
76 input.payer,
77 input.mint_authority,
78 cpi_context_pubkey.unwrap(),
79 )?
80 } else {
81 MintActionMetaConfig::new_create_mint(
82 input.payer,
83 input.mint_authority,
84 input.mint_signer,
85 input.address_tree_pubkey,
86 input.output_queue,
87 )
88 };
89
90 let account_metas = meta_config.to_account_metas();
91
92 let data = instruction_data
93 .data()
94 .map_err(|_| TokenSdkError::SerializationError)?;
95
96 Ok(Instruction {
97 program_id: solana_pubkey::Pubkey::new_from_array(
98 light_token_interface::LIGHT_TOKEN_PROGRAM_ID,
99 ),
100 accounts: account_metas,
101 data,
102 })
103}
104
105#[derive(Debug, Clone, AnchorDeserialize, AnchorSerialize)]
106pub struct CreateMintInputsCpiWrite {
107 pub decimals: u8,
108 pub mint_authority: Pubkey,
109 pub freeze_authority: Option<Pubkey>,
110 pub address_merkle_tree_root_index: u16,
111 pub mint_signer: Pubkey,
112 pub payer: Pubkey,
113 pub mint_address: [u8; 32],
114 pub cpi_context: CpiContext,
115 pub cpi_context_pubkey: Pubkey,
116 pub extensions: Option<Vec<ExtensionInstructionData>>,
117 pub version: u8,
118}
119
120pub fn create_compressed_mint_cpi_write(input: CreateMintInputsCpiWrite) -> Result<Instruction> {
121 if !input.cpi_context.first_set_context && !input.cpi_context.set_context {
122 msg!(
123 "Invalid CPI context first cpi set or set context must be true {:?}",
124 input.cpi_context
125 );
126 return Err(TokenSdkError::InvalidAccountData);
127 }
128
129 let (mint_pda, bump) = find_mint_address(&input.mint_signer);
130 let compressed_mint_instruction_data = MintInstructionData {
131 supply: 0,
132 decimals: input.decimals,
133 metadata: light_token_interface::state::MintMetadata {
134 version: input.version,
135 mint: mint_pda.to_bytes().into(),
136 mint_decompressed: false,
137 mint_signer: input.mint_signer.to_bytes(),
138 bump,
139 },
140 mint_authority: Some(input.mint_authority.to_bytes().into()),
141 freeze_authority: input.freeze_authority.map(|auth| auth.to_bytes().into()),
142 extensions: input.extensions,
143 };
144
145 let instruction_data = light_token_interface::instructions::mint_action::MintActionCompressedInstructionData::new_mint_write_to_cpi_context(
146 input.address_merkle_tree_root_index,
147 compressed_mint_instruction_data,
148 input.cpi_context,
149 );
150
151 let meta_config = MintActionMetaConfigCpiWrite {
152 fee_payer: input.payer,
153 mint_signer: Some(input.mint_signer),
154 authority: input.mint_authority,
155 cpi_context: input.cpi_context_pubkey,
156 };
157
158 let account_metas = get_mint_action_instruction_account_metas_cpi_write(meta_config);
159
160 let data = instruction_data
161 .data()
162 .map_err(|_| TokenSdkError::SerializationError)?;
163
164 Ok(Instruction {
165 program_id: solana_pubkey::Pubkey::new_from_array(
166 light_token_interface::LIGHT_TOKEN_PROGRAM_ID,
167 ),
168 accounts: account_metas,
169 data,
170 })
171}
172
173pub fn create_compressed_mint(input: CreateMintInputs) -> Result<Instruction> {
175 create_compressed_mint_cpi(input, None, None)
176}
177
178pub fn derive_mint_compressed_address(
180 mint_seed: &Pubkey,
181 address_tree_pubkey: &Pubkey,
182) -> [u8; 32] {
183 light_compressed_account::address::derive_address(
184 &find_mint_address(mint_seed).0.to_bytes(),
185 &address_tree_pubkey.to_bytes(),
186 &light_token_interface::LIGHT_TOKEN_PROGRAM_ID,
187 )
188}
189
190pub fn derive_mint_from_spl_mint(mint: &Pubkey, address_tree_pubkey: &Pubkey) -> [u8; 32] {
191 light_compressed_account::address::derive_address(
192 &mint.to_bytes(),
193 &address_tree_pubkey.to_bytes(),
194 &light_token_interface::LIGHT_TOKEN_PROGRAM_ID,
195 )
196}
197
198pub fn find_mint_address(mint_seed: &Pubkey) -> (Pubkey, u8) {
199 Pubkey::find_program_address(
200 &[COMPRESSED_MINT_SEED, mint_seed.as_ref()],
201 &Pubkey::new_from_array(light_token_interface::LIGHT_TOKEN_PROGRAM_ID),
202 )
203}