1use std::str::FromStr;
2
3use anchor_client::solana_sdk::pubkey::Pubkey;
4use anyhow::Result;
5use console::style;
6use mpl_candy_guard::{
7 accounts::{Initialize as InitializeAccount, Update as UpdateAccount, Wrap as WrapAccount},
8 instruction::{Initialize, Update, Wrap},
9};
10use mpl_candy_machine_core::constants::EMPTY_STR;
11
12use crate::{cache::load_cache, candy_machine::*, common::*, config::get_config_data, utils::*};
13
14pub struct GuardAddArgs {
15 pub keypair: Option<String>,
16 pub rpc_url: Option<String>,
17 pub cache: String,
18 pub config: String,
19 pub candy_machine: Option<String>,
20 pub candy_guard: Option<String>,
21}
22
23pub fn process_guard_add(args: GuardAddArgs) -> Result<()> {
24 println!("[1/3] {}Looking up candy machine", LOOKING_GLASS_EMOJI);
25
26 let pb = spinner_with_style();
27 pb.set_message("Connecting...");
28
29 let (candy_machine_id, cache) = if let Some(candy_machine) = args.candy_machine {
32 (candy_machine, None)
33 } else {
34 let cache = load_cache(&args.cache, false)?;
35 (cache.program.candy_machine.clone(), Some(cache))
36 };
37
38 if candy_machine_id.is_empty() {
39 return Err(anyhow!("Missing candy machine id."));
40 }
41
42 let candy_machine_id = match Pubkey::from_str(&candy_machine_id) {
43 Ok(candy_machine_id) => candy_machine_id,
44 Err(_) => {
45 let error = anyhow!("Failed to parse candy machine id: {}", candy_machine_id);
46 error!("{:?}", error);
47 return Err(error);
48 }
49 };
50
51 pb.finish_and_clear();
52
53 println!(
54 "\n{} {}",
55 style("Candy machine ID:").bold(),
56 candy_machine_id
57 );
58
59 let candy_guard_id = if let Some(candy_guard) = args.candy_guard {
62 candy_guard
63 } else if let Some(ref cache) = cache {
64 cache.program.candy_guard.clone()
65 } else {
66 EMPTY_STR.to_string()
67 };
68
69 let sugar_config = sugar_setup(args.keypair, args.rpc_url)?;
70 let config_data = get_config_data(&args.config)?;
71 let client = setup_client(&sugar_config)?;
72 let payer = sugar_config.keypair;
73 let program = client.program(mpl_candy_guard::ID);
74
75 let candy_guard = if candy_guard_id.is_empty() {
76 println!("\n[2/3] {}Initializing a candy guard", GUARD_EMOJI);
77 let pb = spinner_with_style();
78 pb.set_message("Initializing...");
79
80 let data = if let Some(guards) = &config_data.guards {
81 guards.to_guard_format()?
82 } else {
83 return Err(anyhow!("Missing guards configuration."));
84 };
85
86 let base = Keypair::new();
87 let (candy_guard, _) = Pubkey::find_program_address(
88 &[b"candy_guard", base.pubkey().as_ref()],
89 &mpl_candy_guard::ID,
90 );
91
92 let mut serialized_data = vec![0; data.size()];
93 data.save(&mut serialized_data)?;
94
95 let tx = program
96 .request()
97 .accounts(InitializeAccount {
98 candy_guard,
99 base: base.pubkey(),
100 authority: payer.pubkey(),
101 payer: payer.pubkey(),
102 system_program: system_program::id(),
103 })
104 .args(Initialize {
105 data: serialized_data,
106 })
107 .signer(&base);
108
109 let sig = tx.send()?;
110
111 pb.finish_and_clear();
112 println!("{} {}", style("Signature:").bold(), sig);
113
114 candy_guard
115 } else {
116 println!("\n[2/3] {}Loading candy guard", COMPUTER_EMOJI);
117
118 let candy_guard_id = match Pubkey::from_str(&candy_guard_id) {
119 Ok(candy_guard_id) => candy_guard_id,
120 Err(_) => {
121 let error = anyhow!("Failed to parse candy guard id: {}", candy_guard_id);
122 error!("{:?}", error);
123 return Err(error);
124 }
125 };
126
127 let pb = spinner_with_style();
128 pb.set_message("Connecting...");
129
130 let _candy_guard = program.rpc().get_account(&candy_guard_id)?;
132
133 let data = if let Some(guards) = &config_data.guards {
134 guards.to_guard_format()?
135 } else {
136 return Err(anyhow!("Missing guards configuration."));
137 };
138
139 let mut serialized_data = vec![0; data.size()];
140 data.save(&mut serialized_data)?;
141 println!("\n{}\n", serialized_data.len());
142
143 let tx = program
145 .request()
146 .accounts(UpdateAccount {
147 candy_guard: candy_guard_id,
148 authority: payer.pubkey(),
149 payer: payer.pubkey(),
150 system_program: system_program::ID,
151 })
152 .args(Update {
153 data: serialized_data,
154 });
155
156 tx.send()?;
157
158 pb.finish_with_message("Done");
159
160 candy_guard_id
161 };
162
163 println!("\n{} {}", style("Candy guard ID:").bold(), candy_guard);
164
165 println!("\n[3/3] {}Wrapping", WRAP_EMOJI);
168
169 let pb = spinner_with_style();
170 pb.set_message("Connecting...");
171
172 let tx = program
173 .request()
174 .accounts(WrapAccount {
175 candy_guard,
176 authority: payer.pubkey(),
177 candy_machine: candy_machine_id,
178 candy_machine_program: CANDY_MACHINE_ID,
179 candy_machine_authority: payer.pubkey(),
180 })
181 .args(Wrap {});
182
183 let sig = tx.send()?;
184
185 pb.finish_and_clear();
186 println!("{} {}", style("Signature:").bold(), sig);
187
188 println!("\nThe candy guard is now the mint authority of the candy machine.");
189
190 if cache.is_some() {
194 let mut cache = load_cache(&args.cache, false)?;
195 cache.program.candy_guard = candy_guard.to_string();
196 cache.sync_file()?;
197 }
198
199 Ok(())
200}