sugar_cli/config/
guard_data.rs

1use anchor_lang::prelude::Pubkey;
2use anyhow::{anyhow, Result};
3use dateparser::DateTimeUtc;
4use serde::{Deserialize, Serialize};
5
6use super::{data::price_as_lamports, to_pubkey, to_string};
7
8#[derive(Serialize, Deserialize, Debug, Clone, Default)]
9pub struct CandyGuardData {
10    pub default: GuardSet,
11    pub groups: Option<Vec<Group>>,
12}
13
14impl CandyGuardData {
15    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::state::CandyGuardData> {
16        let groups = if let Some(groups) = &self.groups {
17            let mut group_vec = Vec::with_capacity(groups.len());
18
19            for group in groups {
20                group_vec.push(group.to_guard_format()?);
21            }
22
23            Some(group_vec)
24        } else {
25            None
26        };
27
28        Ok(mpl_candy_guard::state::CandyGuardData {
29            default: self.default.to_guard_format()?,
30            groups,
31        })
32    }
33}
34
35#[derive(Serialize, Deserialize, Debug, Clone, Default)]
36pub struct Group {
37    pub label: String,
38    pub guards: GuardSet,
39}
40
41impl Group {
42    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::state::Group> {
43        Ok(mpl_candy_guard::state::Group {
44            label: self.label.clone(),
45            guards: self.guards.to_guard_format()?,
46        })
47    }
48}
49
50/// The set of guards available.
51#[derive(Serialize, Deserialize, Debug, Clone, Default)]
52#[serde(rename_all = "camelCase")]
53pub struct GuardSet {
54    /// Last instruction check and bot tax (penalty for invalid transactions).
55    pub bot_tax: Option<BotTax>,
56    /// Sol payment guard (set the price for the mint in lamports).
57    pub sol_payment: Option<SolPayment>,
58    /// Token payment guard (set the price for the mint in spl-token amount).
59    pub token_payment: Option<TokenPayment>,
60    /// Start data guard (controls when minting is allowed).
61    pub start_date: Option<StartDate>,
62    /// Third party signer guard.
63    pub third_party_signer: Option<ThirdPartySigner>,
64    /// Token gate guard (restricrt access to holders of a specific token).
65    pub token_gate: Option<TokenGate>,
66    /// Gatekeeper guard
67    pub gatekeeper: Option<Gatekeeper>,
68    /// End date guard
69    pub end_date: Option<EndDate>,
70    /// Allow list guard
71    pub allow_list: Option<AllowList>,
72    /// Mint limit guard
73    pub mint_limit: Option<MintLimit>,
74    /// NFT Payment
75    pub nft_payment: Option<NftPayment>,
76    /// Redeemed amount guard
77    pub redeemed_amount: Option<RedeemedAmount>,
78    /// Address gate (check access against a specified address)
79    pub address_gate: Option<AddressGate>,
80    /// NFT gate guard (check access based on holding a specified NFT)
81    pub nft_gate: Option<NftGate>,
82    /// NFT burn guard (burn a specified NFT)
83    pub nft_burn: Option<NftBurn>,
84    /// Token burn guard (burn a specified amount of spl-token)
85    pub token_burn: Option<TokenBurn>,
86    /// Freeze sol payment guard (set the price for the mint in lamports with a freeze period).
87    pub freeze_sol_payment: Option<FreezeSolPayment>,
88    /// Freeze token payment guard (set the price for the mint in spl-token amount with a freeze period).
89    pub freeze_token_payment: Option<FreezeTokenPayment>,
90}
91
92impl GuardSet {
93    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::guards::GuardSet> {
94        // bot tax
95        let bot_tax = if let Some(bot_tax) = &self.bot_tax {
96            Some(bot_tax.to_guard_format()?)
97        } else {
98            None
99        };
100        // sol payment
101        let sol_payment = if let Some(sol_payment) = &self.sol_payment {
102            Some(sol_payment.to_guard_format()?)
103        } else {
104            None
105        };
106        // token payment
107        let token_payment = if let Some(token_payment) = &self.token_payment {
108            Some(token_payment.to_guard_format()?)
109        } else {
110            None
111        };
112        // start_date
113        let start_date = if let Some(start_date) = &self.start_date {
114            Some(start_date.to_guard_format()?)
115        } else {
116            None
117        };
118        // third party signer
119        let third_party_signer = if let Some(third_party_signer) = &self.third_party_signer {
120            Some(third_party_signer.to_guard_format()?)
121        } else {
122            None
123        };
124        // token gate
125        let token_gate = if let Some(token_gate) = &self.token_gate {
126            Some(token_gate.to_guard_format()?)
127        } else {
128            None
129        };
130        // gatekeeper
131        let gatekeeper = if let Some(gatekeeper) = &self.gatekeeper {
132            Some(gatekeeper.to_guard_format()?)
133        } else {
134            None
135        };
136        // end date
137        let end_date = if let Some(end_date) = &self.end_date {
138            Some(end_date.to_guard_format()?)
139        } else {
140            None
141        };
142        // allow list
143        let allow_list = if let Some(allow_list) = &self.allow_list {
144            Some(allow_list.to_guard_format()?)
145        } else {
146            None
147        };
148        // mint limit
149        let mint_limit = if let Some(mint_limit) = &self.mint_limit {
150            Some(mint_limit.to_guard_format()?)
151        } else {
152            None
153        };
154        // nft payment
155        let nft_payment = if let Some(nft_payment) = &self.nft_payment {
156            Some(nft_payment.to_guard_format()?)
157        } else {
158            None
159        };
160        // redeemed amount
161        let redeemed_amount = if let Some(redeemed_amount) = &self.redeemed_amount {
162            Some(redeemed_amount.to_guard_format()?)
163        } else {
164            None
165        };
166        // address gate
167        let address_gate = if let Some(address_gate) = &self.address_gate {
168            Some(address_gate.to_guard_format()?)
169        } else {
170            None
171        };
172        // nft gate
173        let nft_gate = if let Some(nft_gate) = &self.nft_gate {
174            Some(nft_gate.to_guard_format()?)
175        } else {
176            None
177        };
178        // nft burn
179        let nft_burn = if let Some(nft_burn) = &self.nft_burn {
180            Some(nft_burn.to_guard_format()?)
181        } else {
182            None
183        };
184        // token burn
185        let token_burn = if let Some(token_burn) = &self.token_burn {
186            Some(token_burn.to_guard_format()?)
187        } else {
188            None
189        };
190        // freeze sol payment
191        let freeze_sol_payment = if let Some(freeze_sol_payment) = &self.freeze_sol_payment {
192            Some(freeze_sol_payment.to_guard_format()?)
193        } else {
194            None
195        };
196        // freeze token payment
197        let freeze_token_payment = if let Some(freeze_token_payment) = &self.freeze_token_payment {
198            Some(freeze_token_payment.to_guard_format()?)
199        } else {
200            None
201        };
202
203        Ok(mpl_candy_guard::guards::GuardSet {
204            bot_tax,
205            sol_payment,
206            token_payment,
207            start_date,
208            third_party_signer,
209            token_gate,
210            gatekeeper,
211            end_date,
212            allow_list,
213            mint_limit,
214            nft_payment,
215            redeemed_amount,
216            address_gate,
217            nft_gate,
218            nft_burn,
219            token_burn,
220            freeze_sol_payment,
221            freeze_token_payment,
222            program_gate: None,
223            allocation: None,
224        })
225    }
226}
227
228// Address guard
229
230#[derive(Serialize, Deserialize, Debug, Clone, Default)]
231pub struct AddressGate {
232    #[serde(deserialize_with = "to_pubkey")]
233    #[serde(serialize_with = "to_string")]
234    pub address: Pubkey,
235}
236
237impl AddressGate {
238    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::guards::AddressGate> {
239        Ok(mpl_candy_guard::guards::AddressGate {
240            address: self.address,
241        })
242    }
243}
244
245// Alow List guard
246
247#[derive(Serialize, Deserialize, Debug, Clone, Default)]
248#[serde(rename_all = "camelCase")]
249pub struct AllowList {
250    pub merkle_root: String,
251}
252
253impl AllowList {
254    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::guards::AllowList> {
255        let root: [u8; 32] = hex::decode(&self.merkle_root)?
256            .try_into()
257            .map_err(|_| anyhow!("Invalid merkle root value: {}", self.merkle_root))?;
258        Ok(mpl_candy_guard::guards::AllowList { merkle_root: root })
259    }
260}
261
262// Bot Tax guard
263
264#[derive(Serialize, Deserialize, Debug, Clone, Default)]
265#[serde(rename_all = "camelCase")]
266pub struct BotTax {
267    pub value: f64,
268
269    pub last_instruction: bool,
270}
271
272impl BotTax {
273    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::guards::BotTax> {
274        Ok(mpl_candy_guard::guards::BotTax {
275            lamports: price_as_lamports(self.value),
276            last_instruction: self.last_instruction,
277        })
278    }
279}
280
281// End Date guard
282
283#[derive(Serialize, Deserialize, Debug, Clone, Default)]
284pub struct EndDate {
285    pub date: String,
286}
287
288impl EndDate {
289    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::guards::EndDate> {
290        let timestamp = self.date.parse::<DateTimeUtc>()?.0.timestamp();
291
292        Ok(mpl_candy_guard::guards::EndDate { date: timestamp })
293    }
294}
295
296// Gatekeeper guard
297
298#[derive(Serialize, Deserialize, Debug, Clone, Default)]
299#[serde(rename_all = "camelCase")]
300pub struct Gatekeeper {
301    #[serde(deserialize_with = "to_pubkey")]
302    #[serde(serialize_with = "to_string")]
303    pub gatekeeper_network: Pubkey,
304
305    pub expire_on_use: bool,
306}
307
308impl Gatekeeper {
309    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::guards::Gatekeeper> {
310        Ok(mpl_candy_guard::guards::Gatekeeper {
311            gatekeeper_network: self.gatekeeper_network,
312            expire_on_use: self.expire_on_use,
313        })
314    }
315}
316
317// Mint Limit guard
318
319#[derive(Serialize, Deserialize, Debug, Clone, Default)]
320pub struct MintLimit {
321    pub id: u8,
322
323    pub limit: u16,
324}
325
326impl MintLimit {
327    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::guards::MintLimit> {
328        Ok(mpl_candy_guard::guards::MintLimit {
329            id: self.id,
330            limit: self.limit,
331        })
332    }
333}
334
335// Nft Burn guard
336
337#[derive(Serialize, Deserialize, Debug, Clone, Default)]
338#[serde(rename_all = "camelCase")]
339pub struct NftBurn {
340    #[serde(deserialize_with = "to_pubkey")]
341    #[serde(serialize_with = "to_string")]
342    pub required_collection: Pubkey,
343}
344
345impl NftBurn {
346    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::guards::NftBurn> {
347        Ok(mpl_candy_guard::guards::NftBurn {
348            required_collection: self.required_collection,
349        })
350    }
351}
352
353// Nft Gate guard
354
355#[derive(Serialize, Deserialize, Debug, Clone, Default)]
356#[serde(rename_all = "camelCase")]
357pub struct NftGate {
358    #[serde(deserialize_with = "to_pubkey")]
359    #[serde(serialize_with = "to_string")]
360    pub required_collection: Pubkey,
361}
362
363impl NftGate {
364    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::guards::NftGate> {
365        Ok(mpl_candy_guard::guards::NftGate {
366            required_collection: self.required_collection,
367        })
368    }
369}
370
371// Nft Payment guard
372
373#[derive(Serialize, Deserialize, Debug, Clone, Default)]
374#[serde(rename_all = "camelCase")]
375pub struct NftPayment {
376    #[serde(deserialize_with = "to_pubkey")]
377    #[serde(serialize_with = "to_string")]
378    pub required_collection: Pubkey,
379
380    #[serde(deserialize_with = "to_pubkey")]
381    #[serde(serialize_with = "to_string")]
382    pub destination: Pubkey,
383}
384
385impl NftPayment {
386    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::guards::NftPayment> {
387        Ok(mpl_candy_guard::guards::NftPayment {
388            required_collection: self.required_collection,
389            destination: self.destination,
390        })
391    }
392}
393
394// Redeemed Amount guard
395
396#[derive(Serialize, Deserialize, Debug, Clone, Default)]
397pub struct RedeemedAmount {
398    pub maximum: u64,
399}
400
401impl RedeemedAmount {
402    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::guards::RedeemedAmount> {
403        Ok(mpl_candy_guard::guards::RedeemedAmount {
404            maximum: self.maximum,
405        })
406    }
407}
408
409// Sol Payment guard
410
411#[derive(Serialize, Deserialize, Debug, Clone, Default)]
412pub struct SolPayment {
413    pub value: f64,
414
415    #[serde(deserialize_with = "to_pubkey")]
416    #[serde(serialize_with = "to_string")]
417    pub destination: Pubkey,
418}
419
420impl SolPayment {
421    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::guards::SolPayment> {
422        Ok(mpl_candy_guard::guards::SolPayment {
423            lamports: price_as_lamports(self.value),
424            destination: self.destination,
425        })
426    }
427}
428
429#[derive(Serialize, Deserialize, Debug, Clone, Default)]
430pub struct StartDate {
431    pub date: String,
432}
433
434impl StartDate {
435    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::guards::StartDate> {
436        let timestamp = self.date.parse::<DateTimeUtc>()?.0.timestamp();
437        Ok(mpl_candy_guard::guards::StartDate { date: timestamp })
438    }
439}
440
441// Third Party Signer guard
442
443#[derive(Serialize, Deserialize, Debug, Clone, Default)]
444#[serde(rename_all = "camelCase")]
445pub struct ThirdPartySigner {
446    #[serde(deserialize_with = "to_pubkey")]
447    #[serde(serialize_with = "to_string")]
448    pub signer_key: Pubkey,
449}
450
451impl ThirdPartySigner {
452    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::guards::ThirdPartySigner> {
453        Ok(mpl_candy_guard::guards::ThirdPartySigner {
454            signer_key: self.signer_key,
455        })
456    }
457}
458
459// Token Burn guard
460
461#[derive(Serialize, Deserialize, Debug, Clone, Default)]
462pub struct TokenBurn {
463    pub amount: u64,
464
465    #[serde(deserialize_with = "to_pubkey")]
466    #[serde(serialize_with = "to_string")]
467    pub mint: Pubkey,
468}
469
470impl TokenBurn {
471    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::guards::TokenBurn> {
472        Ok(mpl_candy_guard::guards::TokenBurn {
473            amount: self.amount,
474            mint: self.mint,
475        })
476    }
477}
478
479// Token Gate guard
480
481#[derive(Serialize, Deserialize, Debug, Clone, Default)]
482pub struct TokenGate {
483    pub amount: u64,
484
485    #[serde(deserialize_with = "to_pubkey")]
486    #[serde(serialize_with = "to_string")]
487    pub mint: Pubkey,
488}
489
490impl TokenGate {
491    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::guards::TokenGate> {
492        Ok(mpl_candy_guard::guards::TokenGate {
493            amount: self.amount,
494            mint: self.mint,
495        })
496    }
497}
498
499// Token Payment guard
500
501#[derive(Serialize, Deserialize, Debug, Clone, Default)]
502#[serde(rename_all = "camelCase")]
503pub struct TokenPayment {
504    pub amount: u64,
505
506    #[serde(deserialize_with = "to_pubkey")]
507    #[serde(serialize_with = "to_string")]
508    pub mint: Pubkey,
509
510    #[serde(deserialize_with = "to_pubkey")]
511    #[serde(serialize_with = "to_string")]
512    pub destination_ata: Pubkey,
513}
514
515impl TokenPayment {
516    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::guards::TokenPayment> {
517        Ok(mpl_candy_guard::guards::TokenPayment {
518            amount: self.amount,
519            mint: self.mint,
520            destination_ata: self.destination_ata,
521        })
522    }
523}
524
525// Freeze Sol Payment guard
526
527#[derive(Serialize, Deserialize, Debug, Clone, Default)]
528#[serde(rename_all = "camelCase")]
529pub struct FreezeSolPayment {
530    pub value: f64,
531
532    #[serde(deserialize_with = "to_pubkey")]
533    #[serde(serialize_with = "to_string")]
534    pub destination: Pubkey,
535}
536
537impl FreezeSolPayment {
538    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::guards::FreezeSolPayment> {
539        Ok(mpl_candy_guard::guards::FreezeSolPayment {
540            lamports: price_as_lamports(self.value),
541            destination: self.destination,
542        })
543    }
544}
545
546// Freeze Token Payment guard
547
548#[derive(Serialize, Deserialize, Debug, Clone, Default)]
549#[serde(rename_all = "camelCase")]
550pub struct FreezeTokenPayment {
551    pub amount: u64,
552
553    #[serde(deserialize_with = "to_pubkey")]
554    #[serde(serialize_with = "to_string")]
555    pub mint: Pubkey,
556
557    #[serde(deserialize_with = "to_pubkey")]
558    #[serde(serialize_with = "to_string")]
559    pub destination_ata: Pubkey,
560}
561
562impl FreezeTokenPayment {
563    pub fn to_guard_format(&self) -> Result<mpl_candy_guard::guards::FreezeTokenPayment> {
564        Ok(mpl_candy_guard::guards::FreezeTokenPayment {
565            amount: self.amount,
566            mint: self.mint,
567            destination_ata: self.destination_ata,
568        })
569    }
570}