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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use anchor_lang::prelude::*;
use mpl_token_metadata::accounts::Metadata;

use crate::{
    approve_collection_authority_helper, cmp_pubkeys, constants::AUTHORITY_SEED,
    revoke_collection_authority_helper, AccountVersion, ApproveCollectionAuthorityHelperAccounts,
    CandyError, CandyMachine, RevokeCollectionAuthorityHelperAccounts,
};

pub fn set_collection(ctx: Context<SetCollection>) -> Result<()> {
    msg!("(Deprecated as of 1.0.0) Use SetCollectionV2 instead");

    let accounts = ctx.accounts;
    let candy_machine = &mut accounts.candy_machine;

    if !matches!(candy_machine.version, AccountVersion::V1) {
        return err!(CandyError::InvalidAccountVersion);
    }

    if candy_machine.items_redeemed > 0 {
        return err!(CandyError::NoChangingCollectionDuringMint);
    } else if !cmp_pubkeys(accounts.collection_mint.key, &candy_machine.collection_mint) {
        return err!(CandyError::MintMismatch);
    }

    let collection_metadata_info = &accounts.collection_metadata;
    let collection_metadata: Metadata =
        Metadata::try_from(&collection_metadata_info.to_account_info())?;

    // revoking the existing collection authority

    let revoke_accounts = RevokeCollectionAuthorityHelperAccounts {
        authority_pda: accounts.authority_pda.to_account_info(),
        collection_authority_record: accounts.collection_authority_record.to_account_info(),
        collection_metadata: accounts.collection_metadata.to_account_info(),
        collection_mint: accounts.collection_mint.to_account_info(),
        token_metadata_program: accounts.token_metadata_program.to_account_info(),
    };

    revoke_collection_authority_helper(
        revoke_accounts,
        candy_machine.key(),
        *ctx.bumps.get("authority_pda").unwrap(),
        collection_metadata.token_standard,
    )?;

    // approving the new collection authority

    candy_machine.collection_mint = accounts.new_collection_mint.key();

    let approve_collection_authority_helper_accounts = ApproveCollectionAuthorityHelperAccounts {
        payer: accounts.payer.to_account_info(),
        authority_pda: accounts.authority_pda.to_account_info(),
        collection_update_authority: accounts.new_collection_update_authority.to_account_info(),
        collection_mint: accounts.new_collection_mint.to_account_info(),
        collection_metadata: accounts.new_collection_metadata.to_account_info(),
        collection_authority_record: accounts.new_collection_authority_record.to_account_info(),
        token_metadata_program: accounts.token_metadata_program.to_account_info(),
        system_program: accounts.system_program.to_account_info(),
    };

    approve_collection_authority_helper(approve_collection_authority_helper_accounts)
}

/// Set the collection PDA for the candy machine
#[derive(Accounts)]
pub struct SetCollection<'info> {
    /// Candy Machine account.
    #[account(mut, has_one = authority)]
    candy_machine: Account<'info, CandyMachine>,

    /// Candy Machine authority.
    authority: Signer<'info>,

    /// Authority PDA.
    ///
    /// CHECK: account checked in seeds constraint
    #[account(
        mut, seeds = [AUTHORITY_SEED.as_bytes(), candy_machine.to_account_info().key.as_ref()],
        bump
    )]
    authority_pda: UncheckedAccount<'info>,

    /// Payer of the transaction.
    payer: Signer<'info>,

    /// Mint account of the collection.
    ///
    /// CHECK: account checked in CPI
    collection_mint: UncheckedAccount<'info>,

    /// Metadata account of the collection.
    ///
    /// CHECK: account checked in CPI
    collection_metadata: UncheckedAccount<'info>,

    /// Collection authority record.
    ///
    /// CHECK: account checked in CPI
    #[account(mut)]
    collection_authority_record: UncheckedAccount<'info>,

    /// Update authority of the new collection NFT.
    #[account(mut)]
    new_collection_update_authority: Signer<'info>,

    /// New collection metadata.
    ///
    /// CHECK: account checked in CPI
    new_collection_metadata: UncheckedAccount<'info>,

    /// New collection mint.
    ///
    /// CHECK: account checked in CPI
    new_collection_mint: UncheckedAccount<'info>,

    /// New collection master edition.
    ///
    /// CHECK: account checked in CPI
    new_collection_master_edition: UncheckedAccount<'info>,

    /// New collection authority record.
    ///
    /// CHECK: account checked in CPI
    #[account(mut)]
    new_collection_authority_record: UncheckedAccount<'info>,

    /// Token Metadata program.
    ///
    /// CHECK: account checked in CPI
    #[account(address = mpl_token_metadata::ID)]
    token_metadata_program: UncheckedAccount<'info>,

    /// System program.
    system_program: Program<'info, System>,
}