1use crate::generated::types::CollectionDetails;
9use crate::generated::types::DataV2;
10use borsh::BorshDeserialize;
11use borsh::BorshSerialize;
12
13pub struct CreateMetadataAccountV3 {
15 pub metadata: solana_program::pubkey::Pubkey,
17 pub mint: solana_program::pubkey::Pubkey,
19 pub mint_authority: solana_program::pubkey::Pubkey,
21 pub payer: solana_program::pubkey::Pubkey,
23 pub update_authority: (solana_program::pubkey::Pubkey, bool),
25 pub system_program: solana_program::pubkey::Pubkey,
27 pub rent: Option<solana_program::pubkey::Pubkey>,
29}
30
31impl CreateMetadataAccountV3 {
32 pub fn instruction(
33 &self,
34 args: CreateMetadataAccountV3InstructionArgs,
35 ) -> solana_program::instruction::Instruction {
36 self.instruction_with_remaining_accounts(args, &[])
37 }
38 #[allow(clippy::vec_init_then_push)]
39 pub fn instruction_with_remaining_accounts(
40 &self,
41 args: CreateMetadataAccountV3InstructionArgs,
42 remaining_accounts: &[solana_program::instruction::AccountMeta],
43 ) -> solana_program::instruction::Instruction {
44 let mut accounts = Vec::with_capacity(7 + remaining_accounts.len());
45 accounts.push(solana_program::instruction::AccountMeta::new(
46 self.metadata,
47 false,
48 ));
49 accounts.push(solana_program::instruction::AccountMeta::new_readonly(
50 self.mint, false,
51 ));
52 accounts.push(solana_program::instruction::AccountMeta::new_readonly(
53 self.mint_authority,
54 true,
55 ));
56 accounts.push(solana_program::instruction::AccountMeta::new(
57 self.payer, true,
58 ));
59 accounts.push(solana_program::instruction::AccountMeta::new_readonly(
60 self.update_authority.0,
61 self.update_authority.1,
62 ));
63 accounts.push(solana_program::instruction::AccountMeta::new_readonly(
64 self.system_program,
65 false,
66 ));
67 if let Some(rent) = self.rent {
68 accounts.push(solana_program::instruction::AccountMeta::new_readonly(
69 rent, false,
70 ));
71 }
72 accounts.extend_from_slice(remaining_accounts);
73 let mut data = CreateMetadataAccountV3InstructionData::new()
74 .try_to_vec()
75 .unwrap();
76 let mut args = args.try_to_vec().unwrap();
77 data.append(&mut args);
78
79 solana_program::instruction::Instruction {
80 program_id: crate::MPL_TOKEN_METADATA_ID,
81 accounts,
82 data,
83 }
84 }
85}
86
87#[derive(BorshDeserialize, BorshSerialize)]
88struct CreateMetadataAccountV3InstructionData {
89 discriminator: u8,
90}
91
92impl CreateMetadataAccountV3InstructionData {
93 fn new() -> Self {
94 Self { discriminator: 33 }
95 }
96}
97
98#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)]
99#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
100pub struct CreateMetadataAccountV3InstructionArgs {
101 pub data: DataV2,
102 pub is_mutable: bool,
103 pub collection_details: Option<CollectionDetails>,
104}
105
106#[derive(Default)]
118pub struct CreateMetadataAccountV3Builder {
119 metadata: Option<solana_program::pubkey::Pubkey>,
120 mint: Option<solana_program::pubkey::Pubkey>,
121 mint_authority: Option<solana_program::pubkey::Pubkey>,
122 payer: Option<solana_program::pubkey::Pubkey>,
123 update_authority: Option<(solana_program::pubkey::Pubkey, bool)>,
124 system_program: Option<solana_program::pubkey::Pubkey>,
125 rent: Option<solana_program::pubkey::Pubkey>,
126 data: Option<DataV2>,
127 is_mutable: Option<bool>,
128 collection_details: Option<CollectionDetails>,
129 __remaining_accounts: Vec<solana_program::instruction::AccountMeta>,
130}
131
132impl CreateMetadataAccountV3Builder {
133 pub fn new() -> Self {
134 Self::default()
135 }
136 #[inline(always)]
138 pub fn metadata(&mut self, metadata: solana_program::pubkey::Pubkey) -> &mut Self {
139 self.metadata = Some(metadata);
140 self
141 }
142 #[inline(always)]
144 pub fn mint(&mut self, mint: solana_program::pubkey::Pubkey) -> &mut Self {
145 self.mint = Some(mint);
146 self
147 }
148 #[inline(always)]
150 pub fn mint_authority(&mut self, mint_authority: solana_program::pubkey::Pubkey) -> &mut Self {
151 self.mint_authority = Some(mint_authority);
152 self
153 }
154 #[inline(always)]
156 pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self {
157 self.payer = Some(payer);
158 self
159 }
160 #[inline(always)]
162 pub fn update_authority(
163 &mut self,
164 update_authority: solana_program::pubkey::Pubkey,
165 as_signer: bool,
166 ) -> &mut Self {
167 self.update_authority = Some((update_authority, as_signer));
168 self
169 }
170 #[inline(always)]
173 pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self {
174 self.system_program = Some(system_program);
175 self
176 }
177 #[inline(always)]
180 pub fn rent(&mut self, rent: Option<solana_program::pubkey::Pubkey>) -> &mut Self {
181 self.rent = rent;
182 self
183 }
184 #[inline(always)]
185 pub fn data(&mut self, data: DataV2) -> &mut Self {
186 self.data = Some(data);
187 self
188 }
189 #[inline(always)]
190 pub fn is_mutable(&mut self, is_mutable: bool) -> &mut Self {
191 self.is_mutable = Some(is_mutable);
192 self
193 }
194 #[inline(always)]
196 pub fn collection_details(&mut self, collection_details: CollectionDetails) -> &mut Self {
197 self.collection_details = Some(collection_details);
198 self
199 }
200 #[inline(always)]
202 pub fn add_remaining_account(
203 &mut self,
204 account: solana_program::instruction::AccountMeta,
205 ) -> &mut Self {
206 self.__remaining_accounts.push(account);
207 self
208 }
209 #[inline(always)]
211 pub fn add_remaining_accounts(
212 &mut self,
213 accounts: &[solana_program::instruction::AccountMeta],
214 ) -> &mut Self {
215 self.__remaining_accounts.extend_from_slice(accounts);
216 self
217 }
218 #[allow(clippy::clone_on_copy)]
219 pub fn instruction(&self) -> solana_program::instruction::Instruction {
220 let accounts = CreateMetadataAccountV3 {
221 metadata: self.metadata.expect("metadata is not set"),
222 mint: self.mint.expect("mint is not set"),
223 mint_authority: self.mint_authority.expect("mint_authority is not set"),
224 payer: self.payer.expect("payer is not set"),
225 update_authority: self.update_authority.expect("update_authority is not set"),
226 system_program: self
227 .system_program
228 .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")),
229 rent: self.rent,
230 };
231 let args = CreateMetadataAccountV3InstructionArgs {
232 data: self.data.clone().expect("data is not set"),
233 is_mutable: self.is_mutable.clone().expect("is_mutable is not set"),
234 collection_details: self.collection_details.clone(),
235 };
236
237 accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts)
238 }
239}
240
241pub struct CreateMetadataAccountV3CpiAccounts<'a, 'b> {
243 pub metadata: &'b solana_program::account_info::AccountInfo<'a>,
245 pub mint: &'b solana_program::account_info::AccountInfo<'a>,
247 pub mint_authority: &'b solana_program::account_info::AccountInfo<'a>,
249 pub payer: &'b solana_program::account_info::AccountInfo<'a>,
251 pub update_authority: (&'b solana_program::account_info::AccountInfo<'a>, bool),
253 pub system_program: &'b solana_program::account_info::AccountInfo<'a>,
255 pub rent: Option<&'b solana_program::account_info::AccountInfo<'a>>,
257}
258
259pub struct CreateMetadataAccountV3Cpi<'a, 'b> {
261 pub __program: &'b solana_program::account_info::AccountInfo<'a>,
263 pub metadata: &'b solana_program::account_info::AccountInfo<'a>,
265 pub mint: &'b solana_program::account_info::AccountInfo<'a>,
267 pub mint_authority: &'b solana_program::account_info::AccountInfo<'a>,
269 pub payer: &'b solana_program::account_info::AccountInfo<'a>,
271 pub update_authority: (&'b solana_program::account_info::AccountInfo<'a>, bool),
273 pub system_program: &'b solana_program::account_info::AccountInfo<'a>,
275 pub rent: Option<&'b solana_program::account_info::AccountInfo<'a>>,
277 pub __args: CreateMetadataAccountV3InstructionArgs,
279}
280
281impl<'a, 'b> CreateMetadataAccountV3Cpi<'a, 'b> {
282 pub fn new(
283 program: &'b solana_program::account_info::AccountInfo<'a>,
284 accounts: CreateMetadataAccountV3CpiAccounts<'a, 'b>,
285 args: CreateMetadataAccountV3InstructionArgs,
286 ) -> Self {
287 Self {
288 __program: program,
289 metadata: accounts.metadata,
290 mint: accounts.mint,
291 mint_authority: accounts.mint_authority,
292 payer: accounts.payer,
293 update_authority: accounts.update_authority,
294 system_program: accounts.system_program,
295 rent: accounts.rent,
296 __args: args,
297 }
298 }
299 #[inline(always)]
300 pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult {
301 self.invoke_signed_with_remaining_accounts(&[], &[])
302 }
303 #[inline(always)]
304 pub fn invoke_with_remaining_accounts(
305 &self,
306 remaining_accounts: &[(
307 &'b solana_program::account_info::AccountInfo<'a>,
308 bool,
309 bool,
310 )],
311 ) -> solana_program::entrypoint::ProgramResult {
312 self.invoke_signed_with_remaining_accounts(&[], remaining_accounts)
313 }
314 #[inline(always)]
315 pub fn invoke_signed(
316 &self,
317 signers_seeds: &[&[&[u8]]],
318 ) -> solana_program::entrypoint::ProgramResult {
319 self.invoke_signed_with_remaining_accounts(signers_seeds, &[])
320 }
321 #[allow(clippy::clone_on_copy)]
322 #[allow(clippy::vec_init_then_push)]
323 pub fn invoke_signed_with_remaining_accounts(
324 &self,
325 signers_seeds: &[&[&[u8]]],
326 remaining_accounts: &[(
327 &'b solana_program::account_info::AccountInfo<'a>,
328 bool,
329 bool,
330 )],
331 ) -> solana_program::entrypoint::ProgramResult {
332 let mut accounts = Vec::with_capacity(7 + remaining_accounts.len());
333 accounts.push(solana_program::instruction::AccountMeta::new(
334 *self.metadata.key,
335 false,
336 ));
337 accounts.push(solana_program::instruction::AccountMeta::new_readonly(
338 *self.mint.key,
339 false,
340 ));
341 accounts.push(solana_program::instruction::AccountMeta::new_readonly(
342 *self.mint_authority.key,
343 true,
344 ));
345 accounts.push(solana_program::instruction::AccountMeta::new(
346 *self.payer.key,
347 true,
348 ));
349 accounts.push(solana_program::instruction::AccountMeta::new_readonly(
350 *self.update_authority.0.key,
351 self.update_authority.1,
352 ));
353 accounts.push(solana_program::instruction::AccountMeta::new_readonly(
354 *self.system_program.key,
355 false,
356 ));
357 if let Some(rent) = self.rent {
358 accounts.push(solana_program::instruction::AccountMeta::new_readonly(
359 *rent.key, false,
360 ));
361 }
362 remaining_accounts.iter().for_each(|remaining_account| {
363 accounts.push(solana_program::instruction::AccountMeta {
364 pubkey: *remaining_account.0.key,
365 is_signer: remaining_account.1,
366 is_writable: remaining_account.2,
367 })
368 });
369 let mut data = CreateMetadataAccountV3InstructionData::new()
370 .try_to_vec()
371 .unwrap();
372 let mut args = self.__args.try_to_vec().unwrap();
373 data.append(&mut args);
374
375 let instruction = solana_program::instruction::Instruction {
376 program_id: crate::MPL_TOKEN_METADATA_ID,
377 accounts,
378 data,
379 };
380 let mut account_infos = Vec::with_capacity(7 + 1 + remaining_accounts.len());
381 account_infos.push(self.__program.clone());
382 account_infos.push(self.metadata.clone());
383 account_infos.push(self.mint.clone());
384 account_infos.push(self.mint_authority.clone());
385 account_infos.push(self.payer.clone());
386 account_infos.push(self.update_authority.0.clone());
387 account_infos.push(self.system_program.clone());
388 if let Some(rent) = self.rent {
389 account_infos.push(rent.clone());
390 }
391 remaining_accounts
392 .iter()
393 .for_each(|remaining_account| account_infos.push(remaining_account.0.clone()));
394
395 if signers_seeds.is_empty() {
396 solana_program::program::invoke(&instruction, &account_infos)
397 } else {
398 solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds)
399 }
400 }
401}
402
403pub struct CreateMetadataAccountV3CpiBuilder<'a, 'b> {
415 instruction: Box<CreateMetadataAccountV3CpiBuilderInstruction<'a, 'b>>,
416}
417
418impl<'a, 'b> CreateMetadataAccountV3CpiBuilder<'a, 'b> {
419 pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self {
420 let instruction = Box::new(CreateMetadataAccountV3CpiBuilderInstruction {
421 __program: program,
422 metadata: None,
423 mint: None,
424 mint_authority: None,
425 payer: None,
426 update_authority: None,
427 system_program: None,
428 rent: None,
429 data: None,
430 is_mutable: None,
431 collection_details: None,
432 __remaining_accounts: Vec::new(),
433 });
434 Self { instruction }
435 }
436 #[inline(always)]
438 pub fn metadata(
439 &mut self,
440 metadata: &'b solana_program::account_info::AccountInfo<'a>,
441 ) -> &mut Self {
442 self.instruction.metadata = Some(metadata);
443 self
444 }
445 #[inline(always)]
447 pub fn mint(&mut self, mint: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self {
448 self.instruction.mint = Some(mint);
449 self
450 }
451 #[inline(always)]
453 pub fn mint_authority(
454 &mut self,
455 mint_authority: &'b solana_program::account_info::AccountInfo<'a>,
456 ) -> &mut Self {
457 self.instruction.mint_authority = Some(mint_authority);
458 self
459 }
460 #[inline(always)]
462 pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self {
463 self.instruction.payer = Some(payer);
464 self
465 }
466 #[inline(always)]
468 pub fn update_authority(
469 &mut self,
470 update_authority: &'b solana_program::account_info::AccountInfo<'a>,
471 as_signer: bool,
472 ) -> &mut Self {
473 self.instruction.update_authority = Some((update_authority, as_signer));
474 self
475 }
476 #[inline(always)]
478 pub fn system_program(
479 &mut self,
480 system_program: &'b solana_program::account_info::AccountInfo<'a>,
481 ) -> &mut Self {
482 self.instruction.system_program = Some(system_program);
483 self
484 }
485 #[inline(always)]
488 pub fn rent(
489 &mut self,
490 rent: Option<&'b solana_program::account_info::AccountInfo<'a>>,
491 ) -> &mut Self {
492 self.instruction.rent = rent;
493 self
494 }
495 #[inline(always)]
496 pub fn data(&mut self, data: DataV2) -> &mut Self {
497 self.instruction.data = Some(data);
498 self
499 }
500 #[inline(always)]
501 pub fn is_mutable(&mut self, is_mutable: bool) -> &mut Self {
502 self.instruction.is_mutable = Some(is_mutable);
503 self
504 }
505 #[inline(always)]
507 pub fn collection_details(&mut self, collection_details: CollectionDetails) -> &mut Self {
508 self.instruction.collection_details = Some(collection_details);
509 self
510 }
511 #[inline(always)]
513 pub fn add_remaining_account(
514 &mut self,
515 account: &'b solana_program::account_info::AccountInfo<'a>,
516 is_writable: bool,
517 is_signer: bool,
518 ) -> &mut Self {
519 self.instruction
520 .__remaining_accounts
521 .push((account, is_writable, is_signer));
522 self
523 }
524 #[inline(always)]
529 pub fn add_remaining_accounts(
530 &mut self,
531 accounts: &[(
532 &'b solana_program::account_info::AccountInfo<'a>,
533 bool,
534 bool,
535 )],
536 ) -> &mut Self {
537 self.instruction
538 .__remaining_accounts
539 .extend_from_slice(accounts);
540 self
541 }
542 #[inline(always)]
543 pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult {
544 self.invoke_signed(&[])
545 }
546 #[allow(clippy::clone_on_copy)]
547 #[allow(clippy::vec_init_then_push)]
548 pub fn invoke_signed(
549 &self,
550 signers_seeds: &[&[&[u8]]],
551 ) -> solana_program::entrypoint::ProgramResult {
552 let args = CreateMetadataAccountV3InstructionArgs {
553 data: self.instruction.data.clone().expect("data is not set"),
554 is_mutable: self
555 .instruction
556 .is_mutable
557 .clone()
558 .expect("is_mutable is not set"),
559 collection_details: self.instruction.collection_details.clone(),
560 };
561 let instruction = CreateMetadataAccountV3Cpi {
562 __program: self.instruction.__program,
563
564 metadata: self.instruction.metadata.expect("metadata is not set"),
565
566 mint: self.instruction.mint.expect("mint is not set"),
567
568 mint_authority: self
569 .instruction
570 .mint_authority
571 .expect("mint_authority is not set"),
572
573 payer: self.instruction.payer.expect("payer is not set"),
574
575 update_authority: self
576 .instruction
577 .update_authority
578 .expect("update_authority is not set"),
579
580 system_program: self
581 .instruction
582 .system_program
583 .expect("system_program is not set"),
584
585 rent: self.instruction.rent,
586 __args: args,
587 };
588 instruction.invoke_signed_with_remaining_accounts(
589 signers_seeds,
590 &self.instruction.__remaining_accounts,
591 )
592 }
593}
594
595struct CreateMetadataAccountV3CpiBuilderInstruction<'a, 'b> {
596 __program: &'b solana_program::account_info::AccountInfo<'a>,
597 metadata: Option<&'b solana_program::account_info::AccountInfo<'a>>,
598 mint: Option<&'b solana_program::account_info::AccountInfo<'a>>,
599 mint_authority: Option<&'b solana_program::account_info::AccountInfo<'a>>,
600 payer: Option<&'b solana_program::account_info::AccountInfo<'a>>,
601 update_authority: Option<(&'b solana_program::account_info::AccountInfo<'a>, bool)>,
602 system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>,
603 rent: Option<&'b solana_program::account_info::AccountInfo<'a>>,
604 data: Option<DataV2>,
605 is_mutable: Option<bool>,
606 collection_details: Option<CollectionDetails>,
607 __remaining_accounts: Vec<(
609 &'b solana_program::account_info::AccountInfo<'a>,
610 bool,
611 bool,
612 )>,
613}