light_token_client/actions/
create_mint.rs1use light_client::{
6 indexer::{AddressWithTree, Indexer},
7 rpc::{Rpc, RpcError},
8};
9use light_token::instruction::{
10 derive_mint_compressed_address, find_mint_address, CreateMint as CreateMintInstruction,
11 CreateMintParams as CreateMintInstructionParams,
12};
13use light_token_interface::{
14 instructions::extensions::{ExtensionInstructionData, TokenMetadataInstructionData},
15 state::AdditionalMetadata,
16};
17use solana_keypair::Keypair;
18use solana_pubkey::Pubkey;
19use solana_signature::Signature;
20use solana_signer::Signer;
21
22#[derive(Clone, Debug, Default)]
24pub struct TokenMetadata {
25 pub name: String,
27 pub symbol: String,
29 pub uri: String,
31 pub update_authority: Option<Pubkey>,
33 pub additional_metadata: Option<Vec<(String, String)>>,
35}
36
37#[derive(Default, Debug)]
57pub struct CreateMint {
58 pub decimals: u8,
60 pub freeze_authority: Option<Pubkey>,
62 pub token_metadata: Option<TokenMetadata>,
64 pub seed: Option<Keypair>,
67}
68
69impl CreateMint {
70 pub async fn execute<R: Rpc + Indexer>(
80 self,
81 rpc: &mut R,
82 payer: &Keypair,
83 mint_authority: &Keypair,
84 ) -> Result<(Signature, Pubkey), RpcError> {
85 let mint_seed = self.seed.unwrap_or_else(Keypair::new);
86 let address_tree = rpc.get_address_tree_v2();
87 let output_queue = rpc.get_random_state_tree_info()?.queue;
88
89 let compression_address =
91 derive_mint_compressed_address(&mint_seed.pubkey(), &address_tree.tree);
92
93 let (mint, bump) = find_mint_address(&mint_seed.pubkey());
95
96 let rpc_result = rpc
98 .get_validity_proof(
99 vec![],
100 vec![AddressWithTree {
101 address: compression_address,
102 tree: address_tree.tree,
103 }],
104 None,
105 )
106 .await
107 .map_err(|e| RpcError::CustomError(format!("Failed to get validity proof: {}", e)))?
108 .value;
109
110 let extensions = self.token_metadata.map(|metadata| {
112 let additional_metadata = metadata.additional_metadata.map(|items| {
113 items
114 .into_iter()
115 .map(|(key, value)| AdditionalMetadata {
116 key: key.into_bytes(),
117 value: value.into_bytes(),
118 })
119 .collect()
120 });
121
122 vec![ExtensionInstructionData::TokenMetadata(
123 TokenMetadataInstructionData {
124 update_authority: Some(
125 metadata
126 .update_authority
127 .unwrap_or_else(|| mint_authority.pubkey())
128 .to_bytes()
129 .into(),
130 ),
131 name: metadata.name.into_bytes(),
132 symbol: metadata.symbol.into_bytes(),
133 uri: metadata.uri.into_bytes(),
134 additional_metadata,
135 },
136 )]
137 });
138
139 let params = CreateMintInstructionParams {
141 decimals: self.decimals,
142 address_merkle_tree_root_index: rpc_result.addresses[0].root_index,
143 mint_authority: mint_authority.pubkey(),
144 proof: rpc_result.proof.0.ok_or_else(|| {
145 RpcError::CustomError("Validity proof is required for create_mint".to_string())
146 })?,
147 compression_address,
148 mint,
149 bump,
150 freeze_authority: self.freeze_authority,
151 extensions,
152 rent_payment: 16, write_top_up: 766, };
155
156 let instruction = CreateMintInstruction::new(
158 params,
159 mint_seed.pubkey(),
160 payer.pubkey(),
161 address_tree.tree,
162 output_queue,
163 )
164 .instruction()
165 .map_err(|e| RpcError::CustomError(format!("Failed to create instruction: {}", e)))?;
166
167 let mut signers: Vec<&Keypair> = vec![payer, &mint_seed];
169 if mint_authority.pubkey() != payer.pubkey() {
170 signers.push(mint_authority);
171 }
172
173 let signature = rpc
175 .create_and_send_transaction(&[instruction], &payer.pubkey(), &signers)
176 .await?;
177
178 Ok((signature, mint))
179 }
180}