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