sugar_cli/update/
set_token_standard.rs

1use std::str::FromStr;
2
3use anchor_client::solana_sdk::pubkey::Pubkey;
4use anyhow::Result;
5use console::style;
6use mpl_candy_machine_core::{accounts::SetTokenStandard, AccountVersion};
7use mpl_token_metadata::{
8    instruction::MetadataDelegateRole,
9    pda::{find_collection_authority_account, find_metadata_delegate_record_account},
10};
11
12use crate::{
13    cache::load_cache,
14    candy_machine::{get_candy_machine_state, CANDY_MACHINE_ID},
15    common::*,
16    config::TokenStandard,
17    pdas::{find_candy_machine_creator_pda, find_metadata_pda, get_metadata_pda},
18    utils::*,
19};
20
21pub struct SetTokenStandardArgs {
22    pub keypair: Option<String>,
23    pub rpc_url: Option<String>,
24    pub cache: String,
25    pub token_standard: Option<TokenStandard>,
26    pub candy_machine: Option<String>,
27    pub rule_set: Option<String>,
28}
29
30pub fn process_set_token_stardard(args: SetTokenStandardArgs) -> Result<()> {
31    // validate that we got the required input
32    if args.token_standard.is_none() && args.rule_set.is_none() {
33        return Err(anyhow!(
34            "You need to specify a token standard and/or rule set."
35        ));
36    }
37
38    println!("[1/2] {}Loading candy machine", LOOKING_GLASS_EMOJI);
39
40    // the candy machine id specified takes precedence over the one from the cache
41
42    let candy_machine_id = if let Some(candy_machine) = args.candy_machine {
43        candy_machine
44    } else {
45        let cache = load_cache(&args.cache, false)?;
46        cache.program.candy_machine
47    };
48
49    if candy_machine_id.is_empty() {
50        return Err(anyhow!("Missing candy guard id."));
51    }
52
53    let candy_machine_id = match Pubkey::from_str(&candy_machine_id) {
54        Ok(candy_machine_id) => candy_machine_id,
55        Err(_) => {
56            let error = anyhow!("Failed to parse candy machine id: {}", candy_machine_id);
57            error!("{:?}", error);
58            return Err(error);
59        }
60    };
61
62    let sugar_config = sugar_setup(args.keypair, args.rpc_url)?;
63    let client = setup_client(&sugar_config)?;
64    let program = client.program(CANDY_MACHINE_ID);
65
66    let pb = spinner_with_style();
67    pb.set_message("Connecting...");
68
69    let candy_machine_state = get_candy_machine_state(&sugar_config, &candy_machine_id)?;
70
71    pb.finish_with_message("Done");
72
73    let message = if args.token_standard.is_some() {
74        if args.rule_set.is_some() {
75            "token standard and rule set"
76        } else {
77            "token standard"
78        }
79    } else {
80        "rule set"
81    };
82
83    println!("\n[2/2] {}Setting {}", WITHDRAW_EMOJI, message);
84
85    let pb = spinner_with_style();
86    pb.set_message("Connecting...");
87
88    let (authority_pda, _) = find_candy_machine_creator_pda(&candy_machine_id);
89    let collection_mint = candy_machine_state.collection_mint;
90    let collection_metadata = find_metadata_pda(&collection_mint);
91    let (_, collection_metadata_pda) =
92        get_metadata_pda(&candy_machine_state.collection_mint, &program)?;
93    let collection_update_authority = collection_metadata_pda.update_authority;
94
95    let collection_authority_record = if matches!(candy_machine_state.version, AccountVersion::V1) {
96        Some(find_collection_authority_account(&collection_mint, &authority_pda).0)
97    } else {
98        None
99    };
100
101    let collection_delegate_record = find_metadata_delegate_record_account(
102        &collection_mint,
103        MetadataDelegateRole::Collection,
104        &collection_update_authority,
105        &authority_pda,
106    )
107    .0;
108
109    // either uses the specified token standard or the existing one, for the case
110    // where only the rule set will be set
111    let token_standard = if let Some(token_standard) = args.token_standard {
112        <TokenStandard as std::convert::Into<mpl_token_metadata::state::TokenStandard>>::into(
113            token_standard,
114        ) as u8
115    } else {
116        candy_machine_state.token_standard
117    };
118
119    let payer = sugar_config.keypair;
120
121    let tx = program
122        .request()
123        .accounts(SetTokenStandard {
124            candy_machine: candy_machine_id,
125            authority_pda,
126            authority: payer.pubkey(),
127            payer: payer.pubkey(),
128            collection_metadata,
129            collection_mint,
130            collection_update_authority,
131            collection_authority_record,
132            collection_delegate_record,
133            rule_set: if let Some(rule_set) = args.rule_set {
134                Some(Pubkey::from_str(&rule_set)?)
135            } else {
136                None
137            },
138            system_program: system_program::ID,
139            sysvar_instructions: sysvar::instructions::ID,
140            token_metadata_program: mpl_token_metadata::ID,
141            authorization_rules_program: None,
142            authorization_rules: None,
143        })
144        .args(mpl_candy_machine_core::instruction::SetTokenStandard { token_standard });
145
146    let sig = tx.send()?;
147
148    pb.finish_and_clear();
149    println!("{} {}", style("Signature:").bold(), sig);
150
151    Ok(())
152}