1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use solana_program::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey};

use crate::{
    error::MetadataError,
    pda::find_collection_authority_account,
    state::{Collection, CollectionAuthorityRecord, MasterEditionV2, Metadata, TokenStandard},
};

pub fn assert_collection_update_is_valid(
    _existing: &Option<Collection>,
    incoming: &Option<Collection>,
) -> Result<(), ProgramError> {
    if incoming.is_some() && incoming.as_ref().unwrap().verified == true {
        // Never allow a collection to be verified outside of verify_collection instruction
        return Err(MetadataError::CollectionCannotBeVerifiedInThisInstruction.into());
    }
    Ok(())
}

pub fn assert_is_collection_delegated_authority(
    authority_record: &AccountInfo,
    collection_authority: &Pubkey,
    mint: &Pubkey,
) -> Result<u8, ProgramError> {
    let (pda, bump) = find_collection_authority_account(mint, collection_authority);
    if pda != *authority_record.key {
        return Err(MetadataError::DerivedKeyInvalid.into());
    }
    Ok(bump)
}

pub fn assert_has_collection_authority(
    collection_authority_info: &AccountInfo,
    collection_data: &Metadata,
    mint: &Pubkey,
    delegate_collection_authority_record: Option<&AccountInfo>,
) -> Result<(), ProgramError> {
    if let Some(collection_authority_record) = delegate_collection_authority_record {
        let bump = assert_is_collection_delegated_authority(
            collection_authority_record,
            collection_authority_info.key,
            mint,
        )?;
        let data = collection_authority_record
            .try_borrow_data()?;
        if data.len() == 0 {
            return Err(MetadataError::InvalidCollectionUpdateAuthority.into());
        }
        let bump_match = CollectionAuthorityRecord::from_bytes(&data)?;
        if bump_match.bump != bump {
            return Err(MetadataError::InvalidCollectionUpdateAuthority.into());
        }
    } else {
        if collection_data.update_authority != *collection_authority_info.key {
            return Err(MetadataError::InvalidCollectionUpdateAuthority.into());
        }
    }
    Ok(())
}

pub fn assert_collection_verify_is_valid(
    collection_member: &Metadata,
    collection_data: &Metadata,
    collection_mint: &AccountInfo,
    edition_account_info: &AccountInfo,
) -> Result<(), ProgramError> {
    match &collection_member.collection {
        Some(collection) => {
            if collection.key != *collection_mint.key
                || collection_data.mint != *collection_mint.key
            {
                return Err(MetadataError::CollectionNotFound.into());
            }
        }
        None => {
            return Err(MetadataError::CollectionNotFound.into());
        }
    }
    assert_master_edition(collection_data, edition_account_info)?;
    Ok(())
}

pub fn assert_master_edition(
    collection_data: &Metadata,
    edition_account_info: &AccountInfo,
) -> Result<(), ProgramError> {
    let edition = MasterEditionV2::from_account_info(edition_account_info)
        .map_err(|_err: ProgramError| MetadataError::CollectionMustBeAUniqueMasterEdition)?;
    if collection_data.token_standard != Some(TokenStandard::NonFungible)
        || edition.max_supply != Some(0)
    {
        return Err(MetadataError::CollectionMustBeAUniqueMasterEdition.into());
    }
    Ok(())
}