Skip to main content

solana_nft_token_metadata/
processor.rs

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
226// Update existing account instruction
227pub 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
357/// Create master edition
358pub 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    // While you can't mint any more of your master record, you can
439    // mint as many limited editions as you like within your max supply.
440    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    // we cant do much here to prove that this is the right token vault program except to prove that it matches
561    // the global one right now. We dont want to force people to use one vault program,
562    // so there is a bit of trust involved, but the attack vector here is someone provides
563    // an entirely fake vault program that claims to own token account X via it's pda but in order to spoof X's owner
564    // and get a free edition. However, we check that the owner of account X is the vault account's pda, so
565    // not sure how they would get away with it - they'd need to actually own that account! - J.
566    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    // Since we're crunching out borsh for CPU units, do type checks this way
574    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    // skip deserialization to keep things cheap on CPU
583    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    // Since most checks happen next level down in token program, we only need to verify
604    // that the vault authority signer matches what's expected on vault to authorize
605    // use of our pda authority, and that the token store is right for the safety deposit.
606    // Then pass it through.
607    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
654/// Puff out the variable length fields to a fixed length on a metadata
655/// account in a permissionless way.
656pub 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}