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, 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)]
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(Serialize, Deserialize, Decode, Encode, Debug, Clone, Copy, PartialEq, Eq, PartialOrd)]
252pub enum TokenConfigurationPresetFeatures {
253 MostRestrictive,
258
259 WithOnlyEmergencyAction,
265
266 WithMintingAndBurningActions,
270
271 WithAllAdvancedActions,
276
277 WithExtremeActions,
284}
285
286#[derive(Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq, Eq, PartialOrd)]
296#[serde(rename_all = "camelCase")]
297pub struct TokenConfigurationPreset {
298 pub features: TokenConfigurationPresetFeatures,
304
305 pub action_taker: AuthorizedActionTakers,
310}
311
312#[cfg(all(feature = "json-conversion", feature = "serde-conversion"))]
314impl crate::serialization::JsonConvertible for TokenConfigurationPresetFeatures {}
315
316#[cfg(all(feature = "value-conversion", feature = "serde-conversion"))]
317impl crate::serialization::ValueConvertible for TokenConfigurationPresetFeatures {}
318
319#[cfg(all(feature = "json-conversion", feature = "serde-conversion"))]
320impl crate::serialization::JsonConvertible for TokenConfigurationPreset {}
321
322#[cfg(all(feature = "value-conversion", feature = "serde-conversion"))]
323impl crate::serialization::ValueConvertible for TokenConfigurationPreset {}
324
325#[cfg(all(
326 test,
327 feature = "json-conversion",
328 feature = "value-conversion",
329 feature = "serde-conversion"
330))]
331mod json_convertible_tests_preset {
332 use super::*;
333 use crate::serialization::{JsonConvertible, ValueConvertible};
334 use platform_value::platform_value;
335 use serde_json::json;
336
337 fn fixture() -> TokenConfigurationPreset {
338 TokenConfigurationPreset {
339 features: TokenConfigurationPresetFeatures::WithAllAdvancedActions,
340 action_taker: AuthorizedActionTakers::Group(7),
341 }
342 }
343
344 #[test]
345 fn preset_json_round_trip_with_full_wire_shape() {
346 let original = fixture();
347 let json = original.to_json().expect("to_json");
348 assert_eq!(
352 json,
353 json!({
354 "features": "WithAllAdvancedActions",
355 "actionTaker": {"$type": "group", "position": 7},
356 })
357 );
358 let recovered = TokenConfigurationPreset::from_json(json).expect("from_json");
359 assert_eq!(original, recovered);
360 }
361
362 #[test]
363 fn preset_value_round_trip_with_full_wire_shape() {
364 let original = fixture();
365 let value = original.to_object().expect("to_object");
366 assert_eq!(
367 value,
368 platform_value!({
369 "features": "WithAllAdvancedActions",
370 "actionTaker": {"$type": "group", "position": 7u16},
371 })
372 );
373 let recovered = TokenConfigurationPreset::from_object(value).expect("from_object");
374 assert_eq!(original, recovered);
375 }
376
377 #[test]
378 fn preset_features_round_trips_all_variants() {
379 let cases = [
380 (
381 TokenConfigurationPresetFeatures::MostRestrictive,
382 "MostRestrictive",
383 ),
384 (
385 TokenConfigurationPresetFeatures::WithOnlyEmergencyAction,
386 "WithOnlyEmergencyAction",
387 ),
388 (
389 TokenConfigurationPresetFeatures::WithMintingAndBurningActions,
390 "WithMintingAndBurningActions",
391 ),
392 (
393 TokenConfigurationPresetFeatures::WithAllAdvancedActions,
394 "WithAllAdvancedActions",
395 ),
396 (
397 TokenConfigurationPresetFeatures::WithExtremeActions,
398 "WithExtremeActions",
399 ),
400 ];
401 for (original, expected) in cases {
402 let json_v = original.to_json().expect("to_json");
403 assert_eq!(json_v, json!(expected));
404 assert_eq!(
405 TokenConfigurationPresetFeatures::from_json(json_v).expect("from_json"),
406 original
407 );
408 let value = original.to_object().expect("to_object");
409 assert_eq!(value, platform_value!(expected));
410 assert_eq!(
411 TokenConfigurationPresetFeatures::from_object(value).expect("from_object"),
412 original
413 );
414 }
415 }
416}
417
418impl TokenConfigurationPreset {
419 pub fn default_main_control_group_can_be_modified(&self) -> AuthorizedActionTakers {
420 match self.features {
421 TokenConfigurationPresetFeatures::MostRestrictive
422 | TokenConfigurationPresetFeatures::WithOnlyEmergencyAction
423 | TokenConfigurationPresetFeatures::WithMintingAndBurningActions
424 | TokenConfigurationPresetFeatures::WithAllAdvancedActions => {
425 AuthorizedActionTakers::NoOne
426 }
427 TokenConfigurationPresetFeatures::WithExtremeActions => self.action_taker,
428 }
429 }
430 pub fn default_basic_change_control_rules_v0(&self) -> ChangeControlRulesV0 {
431 match self.features {
432 TokenConfigurationPresetFeatures::MostRestrictive
433 | TokenConfigurationPresetFeatures::WithOnlyEmergencyAction => ChangeControlRulesV0 {
434 authorized_to_make_change: AuthorizedActionTakers::NoOne,
435 admin_action_takers: AuthorizedActionTakers::NoOne,
436 changing_authorized_action_takers_to_no_one_allowed: false,
437 changing_admin_action_takers_to_no_one_allowed: false,
438 self_changing_admin_action_takers_allowed: false,
439 },
440 TokenConfigurationPresetFeatures::WithMintingAndBurningActions
441 | TokenConfigurationPresetFeatures::WithAllAdvancedActions => ChangeControlRulesV0 {
442 authorized_to_make_change: self.action_taker,
443 admin_action_takers: self.action_taker,
444 changing_authorized_action_takers_to_no_one_allowed: false,
445 changing_admin_action_takers_to_no_one_allowed: false,
446 self_changing_admin_action_takers_allowed: true,
447 },
448 TokenConfigurationPresetFeatures::WithExtremeActions => ChangeControlRulesV0 {
449 authorized_to_make_change: self.action_taker,
450 admin_action_takers: self.action_taker,
451 changing_authorized_action_takers_to_no_one_allowed: true,
452 changing_admin_action_takers_to_no_one_allowed: true,
453 self_changing_admin_action_takers_allowed: true,
454 },
455 }
456 }
457
458 pub fn default_advanced_change_control_rules_v0(&self) -> ChangeControlRulesV0 {
459 match self.features {
460 TokenConfigurationPresetFeatures::MostRestrictive
461 | TokenConfigurationPresetFeatures::WithOnlyEmergencyAction
462 | TokenConfigurationPresetFeatures::WithMintingAndBurningActions => {
463 ChangeControlRulesV0 {
464 authorized_to_make_change: AuthorizedActionTakers::NoOne,
465 admin_action_takers: AuthorizedActionTakers::NoOne,
466 changing_authorized_action_takers_to_no_one_allowed: false,
467 changing_admin_action_takers_to_no_one_allowed: false,
468 self_changing_admin_action_takers_allowed: false,
469 }
470 }
471 TokenConfigurationPresetFeatures::WithAllAdvancedActions => ChangeControlRulesV0 {
472 authorized_to_make_change: self.action_taker,
473 admin_action_takers: self.action_taker,
474 changing_authorized_action_takers_to_no_one_allowed: false,
475 changing_admin_action_takers_to_no_one_allowed: false,
476 self_changing_admin_action_takers_allowed: true,
477 },
478 TokenConfigurationPresetFeatures::WithExtremeActions => ChangeControlRulesV0 {
479 authorized_to_make_change: self.action_taker,
480 admin_action_takers: self.action_taker,
481 changing_authorized_action_takers_to_no_one_allowed: true,
482 changing_admin_action_takers_to_no_one_allowed: true,
483 self_changing_admin_action_takers_allowed: true,
484 },
485 }
486 }
487
488 pub fn default_emergency_action_change_control_rules_v0(&self) -> ChangeControlRulesV0 {
489 match self.features {
490 TokenConfigurationPresetFeatures::MostRestrictive => ChangeControlRulesV0 {
491 authorized_to_make_change: AuthorizedActionTakers::NoOne,
492 admin_action_takers: AuthorizedActionTakers::NoOne,
493 changing_authorized_action_takers_to_no_one_allowed: false,
494 changing_admin_action_takers_to_no_one_allowed: false,
495 self_changing_admin_action_takers_allowed: false,
496 },
497 TokenConfigurationPresetFeatures::WithAllAdvancedActions
498 | TokenConfigurationPresetFeatures::WithMintingAndBurningActions
499 | TokenConfigurationPresetFeatures::WithOnlyEmergencyAction => ChangeControlRulesV0 {
500 authorized_to_make_change: self.action_taker,
501 admin_action_takers: self.action_taker,
502 changing_authorized_action_takers_to_no_one_allowed: false,
503 changing_admin_action_takers_to_no_one_allowed: false,
504 self_changing_admin_action_takers_allowed: true,
505 },
506 TokenConfigurationPresetFeatures::WithExtremeActions => ChangeControlRulesV0 {
507 authorized_to_make_change: self.action_taker,
508 admin_action_takers: self.action_taker,
509 changing_authorized_action_takers_to_no_one_allowed: true,
510 changing_admin_action_takers_to_no_one_allowed: true,
511 self_changing_admin_action_takers_allowed: true,
512 },
513 }
514 }
515
516 pub fn default_distribution_rules_v0(
517 &self,
518 perpetual_distribution: Option<TokenPerpetualDistribution>,
519 pre_programmed_distribution: Option<TokenPreProgrammedDistribution>,
520 with_direct_pricing: bool,
521 ) -> TokenDistributionRulesV0 {
522 TokenDistributionRulesV0 {
523 perpetual_distribution,
524 perpetual_distribution_rules: self.default_advanced_change_control_rules_v0().into(),
525 pre_programmed_distribution,
526 new_tokens_destination_identity: None,
527 new_tokens_destination_identity_rules: self
528 .default_basic_change_control_rules_v0()
529 .into(),
530 minting_allow_choosing_destination: true,
531 minting_allow_choosing_destination_rules: self
532 .default_basic_change_control_rules_v0()
533 .into(),
534 change_direct_purchase_pricing_rules: if with_direct_pricing {
535 self.default_basic_change_control_rules_v0().into()
536 } else {
537 ChangeControlRulesV0 {
538 authorized_to_make_change: AuthorizedActionTakers::NoOne,
539 admin_action_takers: AuthorizedActionTakers::NoOne,
540 changing_authorized_action_takers_to_no_one_allowed: false,
541 changing_admin_action_takers_to_no_one_allowed: false,
542 self_changing_admin_action_takers_allowed: false,
543 }
544 .into()
545 },
546 }
547 }
548
549 pub fn default_marketplace_rules_v0(&self) -> TokenMarketplaceRulesV0 {
550 TokenMarketplaceRulesV0 {
551 trade_mode: TokenTradeMode::NotTradeable,
552 trade_mode_change_rules: self.default_basic_change_control_rules_v0().into(),
553 }
554 }
555
556 pub fn token_configuration_v0(
557 &self,
558 conventions: TokenConfigurationConvention,
559 base_supply: TokenAmount,
560 max_supply: Option<TokenAmount>,
561 keeps_all_history: bool,
562 with_direct_pricing: bool,
563 ) -> TokenConfigurationV0 {
564 TokenConfigurationV0 {
565 conventions,
566 conventions_change_rules: self.default_basic_change_control_rules_v0().into(),
567 base_supply,
568 max_supply,
569 keeps_history: TokenKeepsHistoryRulesV0::default_for_keeping_all_history(
570 keeps_all_history,
571 )
572 .into(),
573 start_as_paused: false,
574 allow_transfer_to_frozen_balance: true,
575 max_supply_change_rules: self.default_advanced_change_control_rules_v0().into(),
576 distribution_rules: self
577 .default_distribution_rules_v0(None, None, with_direct_pricing)
578 .into(),
579 marketplace_rules: self.default_marketplace_rules_v0().into(),
580 manual_minting_rules: self.default_basic_change_control_rules_v0().into(),
581 manual_burning_rules: self.default_basic_change_control_rules_v0().into(),
582 freeze_rules: self.default_advanced_change_control_rules_v0().into(),
583 unfreeze_rules: self.default_advanced_change_control_rules_v0().into(),
584 destroy_frozen_funds_rules: self.default_advanced_change_control_rules_v0().into(),
585 emergency_action_rules: self
586 .default_emergency_action_change_control_rules_v0()
587 .into(),
588 main_control_group: None,
589 main_control_group_can_be_modified: self.default_main_control_group_can_be_modified(),
590 description: None,
591 }
592 }
593}
594
595impl TokenConfigurationV0 {
596 pub fn default_most_restrictive() -> Self {
597 TokenConfigurationPreset {
598 features: TokenConfigurationPresetFeatures::MostRestrictive,
599 action_taker: AuthorizedActionTakers::NoOne,
600 }
601 .token_configuration_v0(
602 TokenConfigurationConvention::V0(TokenConfigurationConventionV0 {
603 localizations: Default::default(),
604 decimals: 8,
605 }),
606 100000,
607 None,
608 true,
609 false,
610 )
611 }
612
613 pub fn with_base_supply(mut self, base_supply: TokenAmount) -> Self {
614 self.base_supply = base_supply;
615 self
616 }
617}
618
619#[cfg(test)]
620mod tests {
621 use super::*;
622 use crate::data_contract::associated_token::token_configuration::accessors::v0::{
623 TokenConfigurationV0Getters, TokenConfigurationV0Setters,
624 };
625 use platform_value::Identifier;
626
627 fn preset(
628 features: TokenConfigurationPresetFeatures,
629 action_taker: AuthorizedActionTakers,
630 ) -> TokenConfigurationPreset {
631 TokenConfigurationPreset {
632 features,
633 action_taker,
634 }
635 }
636
637 #[test]
640 fn preset_main_control_group_can_be_modified_most_restrictive_is_no_one() {
641 let p = preset(
642 TokenConfigurationPresetFeatures::MostRestrictive,
643 AuthorizedActionTakers::ContractOwner,
644 );
645 assert_eq!(
646 p.default_main_control_group_can_be_modified(),
647 AuthorizedActionTakers::NoOne
648 );
649 }
650
651 #[test]
652 fn preset_main_control_group_can_be_modified_only_emergency_is_no_one() {
653 let p = preset(
654 TokenConfigurationPresetFeatures::WithOnlyEmergencyAction,
655 AuthorizedActionTakers::ContractOwner,
656 );
657 assert_eq!(
658 p.default_main_control_group_can_be_modified(),
659 AuthorizedActionTakers::NoOne
660 );
661 }
662
663 #[test]
664 fn preset_main_control_group_can_be_modified_minting_burning_is_no_one() {
665 let p = preset(
666 TokenConfigurationPresetFeatures::WithMintingAndBurningActions,
667 AuthorizedActionTakers::ContractOwner,
668 );
669 assert_eq!(
670 p.default_main_control_group_can_be_modified(),
671 AuthorizedActionTakers::NoOne
672 );
673 }
674
675 #[test]
676 fn preset_main_control_group_can_be_modified_advanced_is_no_one() {
677 let p = preset(
678 TokenConfigurationPresetFeatures::WithAllAdvancedActions,
679 AuthorizedActionTakers::ContractOwner,
680 );
681 assert_eq!(
682 p.default_main_control_group_can_be_modified(),
683 AuthorizedActionTakers::NoOne
684 );
685 }
686
687 #[test]
688 fn preset_main_control_group_can_be_modified_extreme_is_action_taker() {
689 let taker = AuthorizedActionTakers::Identity(Identifier::from([9u8; 32]));
690 let p = preset(TokenConfigurationPresetFeatures::WithExtremeActions, taker);
691 assert_eq!(p.default_main_control_group_can_be_modified(), taker);
692 }
693
694 #[test]
697 fn preset_basic_rules_most_restrictive_is_no_one_locked() {
698 let p = preset(
699 TokenConfigurationPresetFeatures::MostRestrictive,
700 AuthorizedActionTakers::ContractOwner,
701 );
702 let rules = p.default_basic_change_control_rules_v0();
703 assert_eq!(
704 rules.authorized_to_make_change,
705 AuthorizedActionTakers::NoOne
706 );
707 assert_eq!(rules.admin_action_takers, AuthorizedActionTakers::NoOne);
708 assert!(!rules.changing_authorized_action_takers_to_no_one_allowed);
709 assert!(!rules.changing_admin_action_takers_to_no_one_allowed);
710 assert!(!rules.self_changing_admin_action_takers_allowed);
711 }
712
713 #[test]
714 fn preset_basic_rules_only_emergency_is_no_one_locked() {
715 let p = preset(
716 TokenConfigurationPresetFeatures::WithOnlyEmergencyAction,
717 AuthorizedActionTakers::ContractOwner,
718 );
719 let rules = p.default_basic_change_control_rules_v0();
720 assert_eq!(
721 rules.authorized_to_make_change,
722 AuthorizedActionTakers::NoOne
723 );
724 }
725
726 #[test]
727 fn preset_basic_rules_minting_burning_is_action_taker_self_mutable() {
728 let taker = AuthorizedActionTakers::ContractOwner;
729 let p = preset(
730 TokenConfigurationPresetFeatures::WithMintingAndBurningActions,
731 taker,
732 );
733 let rules = p.default_basic_change_control_rules_v0();
734 assert_eq!(rules.authorized_to_make_change, taker);
735 assert_eq!(rules.admin_action_takers, taker);
736 assert!(rules.self_changing_admin_action_takers_allowed);
737 assert!(!rules.changing_authorized_action_takers_to_no_one_allowed);
739 }
740
741 #[test]
742 fn preset_basic_rules_advanced_is_action_taker_self_mutable() {
743 let taker = AuthorizedActionTakers::ContractOwner;
744 let p = preset(
745 TokenConfigurationPresetFeatures::WithAllAdvancedActions,
746 taker,
747 );
748 let rules = p.default_basic_change_control_rules_v0();
749 assert_eq!(rules.authorized_to_make_change, taker);
750 assert!(rules.self_changing_admin_action_takers_allowed);
751 assert!(!rules.changing_admin_action_takers_to_no_one_allowed);
752 }
753
754 #[test]
755 fn preset_basic_rules_extreme_allows_no_one_transitions() {
756 let taker = AuthorizedActionTakers::ContractOwner;
757 let p = preset(TokenConfigurationPresetFeatures::WithExtremeActions, taker);
758 let rules = p.default_basic_change_control_rules_v0();
759 assert_eq!(rules.authorized_to_make_change, taker);
760 assert!(rules.changing_authorized_action_takers_to_no_one_allowed);
761 assert!(rules.changing_admin_action_takers_to_no_one_allowed);
762 assert!(rules.self_changing_admin_action_takers_allowed);
763 }
764
765 #[test]
768 fn preset_advanced_rules_most_restrictive_is_locked() {
769 let p = preset(
770 TokenConfigurationPresetFeatures::MostRestrictive,
771 AuthorizedActionTakers::ContractOwner,
772 );
773 let rules = p.default_advanced_change_control_rules_v0();
774 assert_eq!(
775 rules.authorized_to_make_change,
776 AuthorizedActionTakers::NoOne
777 );
778 assert!(!rules.self_changing_admin_action_takers_allowed);
779 }
780
781 #[test]
782 fn preset_advanced_rules_minting_burning_is_locked() {
783 let p = preset(
784 TokenConfigurationPresetFeatures::WithMintingAndBurningActions,
785 AuthorizedActionTakers::ContractOwner,
786 );
787 let rules = p.default_advanced_change_control_rules_v0();
789 assert_eq!(
790 rules.authorized_to_make_change,
791 AuthorizedActionTakers::NoOne
792 );
793 assert_eq!(rules.admin_action_takers, AuthorizedActionTakers::NoOne);
794 }
795
796 #[test]
797 fn preset_advanced_rules_only_emergency_is_locked() {
798 let p = preset(
799 TokenConfigurationPresetFeatures::WithOnlyEmergencyAction,
800 AuthorizedActionTakers::ContractOwner,
801 );
802 let rules = p.default_advanced_change_control_rules_v0();
803 assert_eq!(
804 rules.authorized_to_make_change,
805 AuthorizedActionTakers::NoOne
806 );
807 }
808
809 #[test]
810 fn preset_advanced_rules_advanced_allows_action_taker() {
811 let taker = AuthorizedActionTakers::ContractOwner;
812 let p = preset(
813 TokenConfigurationPresetFeatures::WithAllAdvancedActions,
814 taker,
815 );
816 let rules = p.default_advanced_change_control_rules_v0();
817 assert_eq!(rules.authorized_to_make_change, taker);
818 assert!(rules.self_changing_admin_action_takers_allowed);
819 assert!(!rules.changing_authorized_action_takers_to_no_one_allowed);
820 }
821
822 #[test]
823 fn preset_advanced_rules_extreme_allows_everything() {
824 let taker = AuthorizedActionTakers::ContractOwner;
825 let p = preset(TokenConfigurationPresetFeatures::WithExtremeActions, taker);
826 let rules = p.default_advanced_change_control_rules_v0();
827 assert!(rules.changing_authorized_action_takers_to_no_one_allowed);
828 assert!(rules.changing_admin_action_takers_to_no_one_allowed);
829 assert!(rules.self_changing_admin_action_takers_allowed);
830 }
831
832 #[test]
835 fn preset_emergency_rules_most_restrictive_is_no_one() {
836 let p = preset(
837 TokenConfigurationPresetFeatures::MostRestrictive,
838 AuthorizedActionTakers::ContractOwner,
839 );
840 let rules = p.default_emergency_action_change_control_rules_v0();
841 assert_eq!(
842 rules.authorized_to_make_change,
843 AuthorizedActionTakers::NoOne
844 );
845 }
846
847 #[test]
848 fn preset_emergency_rules_only_emergency_allows_action_taker() {
849 let taker = AuthorizedActionTakers::ContractOwner;
850 let p = preset(
851 TokenConfigurationPresetFeatures::WithOnlyEmergencyAction,
852 taker,
853 );
854 let rules = p.default_emergency_action_change_control_rules_v0();
855 assert_eq!(rules.authorized_to_make_change, taker);
856 assert!(rules.self_changing_admin_action_takers_allowed);
857 }
858
859 #[test]
860 fn preset_emergency_rules_minting_burning_allows_action_taker() {
861 let taker = AuthorizedActionTakers::ContractOwner;
862 let p = preset(
863 TokenConfigurationPresetFeatures::WithMintingAndBurningActions,
864 taker,
865 );
866 let rules = p.default_emergency_action_change_control_rules_v0();
867 assert_eq!(rules.authorized_to_make_change, taker);
868 assert!(rules.self_changing_admin_action_takers_allowed);
869 }
870
871 #[test]
872 fn preset_emergency_rules_advanced_allows_action_taker() {
873 let taker = AuthorizedActionTakers::ContractOwner;
874 let p = preset(
875 TokenConfigurationPresetFeatures::WithAllAdvancedActions,
876 taker,
877 );
878 let rules = p.default_emergency_action_change_control_rules_v0();
879 assert_eq!(rules.authorized_to_make_change, taker);
880 }
881
882 #[test]
883 fn preset_emergency_rules_extreme_allows_no_one_transitions() {
884 let taker = AuthorizedActionTakers::ContractOwner;
885 let p = preset(TokenConfigurationPresetFeatures::WithExtremeActions, taker);
886 let rules = p.default_emergency_action_change_control_rules_v0();
887 assert!(rules.changing_authorized_action_takers_to_no_one_allowed);
888 }
889
890 #[test]
893 fn preset_distribution_rules_with_direct_pricing_uses_basic_rules() {
894 let taker = AuthorizedActionTakers::ContractOwner;
895 let p = preset(TokenConfigurationPresetFeatures::WithExtremeActions, taker);
896 let rules = p.default_distribution_rules_v0(None, None, true);
897 assert_eq!(
899 rules
900 .change_direct_purchase_pricing_rules
901 .authorized_to_make_change_action_takers(),
902 &taker
903 );
904 }
905
906 #[test]
907 fn preset_distribution_rules_without_direct_pricing_locks_it_down() {
908 let taker = AuthorizedActionTakers::ContractOwner;
909 let p = preset(TokenConfigurationPresetFeatures::WithExtremeActions, taker);
910 let rules = p.default_distribution_rules_v0(None, None, false);
911 assert_eq!(
913 rules
914 .change_direct_purchase_pricing_rules
915 .authorized_to_make_change_action_takers(),
916 &AuthorizedActionTakers::NoOne
917 );
918 }
919
920 #[test]
921 fn preset_distribution_rules_minting_choosing_destination_defaults_true() {
922 let p = preset(
923 TokenConfigurationPresetFeatures::MostRestrictive,
924 AuthorizedActionTakers::NoOne,
925 );
926 let rules = p.default_distribution_rules_v0(None, None, false);
927 assert!(rules.minting_allow_choosing_destination);
928 assert!(rules.new_tokens_destination_identity.is_none());
929 assert!(rules.perpetual_distribution.is_none());
930 assert!(rules.pre_programmed_distribution.is_none());
931 }
932
933 #[test]
936 fn preset_marketplace_rules_default_is_not_tradeable() {
937 let p = preset(
938 TokenConfigurationPresetFeatures::MostRestrictive,
939 AuthorizedActionTakers::NoOne,
940 );
941 let mp = p.default_marketplace_rules_v0();
942 assert_eq!(mp.trade_mode, TokenTradeMode::NotTradeable);
943 }
944
945 #[test]
948 fn preset_token_configuration_v0_populates_fields() {
949 let taker = AuthorizedActionTakers::ContractOwner;
950 let p = preset(TokenConfigurationPresetFeatures::WithExtremeActions, taker);
951 let conventions = TokenConfigurationConvention::V0(TokenConfigurationConventionV0 {
952 localizations: Default::default(),
953 decimals: 4,
954 });
955 let config = p.token_configuration_v0(conventions, 1_000, Some(5_000), true, true);
956 assert_eq!(config.base_supply, 1_000);
957 assert_eq!(config.max_supply, Some(5_000));
958 assert_eq!(
959 config
960 .manual_minting_rules
961 .authorized_to_make_change_action_takers(),
962 &taker
963 );
964 assert!(!config.start_as_paused);
966 assert!(config.allow_transfer_to_frozen_balance);
967 assert_eq!(config.main_control_group, None);
968 assert_eq!(config.main_control_group_can_be_modified, taker);
970 assert!(config.description.is_none());
972 }
973
974 #[test]
975 fn preset_token_configuration_keeps_all_history_true() {
976 let p = preset(
977 TokenConfigurationPresetFeatures::MostRestrictive,
978 AuthorizedActionTakers::NoOne,
979 );
980 let conventions = TokenConfigurationConvention::V0(TokenConfigurationConventionV0 {
981 localizations: Default::default(),
982 decimals: 8,
983 });
984 let cfg = p.token_configuration_v0(conventions, 100, None, true, false);
985 match &cfg.keeps_history {
987 TokenKeepsHistoryRules::V0(v0) => {
988 assert!(v0.keeps_transfer_history);
989 assert!(v0.keeps_freezing_history);
990 assert!(v0.keeps_minting_history);
991 assert!(v0.keeps_burning_history);
992 assert!(v0.keeps_direct_pricing_history);
993 assert!(v0.keeps_direct_purchase_history);
994 }
995 }
996 }
997
998 #[test]
999 fn preset_token_configuration_keeps_all_history_false() {
1000 let p = preset(
1001 TokenConfigurationPresetFeatures::MostRestrictive,
1002 AuthorizedActionTakers::NoOne,
1003 );
1004 let conventions = TokenConfigurationConvention::V0(TokenConfigurationConventionV0 {
1005 localizations: Default::default(),
1006 decimals: 8,
1007 });
1008 let cfg = p.token_configuration_v0(conventions, 100, None, false, false);
1009 match &cfg.keeps_history {
1010 TokenKeepsHistoryRules::V0(v0) => {
1011 assert!(!v0.keeps_transfer_history);
1012 assert!(!v0.keeps_direct_purchase_history);
1013 }
1014 }
1015 }
1016
1017 #[test]
1020 fn token_configuration_v0_default_most_restrictive_has_no_max_supply() {
1021 let c = TokenConfigurationV0::default_most_restrictive();
1022 assert_eq!(c.base_supply, 100_000);
1023 assert!(c.max_supply.is_none());
1024 assert_eq!(
1025 c.main_control_group_can_be_modified,
1026 AuthorizedActionTakers::NoOne
1027 );
1028 }
1029
1030 #[test]
1031 fn token_configuration_v0_with_base_supply_overrides_value() {
1032 let c = TokenConfigurationV0::default_most_restrictive().with_base_supply(42);
1033 assert_eq!(c.base_supply, 42);
1034 }
1035
1036 #[test]
1039 fn display_token_configuration_v0_contains_key_fields() {
1040 let c = TokenConfigurationV0::default_most_restrictive();
1041 let s = format!("{}", c);
1042 assert!(s.contains("TokenConfigurationV0"));
1043 assert!(s.contains("base_supply"));
1044 assert!(s.contains("main_control_group"));
1045 }
1046
1047 #[test]
1050 fn all_used_group_positions_empty_when_no_groups_referenced() {
1051 let c = TokenConfigurationV0::default_most_restrictive();
1052 let (positions, uses_main) = c.all_used_group_positions();
1053 assert!(positions.is_empty());
1054 assert!(!uses_main);
1055 }
1056
1057 #[test]
1058 fn all_used_group_positions_collects_from_group_variant_in_rules() {
1059 let mut c = TokenConfigurationV0::default_most_restrictive();
1060 c.freeze_rules = ChangeControlRules::V0(ChangeControlRulesV0 {
1061 authorized_to_make_change: AuthorizedActionTakers::Group(7),
1062 admin_action_takers: AuthorizedActionTakers::Group(9),
1063 changing_authorized_action_takers_to_no_one_allowed: false,
1064 changing_admin_action_takers_to_no_one_allowed: false,
1065 self_changing_admin_action_takers_allowed: false,
1066 });
1067 let (positions, uses_main) = c.all_used_group_positions();
1068 assert!(positions.contains(&7));
1069 assert!(positions.contains(&9));
1070 assert!(!uses_main);
1071 }
1072
1073 #[test]
1074 fn all_used_group_positions_flags_main_group_usage() {
1075 let mut c = TokenConfigurationV0::default_most_restrictive();
1076 c.emergency_action_rules = ChangeControlRules::V0(ChangeControlRulesV0 {
1077 authorized_to_make_change: AuthorizedActionTakers::MainGroup,
1078 admin_action_takers: AuthorizedActionTakers::NoOne,
1079 changing_authorized_action_takers_to_no_one_allowed: false,
1080 changing_admin_action_takers_to_no_one_allowed: false,
1081 self_changing_admin_action_takers_allowed: false,
1082 });
1083 let (_, uses_main) = c.all_used_group_positions();
1084 assert!(uses_main);
1085 }
1086
1087 #[test]
1088 fn all_used_group_positions_includes_main_control_group() {
1089 let mut c = TokenConfigurationV0::default_most_restrictive();
1090 c.main_control_group = Some(42);
1091 let (positions, _) = c.all_used_group_positions();
1092 assert!(positions.contains(&42));
1093 }
1094
1095 #[test]
1096 fn all_used_group_positions_includes_positions_from_main_control_group_can_be_modified() {
1097 let mut c = TokenConfigurationV0::default_most_restrictive();
1098 c.main_control_group_can_be_modified = AuthorizedActionTakers::Group(11);
1099 let (positions, _) = c.all_used_group_positions();
1100 assert!(positions.contains(&11));
1101 }
1102
1103 #[test]
1104 fn all_used_group_positions_ignores_contract_owner_and_identity_and_no_one() {
1105 let mut c = TokenConfigurationV0::default_most_restrictive();
1106 c.manual_minting_rules = ChangeControlRules::V0(ChangeControlRulesV0 {
1107 authorized_to_make_change: AuthorizedActionTakers::ContractOwner,
1108 admin_action_takers: AuthorizedActionTakers::Identity(Identifier::from([1u8; 32])),
1109 changing_authorized_action_takers_to_no_one_allowed: false,
1110 changing_admin_action_takers_to_no_one_allowed: false,
1111 self_changing_admin_action_takers_allowed: false,
1112 });
1113 let (positions, uses_main) = c.all_used_group_positions();
1114 assert!(positions.is_empty());
1115 assert!(!uses_main);
1116 }
1117
1118 #[test]
1121 fn all_change_control_rules_returns_expected_rule_names() {
1122 let c = TokenConfigurationV0::default_most_restrictive();
1123 let rules = c.all_change_control_rules();
1124 let names: Vec<&str> = rules.iter().map(|(name, _)| *name).collect();
1125 assert!(names.contains(&"max_supply_change_rules"));
1126 assert!(names.contains(&"conventions_change_rules"));
1127 assert!(names.contains(&"manual_minting_rules"));
1128 assert!(names.contains(&"manual_burning_rules"));
1129 assert!(names.contains(&"freeze_rules"));
1130 assert!(names.contains(&"unfreeze_rules"));
1131 assert!(names.contains(&"destroy_frozen_funds_rules"));
1132 assert!(names.contains(&"emergency_action_rules"));
1133 assert!(names.contains(&"trade_mode_change_rules"));
1134 assert_eq!(rules.len(), 13);
1136 }
1137
1138 #[test]
1141 fn setters_set_description_max_supply_base_supply_main_control_group() {
1142 let mut c = TokenConfigurationV0::default_most_restrictive();
1143 c.set_description(Some("my token".to_string()));
1144 c.set_max_supply(Some(999));
1145 c.set_base_supply(77);
1146 c.set_main_control_group(Some(3));
1147 c.set_start_as_paused(true);
1148 c.allow_transfer_to_frozen_balance(false);
1149 c.set_main_control_group_can_be_modified(AuthorizedActionTakers::ContractOwner);
1150 assert_eq!(c.description(), &Some("my token".to_string()));
1151 assert_eq!(c.max_supply(), Some(999));
1152 assert_eq!(c.base_supply(), 77);
1153 assert_eq!(c.main_control_group(), Some(3));
1154 assert!(c.start_as_paused());
1155 assert!(!c.is_allowed_transfer_to_frozen_balance());
1156 assert_eq!(
1157 c.main_control_group_can_be_modified(),
1158 &AuthorizedActionTakers::ContractOwner
1159 );
1160 }
1161}