1mod accessors;
2
3use crate::balances::credits::TokenAmount;
4use crate::data_contract::associated_token::token_configuration_convention::v0::TokenConfigurationConventionV0;
5use crate::data_contract::associated_token::token_configuration_convention::TokenConfigurationConvention;
6use crate::data_contract::associated_token::token_distribution_rules::v0::TokenDistributionRulesV0;
7use crate::data_contract::associated_token::token_distribution_rules::TokenDistributionRules;
8use crate::data_contract::associated_token::token_keeps_history_rules::v0::TokenKeepsHistoryRulesV0;
9use crate::data_contract::associated_token::token_keeps_history_rules::TokenKeepsHistoryRules;
10use crate::data_contract::associated_token::token_marketplace_rules::v0::{
11 TokenMarketplaceRulesV0, TokenTradeMode,
12};
13use crate::data_contract::associated_token::token_marketplace_rules::TokenMarketplaceRules;
14use crate::data_contract::associated_token::token_perpetual_distribution::TokenPerpetualDistribution;
15use crate::data_contract::associated_token::token_pre_programmed_distribution::TokenPreProgrammedDistribution;
16use crate::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers;
17use crate::data_contract::change_control_rules::v0::ChangeControlRulesV0;
18use crate::data_contract::change_control_rules::ChangeControlRules;
19use crate::data_contract::GroupContractPosition;
20#[cfg(feature = "json-conversion")]
21use crate::serialization::json_safe_fields;
22use bincode::{Decode, DecodeUntrusted, Encode};
23use serde::{Deserialize, Serialize};
24use std::fmt;
25
26#[cfg_attr(feature = "json-conversion", json_safe_fields)]
36#[derive(Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq, Eq, DecodeUntrusted)]
37#[serde(rename_all = "camelCase")]
38pub struct TokenConfigurationV0 {
39 pub conventions: TokenConfigurationConvention,
41
42 #[serde(default = "default_change_control_rules")]
44 pub conventions_change_rules: ChangeControlRules,
45
46 #[serde(default)]
48 pub base_supply: TokenAmount,
49
50 #[serde(default)]
54 pub max_supply: Option<TokenAmount>,
55
56 #[serde(default = "default_token_keeps_history_rules")]
58 pub keeps_history: TokenKeepsHistoryRules,
59
60 #[serde(default = "default_starts_as_paused")]
64 pub start_as_paused: bool,
65
66 #[serde(default = "default_allow_transfer_to_frozen_balance")]
68 pub allow_transfer_to_frozen_balance: bool,
69
70 #[serde(default = "default_change_control_rules")]
74 pub max_supply_change_rules: ChangeControlRules,
75
76 #[serde(default = "default_token_distribution_rules")]
78 pub distribution_rules: TokenDistributionRules,
79
80 #[serde(default = "default_token_marketplace_rules")]
82 pub marketplace_rules: TokenMarketplaceRules,
83
84 #[serde(default = "default_contract_owner_change_control_rules")]
86 pub manual_minting_rules: ChangeControlRules,
87
88 #[serde(default = "default_contract_owner_change_control_rules")]
90 pub manual_burning_rules: ChangeControlRules,
91
92 #[serde(default = "default_change_control_rules")]
94 pub freeze_rules: ChangeControlRules,
95
96 #[serde(default = "default_change_control_rules")]
98 pub unfreeze_rules: ChangeControlRules,
99
100 #[serde(default = "default_change_control_rules")]
102 pub destroy_frozen_funds_rules: ChangeControlRules,
103
104 #[serde(default = "default_change_control_rules")]
106 pub emergency_action_rules: ChangeControlRules,
107
108 #[serde(default)]
110 pub main_control_group: Option<GroupContractPosition>,
111
112 #[serde(default)]
114 pub main_control_group_can_be_modified: AuthorizedActionTakers,
115
116 #[serde(default)]
118 pub description: Option<String>,
119}
120
121fn default_keeps_history() -> bool {
123 true }
125
126fn default_starts_as_paused() -> bool {
128 false
129}
130
131fn default_allow_transfer_to_frozen_balance() -> bool {
133 true
134}
135
136fn default_token_keeps_history_rules() -> TokenKeepsHistoryRules {
137 TokenKeepsHistoryRules::V0(TokenKeepsHistoryRulesV0 {
138 keeps_transfer_history: true,
139 keeps_freezing_history: true,
140 keeps_minting_history: true,
141 keeps_burning_history: true,
142 keeps_direct_pricing_history: true,
143 keeps_direct_purchase_history: true,
144 })
145}
146
147fn default_token_distribution_rules() -> TokenDistributionRules {
148 TokenDistributionRules::V0(TokenDistributionRulesV0 {
149 perpetual_distribution: None,
150 perpetual_distribution_rules: ChangeControlRules::V0(ChangeControlRulesV0 {
151 authorized_to_make_change: AuthorizedActionTakers::NoOne,
152 admin_action_takers: AuthorizedActionTakers::NoOne,
153 changing_authorized_action_takers_to_no_one_allowed: false,
154 changing_admin_action_takers_to_no_one_allowed: false,
155 self_changing_admin_action_takers_allowed: false,
156 }),
157 pre_programmed_distribution: None,
158 new_tokens_destination_identity: None,
159 new_tokens_destination_identity_rules: ChangeControlRules::V0(ChangeControlRulesV0 {
160 authorized_to_make_change: AuthorizedActionTakers::NoOne,
161 admin_action_takers: AuthorizedActionTakers::NoOne,
162 changing_authorized_action_takers_to_no_one_allowed: false,
163 changing_admin_action_takers_to_no_one_allowed: false,
164 self_changing_admin_action_takers_allowed: false,
165 }),
166 minting_allow_choosing_destination: true,
167 minting_allow_choosing_destination_rules: ChangeControlRules::V0(ChangeControlRulesV0 {
168 authorized_to_make_change: AuthorizedActionTakers::NoOne,
169 admin_action_takers: AuthorizedActionTakers::NoOne,
170 changing_authorized_action_takers_to_no_one_allowed: false,
171 changing_admin_action_takers_to_no_one_allowed: false,
172 self_changing_admin_action_takers_allowed: false,
173 }),
174 change_direct_purchase_pricing_rules: ChangeControlRules::V0(ChangeControlRulesV0 {
175 authorized_to_make_change: AuthorizedActionTakers::NoOne,
176 admin_action_takers: AuthorizedActionTakers::NoOne,
177 changing_authorized_action_takers_to_no_one_allowed: false,
178 changing_admin_action_takers_to_no_one_allowed: false,
179 self_changing_admin_action_takers_allowed: false,
180 }),
181 })
182}
183
184fn default_token_marketplace_rules() -> TokenMarketplaceRules {
185 TokenMarketplaceRules::V0(TokenMarketplaceRulesV0 {
186 trade_mode: TokenTradeMode::NotTradeable,
187 trade_mode_change_rules: ChangeControlRules::V0(ChangeControlRulesV0 {
188 authorized_to_make_change: AuthorizedActionTakers::NoOne,
189 admin_action_takers: AuthorizedActionTakers::NoOne,
190 changing_authorized_action_takers_to_no_one_allowed: false,
191 changing_admin_action_takers_to_no_one_allowed: false,
192 self_changing_admin_action_takers_allowed: false,
193 }),
194 })
195}
196
197fn default_change_control_rules() -> ChangeControlRules {
198 ChangeControlRules::V0(ChangeControlRulesV0 {
199 authorized_to_make_change: AuthorizedActionTakers::NoOne,
200 admin_action_takers: AuthorizedActionTakers::NoOne,
201 changing_authorized_action_takers_to_no_one_allowed: false,
202 changing_admin_action_takers_to_no_one_allowed: false,
203 self_changing_admin_action_takers_allowed: false,
204 })
205}
206
207fn default_contract_owner_change_control_rules() -> ChangeControlRules {
208 ChangeControlRules::V0(ChangeControlRulesV0 {
209 authorized_to_make_change: AuthorizedActionTakers::ContractOwner,
210 admin_action_takers: AuthorizedActionTakers::NoOne,
211 changing_authorized_action_takers_to_no_one_allowed: false,
212 changing_admin_action_takers_to_no_one_allowed: false,
213 self_changing_admin_action_takers_allowed: false,
214 })
215}
216
217impl fmt::Display for TokenConfigurationV0 {
218 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219 write!(
220 f,
221 "TokenConfigurationV0 {{\n conventions: {:?},\n conventions_change_rules: {:?},\n base_supply: {},\n max_supply: {:?},\n keeps_history: {},\n start_as_paused: {},\n allow_transfer_to_frozen_balance: {},\n max_supply_change_rules: {:?},\n distribution_rules: {},\n manual_minting_rules: {:?},\n manual_burning_rules: {:?},\n freeze_rules: {:?},\n unfreeze_rules: {:?},\n destroy_frozen_funds_rules: {:?},\n emergency_action_rules: {:?},\n main_control_group: {:?},\n main_control_group_can_be_modified: {:?}\n}}",
222 self.conventions,
223 self.conventions_change_rules,
224 self.base_supply,
225 self.max_supply,
226 self.keeps_history,
227 self.start_as_paused,
228 self.allow_transfer_to_frozen_balance,
229 self.max_supply_change_rules,
230 self.distribution_rules,
231 self.manual_minting_rules,
232 self.manual_burning_rules,
233 self.freeze_rules,
234 self.unfreeze_rules,
235 self.destroy_frozen_funds_rules,
236 self.emergency_action_rules,
237 self.main_control_group,
238 self.main_control_group_can_be_modified
239 )
240 }
241}
242
243#[derive(
252 Serialize,
253 Deserialize,
254 Decode,
255 Encode,
256 Debug,
257 Clone,
258 Copy,
259 PartialEq,
260 Eq,
261 PartialOrd,
262 DecodeUntrusted,
263)]
264pub enum TokenConfigurationPresetFeatures {
265 MostRestrictive,
270
271 WithOnlyEmergencyAction,
277
278 WithMintingAndBurningActions,
282
283 WithAllAdvancedActions,
288
289 WithExtremeActions,
296}
297
298#[derive(
308 Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq, Eq, PartialOrd, DecodeUntrusted,
309)]
310#[serde(rename_all = "camelCase")]
311pub struct TokenConfigurationPreset {
312 pub features: TokenConfigurationPresetFeatures,
318
319 pub action_taker: AuthorizedActionTakers,
324}
325
326#[cfg(all(feature = "json-conversion", feature = "serde-conversion"))]
328impl crate::serialization::JsonConvertible for TokenConfigurationPresetFeatures {}
329
330#[cfg(all(feature = "value-conversion", feature = "serde-conversion"))]
331impl crate::serialization::ValueConvertible for TokenConfigurationPresetFeatures {}
332
333#[cfg(all(feature = "json-conversion", feature = "serde-conversion"))]
334impl crate::serialization::JsonConvertible for TokenConfigurationPreset {}
335
336#[cfg(all(feature = "value-conversion", feature = "serde-conversion"))]
337impl crate::serialization::ValueConvertible for TokenConfigurationPreset {}
338
339#[cfg(all(
340 test,
341 feature = "json-conversion",
342 feature = "value-conversion",
343 feature = "serde-conversion"
344))]
345mod json_convertible_tests_preset {
346 use super::*;
347 use crate::serialization::{JsonConvertible, ValueConvertible};
348 use platform_value::platform_value;
349 use serde_json::json;
350
351 fn fixture() -> TokenConfigurationPreset {
352 TokenConfigurationPreset {
353 features: TokenConfigurationPresetFeatures::WithAllAdvancedActions,
354 action_taker: AuthorizedActionTakers::Group(7),
355 }
356 }
357
358 #[test]
359 fn preset_json_round_trip_with_full_wire_shape() {
360 let original = fixture();
361 let json = original.to_json().expect("to_json");
362 assert_eq!(
366 json,
367 json!({
368 "features": "WithAllAdvancedActions",
369 "actionTaker": {"$type": "group", "position": 7},
370 })
371 );
372 let recovered = TokenConfigurationPreset::from_json(json).expect("from_json");
373 assert_eq!(original, recovered);
374 }
375
376 #[test]
377 fn preset_value_round_trip_with_full_wire_shape() {
378 let original = fixture();
379 let value = original.to_object().expect("to_object");
380 assert_eq!(
381 value,
382 platform_value!({
383 "features": "WithAllAdvancedActions",
384 "actionTaker": {"$type": "group", "position": 7u16},
385 })
386 );
387 let recovered = TokenConfigurationPreset::from_object(value).expect("from_object");
388 assert_eq!(original, recovered);
389 }
390
391 #[test]
392 fn preset_features_round_trips_all_variants() {
393 let cases = [
394 (
395 TokenConfigurationPresetFeatures::MostRestrictive,
396 "MostRestrictive",
397 ),
398 (
399 TokenConfigurationPresetFeatures::WithOnlyEmergencyAction,
400 "WithOnlyEmergencyAction",
401 ),
402 (
403 TokenConfigurationPresetFeatures::WithMintingAndBurningActions,
404 "WithMintingAndBurningActions",
405 ),
406 (
407 TokenConfigurationPresetFeatures::WithAllAdvancedActions,
408 "WithAllAdvancedActions",
409 ),
410 (
411 TokenConfigurationPresetFeatures::WithExtremeActions,
412 "WithExtremeActions",
413 ),
414 ];
415 for (original, expected) in cases {
416 let json_v = original.to_json().expect("to_json");
417 assert_eq!(json_v, json!(expected));
418 assert_eq!(
419 TokenConfigurationPresetFeatures::from_json(json_v).expect("from_json"),
420 original
421 );
422 let value = original.to_object().expect("to_object");
423 assert_eq!(value, platform_value!(expected));
424 assert_eq!(
425 TokenConfigurationPresetFeatures::from_object(value).expect("from_object"),
426 original
427 );
428 }
429 }
430}
431
432impl TokenConfigurationPreset {
433 pub fn default_main_control_group_can_be_modified(&self) -> AuthorizedActionTakers {
434 match self.features {
435 TokenConfigurationPresetFeatures::MostRestrictive
436 | TokenConfigurationPresetFeatures::WithOnlyEmergencyAction
437 | TokenConfigurationPresetFeatures::WithMintingAndBurningActions
438 | TokenConfigurationPresetFeatures::WithAllAdvancedActions => {
439 AuthorizedActionTakers::NoOne
440 }
441 TokenConfigurationPresetFeatures::WithExtremeActions => self.action_taker,
442 }
443 }
444 pub fn default_basic_change_control_rules_v0(&self) -> ChangeControlRulesV0 {
445 match self.features {
446 TokenConfigurationPresetFeatures::MostRestrictive
447 | TokenConfigurationPresetFeatures::WithOnlyEmergencyAction => ChangeControlRulesV0 {
448 authorized_to_make_change: AuthorizedActionTakers::NoOne,
449 admin_action_takers: AuthorizedActionTakers::NoOne,
450 changing_authorized_action_takers_to_no_one_allowed: false,
451 changing_admin_action_takers_to_no_one_allowed: false,
452 self_changing_admin_action_takers_allowed: false,
453 },
454 TokenConfigurationPresetFeatures::WithMintingAndBurningActions
455 | TokenConfigurationPresetFeatures::WithAllAdvancedActions => ChangeControlRulesV0 {
456 authorized_to_make_change: self.action_taker,
457 admin_action_takers: self.action_taker,
458 changing_authorized_action_takers_to_no_one_allowed: false,
459 changing_admin_action_takers_to_no_one_allowed: false,
460 self_changing_admin_action_takers_allowed: true,
461 },
462 TokenConfigurationPresetFeatures::WithExtremeActions => ChangeControlRulesV0 {
463 authorized_to_make_change: self.action_taker,
464 admin_action_takers: self.action_taker,
465 changing_authorized_action_takers_to_no_one_allowed: true,
466 changing_admin_action_takers_to_no_one_allowed: true,
467 self_changing_admin_action_takers_allowed: true,
468 },
469 }
470 }
471
472 pub fn default_advanced_change_control_rules_v0(&self) -> ChangeControlRulesV0 {
473 match self.features {
474 TokenConfigurationPresetFeatures::MostRestrictive
475 | TokenConfigurationPresetFeatures::WithOnlyEmergencyAction
476 | TokenConfigurationPresetFeatures::WithMintingAndBurningActions => {
477 ChangeControlRulesV0 {
478 authorized_to_make_change: AuthorizedActionTakers::NoOne,
479 admin_action_takers: AuthorizedActionTakers::NoOne,
480 changing_authorized_action_takers_to_no_one_allowed: false,
481 changing_admin_action_takers_to_no_one_allowed: false,
482 self_changing_admin_action_takers_allowed: false,
483 }
484 }
485 TokenConfigurationPresetFeatures::WithAllAdvancedActions => ChangeControlRulesV0 {
486 authorized_to_make_change: self.action_taker,
487 admin_action_takers: self.action_taker,
488 changing_authorized_action_takers_to_no_one_allowed: false,
489 changing_admin_action_takers_to_no_one_allowed: false,
490 self_changing_admin_action_takers_allowed: true,
491 },
492 TokenConfigurationPresetFeatures::WithExtremeActions => ChangeControlRulesV0 {
493 authorized_to_make_change: self.action_taker,
494 admin_action_takers: self.action_taker,
495 changing_authorized_action_takers_to_no_one_allowed: true,
496 changing_admin_action_takers_to_no_one_allowed: true,
497 self_changing_admin_action_takers_allowed: true,
498 },
499 }
500 }
501
502 pub fn default_emergency_action_change_control_rules_v0(&self) -> ChangeControlRulesV0 {
503 match self.features {
504 TokenConfigurationPresetFeatures::MostRestrictive => ChangeControlRulesV0 {
505 authorized_to_make_change: AuthorizedActionTakers::NoOne,
506 admin_action_takers: AuthorizedActionTakers::NoOne,
507 changing_authorized_action_takers_to_no_one_allowed: false,
508 changing_admin_action_takers_to_no_one_allowed: false,
509 self_changing_admin_action_takers_allowed: false,
510 },
511 TokenConfigurationPresetFeatures::WithAllAdvancedActions
512 | TokenConfigurationPresetFeatures::WithMintingAndBurningActions
513 | TokenConfigurationPresetFeatures::WithOnlyEmergencyAction => ChangeControlRulesV0 {
514 authorized_to_make_change: self.action_taker,
515 admin_action_takers: self.action_taker,
516 changing_authorized_action_takers_to_no_one_allowed: false,
517 changing_admin_action_takers_to_no_one_allowed: false,
518 self_changing_admin_action_takers_allowed: true,
519 },
520 TokenConfigurationPresetFeatures::WithExtremeActions => ChangeControlRulesV0 {
521 authorized_to_make_change: self.action_taker,
522 admin_action_takers: self.action_taker,
523 changing_authorized_action_takers_to_no_one_allowed: true,
524 changing_admin_action_takers_to_no_one_allowed: true,
525 self_changing_admin_action_takers_allowed: true,
526 },
527 }
528 }
529
530 pub fn default_distribution_rules_v0(
531 &self,
532 perpetual_distribution: Option<TokenPerpetualDistribution>,
533 pre_programmed_distribution: Option<TokenPreProgrammedDistribution>,
534 with_direct_pricing: bool,
535 ) -> TokenDistributionRulesV0 {
536 TokenDistributionRulesV0 {
537 perpetual_distribution,
538 perpetual_distribution_rules: self.default_advanced_change_control_rules_v0().into(),
539 pre_programmed_distribution,
540 new_tokens_destination_identity: None,
541 new_tokens_destination_identity_rules: self
542 .default_basic_change_control_rules_v0()
543 .into(),
544 minting_allow_choosing_destination: true,
545 minting_allow_choosing_destination_rules: self
546 .default_basic_change_control_rules_v0()
547 .into(),
548 change_direct_purchase_pricing_rules: if with_direct_pricing {
549 self.default_basic_change_control_rules_v0().into()
550 } else {
551 ChangeControlRulesV0 {
552 authorized_to_make_change: AuthorizedActionTakers::NoOne,
553 admin_action_takers: AuthorizedActionTakers::NoOne,
554 changing_authorized_action_takers_to_no_one_allowed: false,
555 changing_admin_action_takers_to_no_one_allowed: false,
556 self_changing_admin_action_takers_allowed: false,
557 }
558 .into()
559 },
560 }
561 }
562
563 pub fn default_marketplace_rules_v0(&self) -> TokenMarketplaceRulesV0 {
564 TokenMarketplaceRulesV0 {
565 trade_mode: TokenTradeMode::NotTradeable,
566 trade_mode_change_rules: self.default_basic_change_control_rules_v0().into(),
567 }
568 }
569
570 pub fn token_configuration_v0(
571 &self,
572 conventions: TokenConfigurationConvention,
573 base_supply: TokenAmount,
574 max_supply: Option<TokenAmount>,
575 keeps_all_history: bool,
576 with_direct_pricing: bool,
577 ) -> TokenConfigurationV0 {
578 TokenConfigurationV0 {
579 conventions,
580 conventions_change_rules: self.default_basic_change_control_rules_v0().into(),
581 base_supply,
582 max_supply,
583 keeps_history: TokenKeepsHistoryRulesV0::default_for_keeping_all_history(
584 keeps_all_history,
585 )
586 .into(),
587 start_as_paused: false,
588 allow_transfer_to_frozen_balance: true,
589 max_supply_change_rules: self.default_advanced_change_control_rules_v0().into(),
590 distribution_rules: self
591 .default_distribution_rules_v0(None, None, with_direct_pricing)
592 .into(),
593 marketplace_rules: self.default_marketplace_rules_v0().into(),
594 manual_minting_rules: self.default_basic_change_control_rules_v0().into(),
595 manual_burning_rules: self.default_basic_change_control_rules_v0().into(),
596 freeze_rules: self.default_advanced_change_control_rules_v0().into(),
597 unfreeze_rules: self.default_advanced_change_control_rules_v0().into(),
598 destroy_frozen_funds_rules: self.default_advanced_change_control_rules_v0().into(),
599 emergency_action_rules: self
600 .default_emergency_action_change_control_rules_v0()
601 .into(),
602 main_control_group: None,
603 main_control_group_can_be_modified: self.default_main_control_group_can_be_modified(),
604 description: None,
605 }
606 }
607}
608
609impl TokenConfigurationV0 {
610 pub fn default_most_restrictive() -> Self {
611 TokenConfigurationPreset {
612 features: TokenConfigurationPresetFeatures::MostRestrictive,
613 action_taker: AuthorizedActionTakers::NoOne,
614 }
615 .token_configuration_v0(
616 TokenConfigurationConvention::V0(TokenConfigurationConventionV0 {
617 localizations: Default::default(),
618 decimals: 8,
619 }),
620 100000,
621 None,
622 true,
623 false,
624 )
625 }
626
627 pub fn with_base_supply(mut self, base_supply: TokenAmount) -> Self {
628 self.base_supply = base_supply;
629 self
630 }
631}
632
633#[cfg(test)]
634mod tests {
635 use super::*;
636 use crate::data_contract::associated_token::token_configuration::accessors::v0::{
637 TokenConfigurationV0Getters, TokenConfigurationV0Setters,
638 };
639 use platform_value::Identifier;
640
641 fn preset(
642 features: TokenConfigurationPresetFeatures,
643 action_taker: AuthorizedActionTakers,
644 ) -> TokenConfigurationPreset {
645 TokenConfigurationPreset {
646 features,
647 action_taker,
648 }
649 }
650
651 #[test]
654 fn preset_main_control_group_can_be_modified_most_restrictive_is_no_one() {
655 let p = preset(
656 TokenConfigurationPresetFeatures::MostRestrictive,
657 AuthorizedActionTakers::ContractOwner,
658 );
659 assert_eq!(
660 p.default_main_control_group_can_be_modified(),
661 AuthorizedActionTakers::NoOne
662 );
663 }
664
665 #[test]
666 fn preset_main_control_group_can_be_modified_only_emergency_is_no_one() {
667 let p = preset(
668 TokenConfigurationPresetFeatures::WithOnlyEmergencyAction,
669 AuthorizedActionTakers::ContractOwner,
670 );
671 assert_eq!(
672 p.default_main_control_group_can_be_modified(),
673 AuthorizedActionTakers::NoOne
674 );
675 }
676
677 #[test]
678 fn preset_main_control_group_can_be_modified_minting_burning_is_no_one() {
679 let p = preset(
680 TokenConfigurationPresetFeatures::WithMintingAndBurningActions,
681 AuthorizedActionTakers::ContractOwner,
682 );
683 assert_eq!(
684 p.default_main_control_group_can_be_modified(),
685 AuthorizedActionTakers::NoOne
686 );
687 }
688
689 #[test]
690 fn preset_main_control_group_can_be_modified_advanced_is_no_one() {
691 let p = preset(
692 TokenConfigurationPresetFeatures::WithAllAdvancedActions,
693 AuthorizedActionTakers::ContractOwner,
694 );
695 assert_eq!(
696 p.default_main_control_group_can_be_modified(),
697 AuthorizedActionTakers::NoOne
698 );
699 }
700
701 #[test]
702 fn preset_main_control_group_can_be_modified_extreme_is_action_taker() {
703 let taker = AuthorizedActionTakers::Identity(Identifier::from([9u8; 32]));
704 let p = preset(TokenConfigurationPresetFeatures::WithExtremeActions, taker);
705 assert_eq!(p.default_main_control_group_can_be_modified(), taker);
706 }
707
708 #[test]
711 fn preset_basic_rules_most_restrictive_is_no_one_locked() {
712 let p = preset(
713 TokenConfigurationPresetFeatures::MostRestrictive,
714 AuthorizedActionTakers::ContractOwner,
715 );
716 let rules = p.default_basic_change_control_rules_v0();
717 assert_eq!(
718 rules.authorized_to_make_change,
719 AuthorizedActionTakers::NoOne
720 );
721 assert_eq!(rules.admin_action_takers, AuthorizedActionTakers::NoOne);
722 assert!(!rules.changing_authorized_action_takers_to_no_one_allowed);
723 assert!(!rules.changing_admin_action_takers_to_no_one_allowed);
724 assert!(!rules.self_changing_admin_action_takers_allowed);
725 }
726
727 #[test]
728 fn preset_basic_rules_only_emergency_is_no_one_locked() {
729 let p = preset(
730 TokenConfigurationPresetFeatures::WithOnlyEmergencyAction,
731 AuthorizedActionTakers::ContractOwner,
732 );
733 let rules = p.default_basic_change_control_rules_v0();
734 assert_eq!(
735 rules.authorized_to_make_change,
736 AuthorizedActionTakers::NoOne
737 );
738 }
739
740 #[test]
741 fn preset_basic_rules_minting_burning_is_action_taker_self_mutable() {
742 let taker = AuthorizedActionTakers::ContractOwner;
743 let p = preset(
744 TokenConfigurationPresetFeatures::WithMintingAndBurningActions,
745 taker,
746 );
747 let rules = p.default_basic_change_control_rules_v0();
748 assert_eq!(rules.authorized_to_make_change, taker);
749 assert_eq!(rules.admin_action_takers, taker);
750 assert!(rules.self_changing_admin_action_takers_allowed);
751 assert!(!rules.changing_authorized_action_takers_to_no_one_allowed);
753 }
754
755 #[test]
756 fn preset_basic_rules_advanced_is_action_taker_self_mutable() {
757 let taker = AuthorizedActionTakers::ContractOwner;
758 let p = preset(
759 TokenConfigurationPresetFeatures::WithAllAdvancedActions,
760 taker,
761 );
762 let rules = p.default_basic_change_control_rules_v0();
763 assert_eq!(rules.authorized_to_make_change, taker);
764 assert!(rules.self_changing_admin_action_takers_allowed);
765 assert!(!rules.changing_admin_action_takers_to_no_one_allowed);
766 }
767
768 #[test]
769 fn preset_basic_rules_extreme_allows_no_one_transitions() {
770 let taker = AuthorizedActionTakers::ContractOwner;
771 let p = preset(TokenConfigurationPresetFeatures::WithExtremeActions, taker);
772 let rules = p.default_basic_change_control_rules_v0();
773 assert_eq!(rules.authorized_to_make_change, taker);
774 assert!(rules.changing_authorized_action_takers_to_no_one_allowed);
775 assert!(rules.changing_admin_action_takers_to_no_one_allowed);
776 assert!(rules.self_changing_admin_action_takers_allowed);
777 }
778
779 #[test]
782 fn preset_advanced_rules_most_restrictive_is_locked() {
783 let p = preset(
784 TokenConfigurationPresetFeatures::MostRestrictive,
785 AuthorizedActionTakers::ContractOwner,
786 );
787 let rules = p.default_advanced_change_control_rules_v0();
788 assert_eq!(
789 rules.authorized_to_make_change,
790 AuthorizedActionTakers::NoOne
791 );
792 assert!(!rules.self_changing_admin_action_takers_allowed);
793 }
794
795 #[test]
796 fn preset_advanced_rules_minting_burning_is_locked() {
797 let p = preset(
798 TokenConfigurationPresetFeatures::WithMintingAndBurningActions,
799 AuthorizedActionTakers::ContractOwner,
800 );
801 let rules = p.default_advanced_change_control_rules_v0();
803 assert_eq!(
804 rules.authorized_to_make_change,
805 AuthorizedActionTakers::NoOne
806 );
807 assert_eq!(rules.admin_action_takers, AuthorizedActionTakers::NoOne);
808 }
809
810 #[test]
811 fn preset_advanced_rules_only_emergency_is_locked() {
812 let p = preset(
813 TokenConfigurationPresetFeatures::WithOnlyEmergencyAction,
814 AuthorizedActionTakers::ContractOwner,
815 );
816 let rules = p.default_advanced_change_control_rules_v0();
817 assert_eq!(
818 rules.authorized_to_make_change,
819 AuthorizedActionTakers::NoOne
820 );
821 }
822
823 #[test]
824 fn preset_advanced_rules_advanced_allows_action_taker() {
825 let taker = AuthorizedActionTakers::ContractOwner;
826 let p = preset(
827 TokenConfigurationPresetFeatures::WithAllAdvancedActions,
828 taker,
829 );
830 let rules = p.default_advanced_change_control_rules_v0();
831 assert_eq!(rules.authorized_to_make_change, taker);
832 assert!(rules.self_changing_admin_action_takers_allowed);
833 assert!(!rules.changing_authorized_action_takers_to_no_one_allowed);
834 }
835
836 #[test]
837 fn preset_advanced_rules_extreme_allows_everything() {
838 let taker = AuthorizedActionTakers::ContractOwner;
839 let p = preset(TokenConfigurationPresetFeatures::WithExtremeActions, taker);
840 let rules = p.default_advanced_change_control_rules_v0();
841 assert!(rules.changing_authorized_action_takers_to_no_one_allowed);
842 assert!(rules.changing_admin_action_takers_to_no_one_allowed);
843 assert!(rules.self_changing_admin_action_takers_allowed);
844 }
845
846 #[test]
849 fn preset_emergency_rules_most_restrictive_is_no_one() {
850 let p = preset(
851 TokenConfigurationPresetFeatures::MostRestrictive,
852 AuthorizedActionTakers::ContractOwner,
853 );
854 let rules = p.default_emergency_action_change_control_rules_v0();
855 assert_eq!(
856 rules.authorized_to_make_change,
857 AuthorizedActionTakers::NoOne
858 );
859 }
860
861 #[test]
862 fn preset_emergency_rules_only_emergency_allows_action_taker() {
863 let taker = AuthorizedActionTakers::ContractOwner;
864 let p = preset(
865 TokenConfigurationPresetFeatures::WithOnlyEmergencyAction,
866 taker,
867 );
868 let rules = p.default_emergency_action_change_control_rules_v0();
869 assert_eq!(rules.authorized_to_make_change, taker);
870 assert!(rules.self_changing_admin_action_takers_allowed);
871 }
872
873 #[test]
874 fn preset_emergency_rules_minting_burning_allows_action_taker() {
875 let taker = AuthorizedActionTakers::ContractOwner;
876 let p = preset(
877 TokenConfigurationPresetFeatures::WithMintingAndBurningActions,
878 taker,
879 );
880 let rules = p.default_emergency_action_change_control_rules_v0();
881 assert_eq!(rules.authorized_to_make_change, taker);
882 assert!(rules.self_changing_admin_action_takers_allowed);
883 }
884
885 #[test]
886 fn preset_emergency_rules_advanced_allows_action_taker() {
887 let taker = AuthorizedActionTakers::ContractOwner;
888 let p = preset(
889 TokenConfigurationPresetFeatures::WithAllAdvancedActions,
890 taker,
891 );
892 let rules = p.default_emergency_action_change_control_rules_v0();
893 assert_eq!(rules.authorized_to_make_change, taker);
894 }
895
896 #[test]
897 fn preset_emergency_rules_extreme_allows_no_one_transitions() {
898 let taker = AuthorizedActionTakers::ContractOwner;
899 let p = preset(TokenConfigurationPresetFeatures::WithExtremeActions, taker);
900 let rules = p.default_emergency_action_change_control_rules_v0();
901 assert!(rules.changing_authorized_action_takers_to_no_one_allowed);
902 }
903
904 #[test]
907 fn preset_distribution_rules_with_direct_pricing_uses_basic_rules() {
908 let taker = AuthorizedActionTakers::ContractOwner;
909 let p = preset(TokenConfigurationPresetFeatures::WithExtremeActions, taker);
910 let rules = p.default_distribution_rules_v0(None, None, true);
911 assert_eq!(
913 rules
914 .change_direct_purchase_pricing_rules
915 .authorized_to_make_change_action_takers(),
916 &taker
917 );
918 }
919
920 #[test]
921 fn preset_distribution_rules_without_direct_pricing_locks_it_down() {
922 let taker = AuthorizedActionTakers::ContractOwner;
923 let p = preset(TokenConfigurationPresetFeatures::WithExtremeActions, taker);
924 let rules = p.default_distribution_rules_v0(None, None, false);
925 assert_eq!(
927 rules
928 .change_direct_purchase_pricing_rules
929 .authorized_to_make_change_action_takers(),
930 &AuthorizedActionTakers::NoOne
931 );
932 }
933
934 #[test]
935 fn preset_distribution_rules_minting_choosing_destination_defaults_true() {
936 let p = preset(
937 TokenConfigurationPresetFeatures::MostRestrictive,
938 AuthorizedActionTakers::NoOne,
939 );
940 let rules = p.default_distribution_rules_v0(None, None, false);
941 assert!(rules.minting_allow_choosing_destination);
942 assert!(rules.new_tokens_destination_identity.is_none());
943 assert!(rules.perpetual_distribution.is_none());
944 assert!(rules.pre_programmed_distribution.is_none());
945 }
946
947 #[test]
950 fn preset_marketplace_rules_default_is_not_tradeable() {
951 let p = preset(
952 TokenConfigurationPresetFeatures::MostRestrictive,
953 AuthorizedActionTakers::NoOne,
954 );
955 let mp = p.default_marketplace_rules_v0();
956 assert_eq!(mp.trade_mode, TokenTradeMode::NotTradeable);
957 }
958
959 #[test]
962 fn preset_token_configuration_v0_populates_fields() {
963 let taker = AuthorizedActionTakers::ContractOwner;
964 let p = preset(TokenConfigurationPresetFeatures::WithExtremeActions, taker);
965 let conventions = TokenConfigurationConvention::V0(TokenConfigurationConventionV0 {
966 localizations: Default::default(),
967 decimals: 4,
968 });
969 let config = p.token_configuration_v0(conventions, 1_000, Some(5_000), true, true);
970 assert_eq!(config.base_supply, 1_000);
971 assert_eq!(config.max_supply, Some(5_000));
972 assert_eq!(
973 config
974 .manual_minting_rules
975 .authorized_to_make_change_action_takers(),
976 &taker
977 );
978 assert!(!config.start_as_paused);
980 assert!(config.allow_transfer_to_frozen_balance);
981 assert_eq!(config.main_control_group, None);
982 assert_eq!(config.main_control_group_can_be_modified, taker);
984 assert!(config.description.is_none());
986 }
987
988 #[test]
989 fn preset_token_configuration_keeps_all_history_true() {
990 let p = preset(
991 TokenConfigurationPresetFeatures::MostRestrictive,
992 AuthorizedActionTakers::NoOne,
993 );
994 let conventions = TokenConfigurationConvention::V0(TokenConfigurationConventionV0 {
995 localizations: Default::default(),
996 decimals: 8,
997 });
998 let cfg = p.token_configuration_v0(conventions, 100, None, true, false);
999 match &cfg.keeps_history {
1001 TokenKeepsHistoryRules::V0(v0) => {
1002 assert!(v0.keeps_transfer_history);
1003 assert!(v0.keeps_freezing_history);
1004 assert!(v0.keeps_minting_history);
1005 assert!(v0.keeps_burning_history);
1006 assert!(v0.keeps_direct_pricing_history);
1007 assert!(v0.keeps_direct_purchase_history);
1008 }
1009 }
1010 }
1011
1012 #[test]
1013 fn preset_token_configuration_keeps_all_history_false() {
1014 let p = preset(
1015 TokenConfigurationPresetFeatures::MostRestrictive,
1016 AuthorizedActionTakers::NoOne,
1017 );
1018 let conventions = TokenConfigurationConvention::V0(TokenConfigurationConventionV0 {
1019 localizations: Default::default(),
1020 decimals: 8,
1021 });
1022 let cfg = p.token_configuration_v0(conventions, 100, None, false, false);
1023 match &cfg.keeps_history {
1024 TokenKeepsHistoryRules::V0(v0) => {
1025 assert!(!v0.keeps_transfer_history);
1026 assert!(!v0.keeps_direct_purchase_history);
1027 }
1028 }
1029 }
1030
1031 #[test]
1034 fn token_configuration_v0_default_most_restrictive_has_no_max_supply() {
1035 let c = TokenConfigurationV0::default_most_restrictive();
1036 assert_eq!(c.base_supply, 100_000);
1037 assert!(c.max_supply.is_none());
1038 assert_eq!(
1039 c.main_control_group_can_be_modified,
1040 AuthorizedActionTakers::NoOne
1041 );
1042 }
1043
1044 #[test]
1045 fn token_configuration_v0_with_base_supply_overrides_value() {
1046 let c = TokenConfigurationV0::default_most_restrictive().with_base_supply(42);
1047 assert_eq!(c.base_supply, 42);
1048 }
1049
1050 #[test]
1053 fn display_token_configuration_v0_contains_key_fields() {
1054 let c = TokenConfigurationV0::default_most_restrictive();
1055 let s = format!("{}", c);
1056 assert!(s.contains("TokenConfigurationV0"));
1057 assert!(s.contains("base_supply"));
1058 assert!(s.contains("main_control_group"));
1059 }
1060
1061 #[test]
1064 fn all_used_group_positions_empty_when_no_groups_referenced() {
1065 let c = TokenConfigurationV0::default_most_restrictive();
1066 let (positions, uses_main) = c.all_used_group_positions();
1067 assert!(positions.is_empty());
1068 assert!(!uses_main);
1069 }
1070
1071 #[test]
1072 fn all_used_group_positions_collects_from_group_variant_in_rules() {
1073 let mut c = TokenConfigurationV0::default_most_restrictive();
1074 c.freeze_rules = ChangeControlRules::V0(ChangeControlRulesV0 {
1075 authorized_to_make_change: AuthorizedActionTakers::Group(7),
1076 admin_action_takers: AuthorizedActionTakers::Group(9),
1077 changing_authorized_action_takers_to_no_one_allowed: false,
1078 changing_admin_action_takers_to_no_one_allowed: false,
1079 self_changing_admin_action_takers_allowed: false,
1080 });
1081 let (positions, uses_main) = c.all_used_group_positions();
1082 assert!(positions.contains(&7));
1083 assert!(positions.contains(&9));
1084 assert!(!uses_main);
1085 }
1086
1087 #[test]
1088 fn all_used_group_positions_flags_main_group_usage() {
1089 let mut c = TokenConfigurationV0::default_most_restrictive();
1090 c.emergency_action_rules = ChangeControlRules::V0(ChangeControlRulesV0 {
1091 authorized_to_make_change: AuthorizedActionTakers::MainGroup,
1092 admin_action_takers: AuthorizedActionTakers::NoOne,
1093 changing_authorized_action_takers_to_no_one_allowed: false,
1094 changing_admin_action_takers_to_no_one_allowed: false,
1095 self_changing_admin_action_takers_allowed: false,
1096 });
1097 let (_, uses_main) = c.all_used_group_positions();
1098 assert!(uses_main);
1099 }
1100
1101 #[test]
1102 fn all_used_group_positions_includes_main_control_group() {
1103 let mut c = TokenConfigurationV0::default_most_restrictive();
1104 c.main_control_group = Some(42);
1105 let (positions, _) = c.all_used_group_positions();
1106 assert!(positions.contains(&42));
1107 }
1108
1109 #[test]
1110 fn all_used_group_positions_includes_positions_from_main_control_group_can_be_modified() {
1111 let mut c = TokenConfigurationV0::default_most_restrictive();
1112 c.main_control_group_can_be_modified = AuthorizedActionTakers::Group(11);
1113 let (positions, _) = c.all_used_group_positions();
1114 assert!(positions.contains(&11));
1115 }
1116
1117 #[test]
1118 fn all_used_group_positions_ignores_contract_owner_and_identity_and_no_one() {
1119 let mut c = TokenConfigurationV0::default_most_restrictive();
1120 c.manual_minting_rules = ChangeControlRules::V0(ChangeControlRulesV0 {
1121 authorized_to_make_change: AuthorizedActionTakers::ContractOwner,
1122 admin_action_takers: AuthorizedActionTakers::Identity(Identifier::from([1u8; 32])),
1123 changing_authorized_action_takers_to_no_one_allowed: false,
1124 changing_admin_action_takers_to_no_one_allowed: false,
1125 self_changing_admin_action_takers_allowed: false,
1126 });
1127 let (positions, uses_main) = c.all_used_group_positions();
1128 assert!(positions.is_empty());
1129 assert!(!uses_main);
1130 }
1131
1132 #[test]
1135 fn all_change_control_rules_returns_expected_rule_names() {
1136 let c = TokenConfigurationV0::default_most_restrictive();
1137 let rules = c.all_change_control_rules();
1138 let names: Vec<&str> = rules.iter().map(|(name, _)| *name).collect();
1139 assert!(names.contains(&"max_supply_change_rules"));
1140 assert!(names.contains(&"conventions_change_rules"));
1141 assert!(names.contains(&"manual_minting_rules"));
1142 assert!(names.contains(&"manual_burning_rules"));
1143 assert!(names.contains(&"freeze_rules"));
1144 assert!(names.contains(&"unfreeze_rules"));
1145 assert!(names.contains(&"destroy_frozen_funds_rules"));
1146 assert!(names.contains(&"emergency_action_rules"));
1147 assert!(names.contains(&"trade_mode_change_rules"));
1148 assert_eq!(rules.len(), 13);
1150 }
1151
1152 #[test]
1155 fn setters_set_description_max_supply_base_supply_main_control_group() {
1156 let mut c = TokenConfigurationV0::default_most_restrictive();
1157 c.set_description(Some("my token".to_string()));
1158 c.set_max_supply(Some(999));
1159 c.set_base_supply(77);
1160 c.set_main_control_group(Some(3));
1161 c.set_start_as_paused(true);
1162 c.allow_transfer_to_frozen_balance(false);
1163 c.set_main_control_group_can_be_modified(AuthorizedActionTakers::ContractOwner);
1164 assert_eq!(c.description(), &Some("my token".to_string()));
1165 assert_eq!(c.max_supply(), Some(999));
1166 assert_eq!(c.base_supply(), 77);
1167 assert_eq!(c.main_control_group(), Some(3));
1168 assert!(c.start_as_paused());
1169 assert!(!c.is_allowed_transfer_to_frozen_balance());
1170 assert_eq!(
1171 c.main_control_group_can_be_modified(),
1172 &AuthorizedActionTakers::ContractOwner
1173 );
1174 }
1175}