1use crate::{
2 assertions::{
3 collection::{
4 assert_collection_update_is_valid, assert_collection_verify_is_valid,
5 assert_has_collection_authority,
6 },
7 uses::process_use_authority_validation,
8 },
9 deprecated_processor::{
10 process_deprecated_create_metadata_accounts, process_deprecated_update_metadata_accounts,
11 },
12 error::MetadataError,
13 instruction::MetadataInstruction,
14 state::{
15 CollectionAuthorityRecord, DataV2, Key, MasterEditionV1, MasterEditionV2, Metadata,
16 TokenStandard, UseAuthorityRecord, UseMethod, Uses, BURN, COLLECTION_AUTHORITY,
17 COLLECTION_AUTHORITY_RECORD_SIZE, EDITION, MAX_MASTER_EDITION_LEN, PREFIX, USER,
18 USE_AUTHORITY_RECORD_SIZE,
19 },
20 utils::{
21 assert_currently_holding, assert_data_valid, assert_derivation, assert_initialized,
22 assert_mint_authority_matches_mint, assert_owned_by, assert_signer,
23 assert_token_program_matches_package, assert_update_authority_is_correct,
24 create_or_allocate_account_raw, get_owner_from_token_account,
25 process_create_metadata_accounts_logic,
26 process_mint_new_edition_from_master_edition_via_token_logic, puff_out_data_fields,
27 spl_token_burn, transfer_mint_authority, CreateMetadataAccountsLogicArgs,
28 MintNewEditionFromMasterEditionViaTokenLogicArgs, TokenBurnParams,
29 },
30};
31use arrayref::array_ref;
32use borsh::{BorshDeserialize, BorshSerialize};
33use mpl_token_vault::{error::VaultError, state::VaultState};
34use solana_program::{
35 account_info::{next_account_info, AccountInfo},
36 entrypoint::ProgramResult,
37 msg,
38 program::invoke,
39 program_error::ProgramError,
40 pubkey::Pubkey,
41};
42use spl_token::{
43 instruction::{approve, revoke},
44 state::{Account, Mint},
45};
46
47pub fn process_instruction<'a>(
48 program_id: &'a Pubkey,
49 accounts: &'a [AccountInfo<'a>],
50 input: &[u8],
51) -> ProgramResult {
52 let instruction = MetadataInstruction::try_from_slice(input)?;
53 match instruction {
54 MetadataInstruction::CreateMetadataAccount(args) => {
55 msg!("(Deprecated as of 1.1.0) Instruction: Create Metadata Accounts");
56 process_deprecated_create_metadata_accounts(
57 program_id,
58 accounts,
59 args.data,
60 false,
61 args.is_mutable,
62 )
63 }
64 MetadataInstruction::UpdateMetadataAccount(args) => {
65 msg!("(Deprecated as of 1.1.0) Instruction: Update Metadata Accounts");
66 process_deprecated_update_metadata_accounts(
67 program_id,
68 accounts,
69 args.data,
70 args.update_authority,
71 args.primary_sale_happened,
72 )
73 }
74 MetadataInstruction::CreateMetadataAccountV2(args) => {
75 msg!("Instruction: Create Metadata Accounts v2");
76 process_create_metadata_accounts_v2(
77 program_id,
78 accounts,
79 args.data,
80 false,
81 args.is_mutable,
82 )
83 }
84 MetadataInstruction::UpdateMetadataAccountV2(args) => {
85 msg!("Instruction: Update Metadata Accounts v2");
86 process_update_metadata_accounts_v2(
87 program_id,
88 accounts,
89 args.data,
90 args.update_authority,
91 args.primary_sale_happened,
92 args.is_mutable,
93 )
94 }
95 MetadataInstruction::DeprecatedCreateMasterEdition(_args) => {
96 msg!("Instruction: Deprecated Create Master Edition, Removed in 1.1.0");
97 Err(MetadataError::Removed.into())
98 }
99 MetadataInstruction::DeprecatedMintNewEditionFromMasterEditionViaPrintingToken => {
100 msg!("Instruction: Deprecated Mint New Edition from Master Edition Via Token, Removed in 1.1.0");
101 Err(MetadataError::Removed.into())
102 }
103 MetadataInstruction::UpdatePrimarySaleHappenedViaToken => {
104 msg!("Instruction: Update primary sale via token");
105 process_update_primary_sale_happened_via_token(program_id, accounts)
106 }
107 MetadataInstruction::DeprecatedSetReservationList(_args) => {
108 msg!("Instruction: Deprecated Set Reservation List, Removed in 1.1.0");
109 Err(MetadataError::Removed.into())
110 }
111 MetadataInstruction::DeprecatedCreateReservationList => {
112 msg!("Instruction: Deprecated Create Reservation List, Removed in 1.1.0");
113 Err(MetadataError::Removed.into())
114 }
115 MetadataInstruction::SignMetadata => {
116 msg!("Instruction: Sign Metadata");
117 process_sign_metadata(program_id, accounts)
118 }
119 MetadataInstruction::DeprecatedMintPrintingTokensViaToken(_args) => {
120 msg!("Instruction: Deprecated Mint Printing Tokens Via Token, Removed in 1.1.0");
121 Err(MetadataError::Removed.into())
122 }
123 MetadataInstruction::DeprecatedMintPrintingTokens(_args) => {
124 msg!("Instruction: Deprecated Mint Printing Tokens, Removed in 1.1.0");
125 Err(MetadataError::Removed.into())
126 }
127 MetadataInstruction::CreateMasterEdition(args) => {
128 msg!("(Deprecated as of 1.1.0, please use V3 Create Master Edition)\n V2 Create Master Edition");
129 process_create_master_edition(program_id, accounts, args.max_supply)
130 }
131 MetadataInstruction::CreateMasterEditionV3(args) => {
132 msg!("V3 Create Master Edition");
133 process_create_master_edition(program_id, accounts, args.max_supply)
134 }
135 MetadataInstruction::MintNewEditionFromMasterEditionViaToken(args) => {
136 msg!("Instruction: Mint New Edition from Master Edition Via Token");
137 process_mint_new_edition_from_master_edition_via_token(
138 program_id,
139 accounts,
140 args.edition,
141 false,
142 )
143 }
144 MetadataInstruction::ConvertMasterEditionV1ToV2 => {
145 msg!("Instruction: Convert Master Edition V1 to V2");
146 process_convert_master_edition_v1_to_v2(program_id, accounts)
147 }
148 MetadataInstruction::MintNewEditionFromMasterEditionViaVaultProxy(args) => {
149 msg!("Instruction: Mint New Edition from Master Edition Via Vault Proxy");
150 process_mint_new_edition_from_master_edition_via_vault_proxy(
151 program_id,
152 accounts,
153 args.edition,
154 )
155 }
156 MetadataInstruction::PuffMetadata => {
157 msg!("Instruction: Puff Metadata");
158 process_puff_metadata_account(program_id, accounts)
159 }
160 MetadataInstruction::VerifyCollection => {
161 msg!("Instruction: Verify Collection");
162 verify_collection(program_id, accounts)
163 }
164 MetadataInstruction::UnverifyCollection => {
165 msg!("Instruction: Unverify Collection");
166 unverify_collection(program_id, accounts)
167 }
168 MetadataInstruction::Utilize(args) => {
169 msg!("Instruction: Use/Utilize Token");
170 process_utilize(program_id, accounts, args.number_of_uses)
171 }
172 MetadataInstruction::ApproveUseAuthority(args) => {
173 msg!("Instruction: Approve Use Authority");
174 process_approve_use_authority(program_id, accounts, args.number_of_uses)
175 }
176 MetadataInstruction::RevokeUseAuthority => {
177 msg!("Instruction: Revoke Use Authority");
178 process_revoke_use_authority(program_id, accounts)
179 }
180 MetadataInstruction::ApproveCollectionAuthority => {
181 msg!("Instruction: Approve Collection Authority");
182 process_approve_collection_authority(program_id, accounts)
183 }
184 MetadataInstruction::RevokeCollectionAuthority => {
185 msg!("Instruction: Revoke Collection Authority");
186 process_revoke_collection_authority(program_id, accounts)
187 }
188 }
189}
190
191pub fn process_create_metadata_accounts_v2<'a>(
192 program_id: &'a Pubkey,
193 accounts: &'a [AccountInfo<'a>],
194 data: DataV2,
195 allow_direct_creator_writes: bool,
196 is_mutable: bool,
197) -> ProgramResult {
198 let account_info_iter = &mut accounts.iter();
199 let metadata_account_info = next_account_info(account_info_iter)?;
200 let mint_info = next_account_info(account_info_iter)?;
201 let mint_authority_info = next_account_info(account_info_iter)?;
202 let payer_account_info = next_account_info(account_info_iter)?;
203 let update_authority_info = next_account_info(account_info_iter)?;
204 let system_account_info = next_account_info(account_info_iter)?;
205 let rent_info = next_account_info(account_info_iter)?;
206
207 process_create_metadata_accounts_logic(
208 &program_id,
209 CreateMetadataAccountsLogicArgs {
210 metadata_account_info,
211 mint_info,
212 mint_authority_info,
213 payer_account_info,
214 update_authority_info,
215 system_account_info,
216 rent_info,
217 },
218 data,
219 allow_direct_creator_writes,
220 is_mutable,
221 false,
222 true,
223 )
224}
225
226pub fn process_update_metadata_accounts_v2(
228 program_id: &Pubkey,
229 accounts: &[AccountInfo],
230 optional_data: Option<DataV2>,
231 update_authority: Option<Pubkey>,
232 primary_sale_happened: Option<bool>,
233 is_mutable: Option<bool>,
234) -> ProgramResult {
235 let account_info_iter = &mut accounts.iter();
236
237 let metadata_account_info = next_account_info(account_info_iter)?;
238 let update_authority_info = next_account_info(account_info_iter)?;
239 let mut metadata = Metadata::from_account_info(metadata_account_info)?;
240
241 assert_owned_by(metadata_account_info, program_id)?;
242 assert_update_authority_is_correct(&metadata, update_authority_info)?;
243
244 if let Some(data) = optional_data {
245 if metadata.is_mutable {
246 let compatible_data = data.to_v1();
247 assert_data_valid(
248 &compatible_data,
249 update_authority_info.key,
250 &metadata,
251 false,
252 update_authority_info.is_signer,
253 true,
254 )?;
255 metadata.data = compatible_data;
256 assert_collection_update_is_valid(&metadata.collection, &data.collection)?;
257 metadata.collection = data.collection;
258 } else {
259 return Err(MetadataError::DataIsImmutable.into());
260 }
261 }
262
263 if let Some(val) = update_authority {
264 metadata.update_authority = val;
265 }
266
267 if let Some(val) = primary_sale_happened {
268 if val {
269 metadata.primary_sale_happened = val
270 } else {
271 return Err(MetadataError::PrimarySaleCanOnlyBeFlippedToTrue.into());
272 }
273 }
274
275 if let Some(val) = is_mutable {
276 if !val {
277 metadata.is_mutable = val
278 } else {
279 return Err(MetadataError::IsMutableCanOnlyBeFlippedToFalse.into());
280 }
281 }
282
283 puff_out_data_fields(&mut metadata);
284
285 metadata.serialize(&mut *metadata_account_info.data.borrow_mut())?;
286 Ok(())
287}
288pub fn process_update_primary_sale_happened_via_token(
289 program_id: &Pubkey,
290 accounts: &[AccountInfo],
291) -> ProgramResult {
292 let account_info_iter = &mut accounts.iter();
293
294 let metadata_account_info = next_account_info(account_info_iter)?;
295 let owner_info = next_account_info(account_info_iter)?;
296 let token_account_info = next_account_info(account_info_iter)?;
297
298 let token_account: Account = assert_initialized(token_account_info)?;
299 let mut metadata = Metadata::from_account_info(metadata_account_info)?;
300
301 assert_owned_by(metadata_account_info, program_id)?;
302 assert_owned_by(token_account_info, &spl_token::id())?;
303
304 if !owner_info.is_signer {
305 return Err(ProgramError::MissingRequiredSignature);
306 }
307
308 if token_account.owner != *owner_info.key {
309 return Err(MetadataError::OwnerMismatch.into());
310 }
311
312 if token_account.amount == 0 {
313 return Err(MetadataError::NoBalanceInAccountForAuthorization.into());
314 }
315
316 if token_account.mint != metadata.mint {
317 return Err(MetadataError::MintMismatch.into());
318 }
319
320 metadata.primary_sale_happened = true;
321 metadata.serialize(&mut *metadata_account_info.data.borrow_mut())?;
322
323 Ok(())
324}
325
326pub fn process_sign_metadata(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
327 let account_info_iter = &mut accounts.iter();
328
329 let metadata_info = next_account_info(account_info_iter)?;
330 let creator_info = next_account_info(account_info_iter)?;
331
332 assert_signer(creator_info)?;
333 assert_owned_by(metadata_info, program_id)?;
334
335 let mut metadata = Metadata::from_account_info(metadata_info)?;
336
337 if let Some(creators) = &mut metadata.data.creators {
338 let mut found = false;
339 for creator in creators {
340 if creator.address == *creator_info.key {
341 creator.verified = true;
342 found = true;
343 break;
344 }
345 }
346 if !found {
347 return Err(MetadataError::CreatorNotFound.into());
348 }
349 } else {
350 return Err(MetadataError::NoCreatorsPresentOnMetadata.into());
351 }
352 metadata.serialize(&mut *metadata_info.data.borrow_mut())?;
353
354 Ok(())
355}
356
357pub fn process_create_master_edition(
359 program_id: &Pubkey,
360 accounts: &[AccountInfo],
361 max_supply: Option<u64>,
362) -> ProgramResult {
363 let account_info_iter = &mut accounts.iter();
364
365 let edition_account_info = next_account_info(account_info_iter)?;
366 let mint_info = next_account_info(account_info_iter)?;
367 let update_authority_info = next_account_info(account_info_iter)?;
368 let mint_authority_info = next_account_info(account_info_iter)?;
369 let payer_account_info = next_account_info(account_info_iter)?;
370 let metadata_account_info = next_account_info(account_info_iter)?;
371 let token_program_info = next_account_info(account_info_iter)?;
372 let system_account_info = next_account_info(account_info_iter)?;
373 let rent_info = next_account_info(account_info_iter)?;
374
375 let metadata = Metadata::from_account_info(metadata_account_info)?;
376 let mint: Mint = assert_initialized(mint_info)?;
377
378 let bump_seed = assert_derivation(
379 program_id,
380 edition_account_info,
381 &[
382 PREFIX.as_bytes(),
383 program_id.as_ref(),
384 &mint_info.key.as_ref(),
385 EDITION.as_bytes(),
386 ],
387 )?;
388
389 assert_token_program_matches_package(token_program_info)?;
390 assert_mint_authority_matches_mint(&mint.mint_authority, mint_authority_info)?;
391 assert_owned_by(metadata_account_info, program_id)?;
392 assert_owned_by(mint_info, &spl_token::id())?;
393
394 if metadata.mint != *mint_info.key {
395 return Err(MetadataError::MintMismatch.into());
396 }
397
398 if mint.decimals != 0 {
399 return Err(MetadataError::EditionMintDecimalsShouldBeZero.into());
400 }
401
402 assert_update_authority_is_correct(&metadata, update_authority_info)?;
403
404 if mint.supply != 1 {
405 return Err(MetadataError::EditionsMustHaveExactlyOneToken.into());
406 }
407
408 let edition_authority_seeds = &[
409 PREFIX.as_bytes(),
410 program_id.as_ref(),
411 &mint_info.key.as_ref(),
412 EDITION.as_bytes(),
413 &[bump_seed],
414 ];
415
416 create_or_allocate_account_raw(
417 *program_id,
418 edition_account_info,
419 rent_info,
420 system_account_info,
421 payer_account_info,
422 MAX_MASTER_EDITION_LEN,
423 edition_authority_seeds,
424 )?;
425
426 let mut edition = MasterEditionV2::from_account_info(edition_account_info)?;
427
428 edition.key = Key::MasterEditionV2;
429 edition.supply = 0;
430 edition.max_supply = max_supply;
431 edition.serialize(&mut *edition_account_info.data.borrow_mut())?;
432 if metadata_account_info.is_writable {
433 let mut metadata_mut = Metadata::from_account_info(metadata_account_info)?;
434 metadata_mut.token_standard = Some(TokenStandard::NonFungible);
435 metadata_mut.serialize(&mut *metadata_account_info.data.borrow_mut())?;
436 }
437
438 transfer_mint_authority(
441 edition_account_info.key,
442 edition_account_info,
443 mint_info,
444 mint_authority_info,
445 token_program_info,
446 )?;
447
448 Ok(())
449}
450
451pub fn process_mint_new_edition_from_master_edition_via_token<'a>(
452 program_id: &'a Pubkey,
453 accounts: &'a [AccountInfo<'a>],
454 edition: u64,
455 ignore_owner_signer: bool,
456) -> ProgramResult {
457 let account_info_iter = &mut accounts.iter();
458
459 let new_metadata_account_info = next_account_info(account_info_iter)?;
460 let new_edition_account_info = next_account_info(account_info_iter)?;
461 let master_edition_account_info = next_account_info(account_info_iter)?;
462 let mint_info = next_account_info(account_info_iter)?;
463 let edition_marker_info = next_account_info(account_info_iter)?;
464 let mint_authority_info = next_account_info(account_info_iter)?;
465 let payer_account_info = next_account_info(account_info_iter)?;
466 let owner_account_info = next_account_info(account_info_iter)?;
467 let token_account_info = next_account_info(account_info_iter)?;
468 let update_authority_info = next_account_info(account_info_iter)?;
469 let master_metadata_account_info = next_account_info(account_info_iter)?;
470 let token_program_account_info = next_account_info(account_info_iter)?;
471 let system_account_info = next_account_info(account_info_iter)?;
472 let rent_info = next_account_info(account_info_iter)?;
473
474 process_mint_new_edition_from_master_edition_via_token_logic(
475 &program_id,
476 MintNewEditionFromMasterEditionViaTokenLogicArgs {
477 new_metadata_account_info,
478 new_edition_account_info,
479 master_edition_account_info,
480 mint_info,
481 edition_marker_info,
482 mint_authority_info,
483 payer_account_info,
484 owner_account_info,
485 token_account_info,
486 update_authority_info,
487 master_metadata_account_info,
488 token_program_account_info,
489 system_account_info,
490 rent_info,
491 },
492 edition,
493 ignore_owner_signer,
494 )
495}
496
497pub fn process_convert_master_edition_v1_to_v2(
498 program_id: &Pubkey,
499 accounts: &[AccountInfo],
500) -> ProgramResult {
501 let account_info_iter = &mut accounts.iter();
502 let master_edition_info = next_account_info(account_info_iter)?;
503 let one_time_printing_auth_mint_info = next_account_info(account_info_iter)?;
504 let printing_mint_info = next_account_info(account_info_iter)?;
505
506 assert_owned_by(master_edition_info, program_id)?;
507 assert_owned_by(one_time_printing_auth_mint_info, &spl_token::id())?;
508 assert_owned_by(printing_mint_info, &spl_token::id())?;
509 let master_edition: MasterEditionV1 = MasterEditionV1::from_account_info(master_edition_info)?;
510 let printing_mint: Mint = assert_initialized(printing_mint_info)?;
511 let auth_mint: Mint = assert_initialized(one_time_printing_auth_mint_info)?;
512 if master_edition.one_time_printing_authorization_mint != *one_time_printing_auth_mint_info.key
513 {
514 return Err(MetadataError::OneTimePrintingAuthMintMismatch.into());
515 }
516
517 if master_edition.printing_mint != *printing_mint_info.key {
518 return Err(MetadataError::PrintingMintMismatch.into());
519 }
520
521 if printing_mint.supply != 0 {
522 return Err(MetadataError::PrintingMintSupplyMustBeZeroForConversion.into());
523 }
524
525 if auth_mint.supply != 0 {
526 return Err(MetadataError::OneTimeAuthMintSupplyMustBeZeroForConversion.into());
527 }
528
529 MasterEditionV2 {
530 key: Key::MasterEditionV2,
531 supply: master_edition.supply,
532 max_supply: master_edition.max_supply,
533 }
534 .serialize(&mut *master_edition_info.data.borrow_mut())?;
535
536 Ok(())
537}
538
539pub fn process_mint_new_edition_from_master_edition_via_vault_proxy<'a>(
540 program_id: &'a Pubkey,
541 accounts: &'a [AccountInfo<'a>],
542 edition: u64,
543) -> ProgramResult {
544 let account_info_iter = &mut accounts.iter();
545
546 let new_metadata_account_info = next_account_info(account_info_iter)?;
547 let new_edition_account_info = next_account_info(account_info_iter)?;
548 let master_edition_account_info = next_account_info(account_info_iter)?;
549 let mint_info = next_account_info(account_info_iter)?;
550 let edition_marker_info = next_account_info(account_info_iter)?;
551 let mint_authority_info = next_account_info(account_info_iter)?;
552 let payer_info = next_account_info(account_info_iter)?;
553 let vault_authority_info = next_account_info(account_info_iter)?;
554 let store_info = next_account_info(account_info_iter)?;
555 let safety_deposit_info = next_account_info(account_info_iter)?;
556 let vault_info = next_account_info(account_info_iter)?;
557 let update_authority_info = next_account_info(account_info_iter)?;
558 let master_metadata_account_info = next_account_info(account_info_iter)?;
559 let token_program_account_info = next_account_info(account_info_iter)?;
560 let token_vault_program_info = next_account_info(account_info_iter)?;
567 let system_account_info = next_account_info(account_info_iter)?;
568 let rent_info = next_account_info(account_info_iter)?;
569
570 let vault_data = vault_info.data.borrow();
571 let safety_deposit_data = safety_deposit_info.data.borrow();
572
573 if vault_data[0] != mpl_token_vault::state::Key::VaultV1 as u8 {
575 return Err(VaultError::DataTypeMismatch.into());
576 }
577
578 if safety_deposit_data[0] != mpl_token_vault::state::Key::SafetyDepositBoxV1 as u8 {
579 return Err(VaultError::DataTypeMismatch.into());
580 }
581
582 let token_program = Pubkey::new_from_array(*array_ref![vault_data, 1, 32]);
584 let vault_authority = Pubkey::new_from_array(*array_ref![vault_data, 65, 32]);
585 let store_on_sd = Pubkey::new_from_array(*array_ref![safety_deposit_data, 65, 32]);
586 let vault_on_sd = Pubkey::new_from_array(*array_ref![safety_deposit_data, 1, 32]);
587
588 let owner = get_owner_from_token_account(store_info)?;
589
590 let seeds = &[
591 mpl_token_vault::state::PREFIX.as_bytes(),
592 token_vault_program_info.key.as_ref(),
593 vault_info.key.as_ref(),
594 ];
595 let (authority, _) = Pubkey::find_program_address(seeds, token_vault_program_info.key);
596
597 if owner != authority {
598 return Err(MetadataError::InvalidOwner.into());
599 }
600
601 assert_signer(vault_authority_info)?;
602
603 assert_owned_by(vault_info, token_vault_program_info.key)?;
608 assert_owned_by(safety_deposit_info, token_vault_program_info.key)?;
609 assert_owned_by(store_info, token_program_account_info.key)?;
610
611 if &token_program != token_program_account_info.key {
612 return Err(VaultError::TokenProgramProvidedDoesNotMatchVault.into());
613 }
614
615 if !vault_authority_info.is_signer {
616 return Err(VaultError::AuthorityIsNotSigner.into());
617 }
618 if *vault_authority_info.key != vault_authority {
619 return Err(VaultError::AuthorityDoesNotMatch.into());
620 }
621
622 if vault_data[195] != VaultState::Combined as u8 {
623 return Err(VaultError::VaultShouldBeCombined.into());
624 }
625
626 if vault_on_sd != *vault_info.key {
627 return Err(VaultError::SafetyDepositBoxVaultMismatch.into());
628 }
629
630 if *store_info.key != store_on_sd {
631 return Err(VaultError::StoreDoesNotMatchSafetyDepositBox.into());
632 }
633
634 let args = MintNewEditionFromMasterEditionViaTokenLogicArgs {
635 new_metadata_account_info,
636 new_edition_account_info,
637 master_edition_account_info,
638 mint_info,
639 edition_marker_info,
640 mint_authority_info,
641 payer_account_info: payer_info,
642 owner_account_info: vault_authority_info,
643 token_account_info: store_info,
644 update_authority_info,
645 master_metadata_account_info,
646 token_program_account_info,
647 system_account_info,
648 rent_info,
649 };
650
651 process_mint_new_edition_from_master_edition_via_token_logic(program_id, args, edition, true)
652}
653
654pub fn process_puff_metadata_account(
657 program_id: &Pubkey,
658 accounts: &[AccountInfo],
659) -> ProgramResult {
660 let account_info_iter = &mut accounts.iter();
661
662 let metadata_account_info = next_account_info(account_info_iter)?;
663 let mut metadata = Metadata::from_account_info(metadata_account_info)?;
664
665 assert_owned_by(metadata_account_info, program_id)?;
666
667 puff_out_data_fields(&mut metadata);
668
669 let edition_seeds = &[
670 PREFIX.as_bytes(),
671 program_id.as_ref(),
672 metadata.mint.as_ref(),
673 EDITION.as_bytes(),
674 ];
675 let (_, edition_bump_seed) = Pubkey::find_program_address(edition_seeds, program_id);
676 metadata.edition_nonce = Some(edition_bump_seed);
677
678 metadata.serialize(&mut *metadata_account_info.data.borrow_mut())?;
679 Ok(())
680}
681
682pub fn verify_collection(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
683 let account_info_iter = &mut accounts.iter();
684 let metadata_info = next_account_info(account_info_iter)?;
685 let collection_authority_info = next_account_info(account_info_iter)?;
686 let payer_info = next_account_info(account_info_iter)?;
687 let collection_mint = next_account_info(account_info_iter)?;
688 let collection_info = next_account_info(account_info_iter)?;
689 let edition_account_info = next_account_info(account_info_iter)?;
690 let using_delegated_collection_authority = accounts.len() == 7;
691 assert_signer(collection_authority_info)?;
692 assert_signer(payer_info)?;
693
694 assert_owned_by(metadata_info, program_id)?;
695 assert_owned_by(collection_info, program_id)?;
696 assert_owned_by(collection_mint, &spl_token::id())?;
697 assert_owned_by(edition_account_info, program_id)?;
698
699 let mut metadata = Metadata::from_account_info(metadata_info)?;
700 let collection_data = Metadata::from_account_info(collection_info)?;
701 assert_collection_verify_is_valid(
702 &metadata,
703 &collection_data,
704 collection_mint,
705 edition_account_info,
706 )?;
707 if using_delegated_collection_authority {
708 let collection_authority_record = next_account_info(account_info_iter)?;
709 assert_has_collection_authority(
710 collection_authority_info,
711 &collection_data,
712 collection_mint.key,
713 Some(collection_authority_record),
714 )?;
715 } else {
716 assert_has_collection_authority(
717 collection_authority_info,
718 &collection_data,
719 collection_mint.key,
720 None,
721 )?;
722 }
723 if let Some(collection) = &mut metadata.collection {
724 collection.verified = true;
725 }
726 metadata.serialize(&mut *metadata_info.data.borrow_mut())?;
727 Ok(())
728}
729
730pub fn unverify_collection(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
731 let account_info_iter = &mut accounts.iter();
732 let metadata_info = next_account_info(account_info_iter)?;
733 let collection_authority_info = next_account_info(account_info_iter)?;
734 let collection_mint = next_account_info(account_info_iter)?;
735 let collection_info = next_account_info(account_info_iter)?;
736 let edition_account_info = next_account_info(account_info_iter)?;
737 let using_delegated_collection_authority = accounts.len() == 6;
738
739 assert_signer(collection_authority_info)?;
740 assert_owned_by(metadata_info, program_id)?;
741 assert_owned_by(collection_info, program_id)?;
742 assert_owned_by(collection_mint, &spl_token::id())?;
743 assert_owned_by(edition_account_info, program_id)?;
744
745 let mut metadata = Metadata::from_account_info(metadata_info)?;
746 let collection_data = Metadata::from_account_info(collection_info)?;
747 assert_collection_verify_is_valid(
748 &metadata,
749 &collection_data,
750 collection_mint,
751 edition_account_info,
752 )?;
753 if using_delegated_collection_authority {
754 let collection_authority_record = next_account_info(account_info_iter)?;
755 assert_has_collection_authority(
756 collection_authority_info,
757 &collection_data,
758 collection_mint.key,
759 Some(collection_authority_record),
760 )?;
761 } else {
762 assert_has_collection_authority(
763 collection_authority_info,
764 &collection_data,
765 collection_mint.key,
766 None,
767 )?;
768 }
769 if let Some(collection) = &mut metadata.collection {
770 collection.verified = false;
771 }
772 metadata.serialize(&mut *metadata_info.data.borrow_mut())?;
773 Ok(())
774}
775
776pub fn process_approve_use_authority(
777 program_id: &Pubkey,
778 accounts: &[AccountInfo],
779 number_of_uses: u64,
780) -> ProgramResult {
781 let account_info_iter = &mut accounts.iter();
782 let use_authority_record_info = next_account_info(account_info_iter)?;
783 let owner_info = next_account_info(account_info_iter)?;
784 let payer = next_account_info(account_info_iter)?;
785 let user_info = next_account_info(account_info_iter)?;
786 let token_account_info = next_account_info(account_info_iter)?;
787 let metadata_info = next_account_info(account_info_iter)?;
788 let mint_info = next_account_info(account_info_iter)?;
789 let program_as_burner = next_account_info(account_info_iter)?;
790 let token_program_account_info = next_account_info(account_info_iter)?;
791 let system_account_info = next_account_info(account_info_iter)?;
792 let rent_info = next_account_info(account_info_iter)?;
793 let metadata = Metadata::from_account_info(metadata_info)?;
794 if metadata.uses.is_none() {
795 return Err(MetadataError::Unusable.into());
796 }
797 if *token_program_account_info.key != spl_token::id() {
798 return Err(MetadataError::InvalidTokenProgram.into());
799 }
800 assert_signer(&owner_info)?;
801 assert_signer(&payer)?;
802 assert_currently_holding(
803 program_id,
804 owner_info,
805 metadata_info,
806 &metadata,
807 mint_info,
808 token_account_info,
809 )?;
810
811 let bump_seed = process_use_authority_validation(
812 program_id,
813 use_authority_record_info,
814 user_info,
815 mint_info,
816 true,
817 )?;
818
819 let metadata_uses = metadata.uses.unwrap();
820 let use_authority_seeds = &[
821 PREFIX.as_bytes(),
822 program_id.as_ref(),
823 &mint_info.key.as_ref(),
824 USER.as_bytes(),
825 &user_info.key.as_ref(),
826 &[bump_seed],
827 ];
828
829 create_or_allocate_account_raw(
830 *program_id,
831 use_authority_record_info,
832 rent_info,
833 system_account_info,
834 payer,
835 USE_AUTHORITY_RECORD_SIZE,
836 use_authority_seeds,
837 )?;
838 if number_of_uses > metadata_uses.remaining {
839 return Err(MetadataError::NotEnoughUses.into());
840 }
841 if metadata_uses.use_method == UseMethod::Burn {
842 invoke(
843 &approve(
844 &token_program_account_info.key,
845 &token_account_info.key,
846 &program_as_burner.key,
847 &owner_info.key,
848 &[],
849 1,
850 )
851 .unwrap(),
852 &[
853 token_program_account_info.clone(),
854 token_account_info.clone(),
855 program_as_burner.clone(),
856 owner_info.clone(),
857 ],
858 )?;
859 }
860 let mut record = UseAuthorityRecord::from_account_info(use_authority_record_info)?;
861 record.key = Key::UseAuthorityRecord;
862 record.allowed_uses = number_of_uses;
863 record.serialize(&mut *use_authority_record_info.data.borrow_mut())?;
864 Ok(())
865}
866
867pub fn process_revoke_use_authority(
868 program_id: &Pubkey,
869 accounts: &[AccountInfo],
870) -> ProgramResult {
871 let account_info_iter = &mut accounts.iter();
872 let use_authority_record_info = next_account_info(account_info_iter)?;
873 let owner_info = next_account_info(account_info_iter)?;
874 let user_info = next_account_info(account_info_iter)?;
875 let token_account_info = next_account_info(account_info_iter)?;
876 let mint_info = next_account_info(account_info_iter)?;
877 let metadata_info = next_account_info(account_info_iter)?;
878 let token_program_account_info = next_account_info(account_info_iter)?;
879 let metadata = Metadata::from_account_info(metadata_info)?;
880 if metadata.uses.is_none() {
881 return Err(MetadataError::Unusable.into());
882 }
883 if *token_program_account_info.key != spl_token::id() {
884 return Err(MetadataError::InvalidTokenProgram.into());
885 }
886 assert_signer(&owner_info)?;
887 assert_currently_holding(
888 program_id,
889 owner_info,
890 metadata_info,
891 &metadata,
892 mint_info,
893 token_account_info,
894 )?;
895 process_use_authority_validation(
896 program_id,
897 use_authority_record_info,
898 user_info,
899 mint_info,
900 false,
901 )?;
902 let metadata_uses = metadata.uses.unwrap();
903 if metadata_uses.use_method == UseMethod::Burn {
904 invoke(
905 &revoke(
906 &token_program_account_info.key,
907 &token_account_info.key,
908 &owner_info.key,
909 &[],
910 )
911 .unwrap(),
912 &[
913 token_program_account_info.clone(),
914 token_account_info.clone(),
915 owner_info.clone(),
916 ],
917 )?;
918 }
919 let lamports = use_authority_record_info.lamports();
920 **use_authority_record_info.lamports.borrow_mut() = 0;
921 **owner_info.lamports.borrow_mut() = owner_info
922 .lamports()
923 .checked_add(lamports)
924 .ok_or(MetadataError::NumericalOverflowError)?;
925 let mut data = use_authority_record_info.try_borrow_mut_data()?;
926 data[0] = 0;
927
928 Ok(())
929}
930
931pub fn process_utilize(
932 program_id: &Pubkey,
933 accounts: &[AccountInfo],
934 number_of_uses: u64,
935) -> ProgramResult {
936 let account_info_iter = &mut accounts.iter();
937 let metadata_info = next_account_info(account_info_iter)?;
938 let token_account_info = next_account_info(account_info_iter)?;
939 let mint_info = next_account_info(account_info_iter)?;
940 let user_info = next_account_info(account_info_iter)?;
941 let owner_info = next_account_info(account_info_iter)?;
942 let token_program_account_info = next_account_info(account_info_iter)?;
943 let _ata_program_account_info = next_account_info(account_info_iter)?;
944 let _system_account_info = next_account_info(account_info_iter)?;
945 let _rent_info = next_account_info(account_info_iter)?;
946 let metadata = Metadata::from_account_info(metadata_info)?;
947 let approved_authority_is_using = accounts.len() == 11;
948 if metadata.uses.is_none() {
949 return Err(MetadataError::Unusable.into());
950 }
951 if *token_program_account_info.key != spl_token::id() {
952 return Err(MetadataError::InvalidTokenProgram.into());
953 }
954
955 assert_signer(&user_info)?;
956 assert_currently_holding(
957 program_id,
958 owner_info,
959 metadata_info,
960 &metadata,
961 mint_info,
962 token_account_info,
963 )?;
964 let mut metadata = Metadata::from_account_info(metadata_info)?;
965 let metadata_uses = metadata.uses.unwrap();
966 let must_burn = metadata_uses.use_method == UseMethod::Burn;
967 if number_of_uses > metadata_uses.total || number_of_uses > metadata_uses.remaining {
968 return Err(MetadataError::NotEnoughUses.into());
969 }
970 let remaining_uses = metadata_uses
971 .remaining
972 .checked_sub(number_of_uses)
973 .ok_or(MetadataError::NotEnoughUses)?;
974 metadata.uses = Some(Uses {
975 use_method: metadata_uses.use_method,
976 total: metadata_uses.total,
977 remaining: remaining_uses,
978 });
979 if approved_authority_is_using {
980 let use_authority_record_info = next_account_info(account_info_iter)?;
981 process_use_authority_validation(
982 program_id,
983 use_authority_record_info,
984 user_info,
985 mint_info,
986 false,
987 )?;
988 assert_owned_by(use_authority_record_info, program_id)?;
989 let mut record = UseAuthorityRecord::from_account_info(use_authority_record_info)?;
990 record.allowed_uses = record
991 .allowed_uses
992 .checked_sub(number_of_uses)
993 .ok_or(MetadataError::NotEnoughUses)?;
994 record.serialize(&mut *use_authority_record_info.data.borrow_mut())?;
995 }
996 metadata.serialize(&mut *metadata_info.data.borrow_mut())?;
997 if remaining_uses <= 0 && must_burn {
998 if approved_authority_is_using {
999 let burn_path = &[PREFIX.as_bytes(), program_id.as_ref(), BURN.as_bytes()];
1000 let burn_authority_info = next_account_info(account_info_iter)?;
1001 let burn_bump_ref = &[
1002 PREFIX.as_bytes(),
1003 program_id.as_ref(),
1004 BURN.as_bytes(),
1005 &[assert_derivation(
1006 &program_id,
1007 burn_authority_info,
1008 burn_path,
1009 )?],
1010 ];
1011 spl_token_burn(TokenBurnParams {
1012 mint: mint_info.clone(),
1013 amount: 1,
1014 authority: burn_authority_info.clone(),
1015 token_program: token_program_account_info.clone(),
1016 source: token_account_info.clone(),
1017 authority_signer_seeds: Some(burn_bump_ref),
1018 })?;
1019 } else {
1020 spl_token_burn(TokenBurnParams {
1021 mint: mint_info.clone(),
1022 amount: 1,
1023 authority: owner_info.clone(),
1024 token_program: token_program_account_info.clone(),
1025 source: token_account_info.clone(),
1026 authority_signer_seeds: None,
1027 })?;
1028 }
1029 }
1030 Ok(())
1031}
1032
1033pub fn process_approve_collection_authority(
1034 program_id: &Pubkey,
1035 accounts: &[AccountInfo],
1036) -> ProgramResult {
1037 let account_info_iter = &mut accounts.iter();
1038 let collection_authority_record = next_account_info(account_info_iter)?;
1039 let new_collection_authority = next_account_info(account_info_iter)?;
1040 let update_authority = next_account_info(account_info_iter)?;
1041 let payer = next_account_info(account_info_iter)?;
1042 let metadata_info = next_account_info(account_info_iter)?;
1043 let mint_info = next_account_info(account_info_iter)?;
1044 let system_account_info = next_account_info(account_info_iter)?;
1045 let rent_info = next_account_info(account_info_iter)?;
1046
1047 let metadata = Metadata::from_account_info(metadata_info)?;
1048 assert_owned_by(metadata_info, program_id)?;
1049 assert_owned_by(mint_info, &spl_token::id())?;
1050 assert_signer(&update_authority)?;
1051 assert_signer(&payer)?;
1052 if metadata.update_authority != *update_authority.key {
1053 return Err(MetadataError::UpdateAuthorityIncorrect.into());
1054 }
1055 if metadata.mint != *mint_info.key {
1056 return Err(MetadataError::MintMismatch.into());
1057 }
1058 let collection_authority_info_empty = collection_authority_record.try_data_is_empty()?;
1059 if !collection_authority_info_empty {
1060 return Err(MetadataError::CollectionAuthorityRecordAlreadyExists.into());
1061 }
1062 let collection_authority_path = Vec::from([
1063 PREFIX.as_bytes(),
1064 program_id.as_ref(),
1065 &mint_info.key.as_ref(),
1066 COLLECTION_AUTHORITY.as_bytes(),
1067 &new_collection_authority.key.as_ref(),
1068 ]);
1069 let collection_authority_bump_seed = &[assert_derivation(
1070 program_id,
1071 collection_authority_record,
1072 &collection_authority_path,
1073 )?];
1074 let mut collection_authority_seeds = collection_authority_path.clone();
1075 collection_authority_seeds.push(collection_authority_bump_seed);
1076 create_or_allocate_account_raw(
1077 *program_id,
1078 collection_authority_record,
1079 rent_info,
1080 system_account_info,
1081 payer,
1082 COLLECTION_AUTHORITY_RECORD_SIZE,
1083 &collection_authority_seeds,
1084 )?;
1085
1086 let mut record = CollectionAuthorityRecord::from_account_info(collection_authority_record)?;
1087 record.key = Key::CollectionAuthorityRecord;
1088 record.serialize(&mut *collection_authority_record.data.borrow_mut())?;
1089 Ok(())
1090}
1091
1092pub fn process_revoke_collection_authority(
1093 program_id: &Pubkey,
1094 accounts: &[AccountInfo],
1095) -> ProgramResult {
1096 let account_info_iter = &mut accounts.iter();
1097 let collection_authority_record = next_account_info(account_info_iter)?;
1098 let new_collection_authority = next_account_info(account_info_iter)?;
1099 let update_authority = next_account_info(account_info_iter)?;
1100 let metadata_info = next_account_info(account_info_iter)?;
1101 let mint_info = next_account_info(account_info_iter)?;
1102 let metadata = Metadata::from_account_info(metadata_info)?;
1103 assert_owned_by(metadata_info, program_id)?;
1104 assert_owned_by(mint_info, &spl_token::id())?;
1105 assert_signer(&update_authority)?;
1106 if metadata.update_authority != *update_authority.key {
1107 return Err(MetadataError::UpdateAuthorityIncorrect.into());
1108 }
1109 if metadata.mint != *mint_info.key {
1110 return Err(MetadataError::MintMismatch.into());
1111 }
1112 let collection_authority_info_empty = collection_authority_record.try_data_is_empty()?;
1113 if collection_authority_info_empty {
1114 return Err(MetadataError::CollectionAuthorityDoesNotExist.into());
1115 }
1116 assert_has_collection_authority(
1117 new_collection_authority,
1118 &metadata,
1119 &mint_info.key,
1120 Some(collection_authority_record),
1121 )?;
1122 let lamports = **collection_authority_record.lamports.borrow();
1123 **collection_authority_record.lamports.borrow_mut() = 0;
1124 **update_authority.lamports.borrow_mut() = lamports;
1125 let mut data = collection_authority_record.try_borrow_mut_data()?;
1126 data[0] = 0;
1127 Ok(())
1128}