Skip to main content

dpp/data_contract/associated_token/token_configuration/v0/
mod.rs

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/// Defines the complete configuration for a version 0 token contract.
27///
28/// `TokenConfigurationV0` encapsulates all metadata, control rules, supply settings,
29/// and governance constraints used to initialize and manage a token instance on Platform.
30/// This structure serves as the core representation of a token's logic, permissions,
31/// and capabilities.
32///
33/// This configuration is designed to be deterministic and versioned for compatibility
34/// across protocol upgrades and validation environments.
35#[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    /// Metadata conventions, including decimals and localizations.
40    pub conventions: TokenConfigurationConvention,
41
42    /// Change control rules governing who can modify the conventions field.
43    #[serde(default = "default_change_control_rules")]
44    pub conventions_change_rules: ChangeControlRules,
45
46    /// The initial token supply minted at creation.
47    #[serde(default)]
48    pub base_supply: TokenAmount,
49
50    /// The maximum allowable supply of the token.
51    ///
52    /// If `None`, the supply is unbounded unless otherwise constrained by minting logic.
53    #[serde(default)]
54    pub max_supply: Option<TokenAmount>,
55
56    /// Configuration governing which historical actions are recorded for this token.
57    #[serde(default = "default_token_keeps_history_rules")]
58    pub keeps_history: TokenKeepsHistoryRules,
59
60    /// Indicates whether the token should start in a paused state.
61    ///
62    /// When `true`, transfers are disallowed until explicitly unpaused via an emergency action.
63    #[serde(default = "default_starts_as_paused")]
64    pub start_as_paused: bool,
65
66    /// Allows minting and transferring to frozen token balances if enabled.
67    #[serde(default = "default_allow_transfer_to_frozen_balance")]
68    pub allow_transfer_to_frozen_balance: bool,
69
70    /// Change control rules for updating the `max_supply`.
71    ///
72    /// Note: The `max_supply` can never be reduced below the `base_supply`.
73    #[serde(default = "default_change_control_rules")]
74    pub max_supply_change_rules: ChangeControlRules,
75
76    /// Defines the token's distribution logic, including perpetual and pre-programmed distributions.
77    #[serde(default = "default_token_distribution_rules")]
78    pub distribution_rules: TokenDistributionRules,
79
80    /// Defines the token's marketplace logic.
81    #[serde(default = "default_token_marketplace_rules")]
82    pub marketplace_rules: TokenMarketplaceRules,
83
84    /// Rules controlling who is authorized to perform manual minting of tokens.
85    #[serde(default = "default_contract_owner_change_control_rules")]
86    pub manual_minting_rules: ChangeControlRules,
87
88    /// Rules controlling who is authorized to perform manual burning of tokens.
89    #[serde(default = "default_contract_owner_change_control_rules")]
90    pub manual_burning_rules: ChangeControlRules,
91
92    /// Rules governing who may freeze token balances.
93    #[serde(default = "default_change_control_rules")]
94    pub freeze_rules: ChangeControlRules,
95
96    /// Rules governing who may unfreeze token balances.
97    #[serde(default = "default_change_control_rules")]
98    pub unfreeze_rules: ChangeControlRules,
99
100    /// Rules governing who may destroy frozen funds.
101    #[serde(default = "default_change_control_rules")]
102    pub destroy_frozen_funds_rules: ChangeControlRules,
103
104    /// Rules governing who may invoke emergency actions, such as pausing transfers.
105    #[serde(default = "default_change_control_rules")]
106    pub emergency_action_rules: ChangeControlRules,
107
108    /// Optional reference to the group assigned as the token's main control group.
109    #[serde(default)]
110    pub main_control_group: Option<GroupContractPosition>,
111
112    /// Defines whether and how the main control group assignment may be modified.
113    #[serde(default)]
114    pub main_control_group_can_be_modified: AuthorizedActionTakers,
115
116    /// Optional textual description of the token's purpose, behavior, or metadata.
117    #[serde(default)]
118    pub description: Option<String>,
119}
120
121// Default function for `keeps_history`
122fn default_keeps_history() -> bool {
123    true // Default to `true` for keeps_history
124}
125
126// Default function for `starts_as_paused`
127fn default_starts_as_paused() -> bool {
128    false
129}
130
131// Default function for `allow_transfer_to_frozen_balance`
132fn 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/// Represents predefined capability levels for token control presets.
244///
245/// `TokenConfigurationPresetFeatures` defines a hierarchy of governance capabilities
246/// that can be used to initialize rule sets for a token. Each variant enables a specific
247/// scope of permitted actions, allowing for simple selection of common governance models.
248///
249/// These presets are intended to be used in conjunction with `TokenConfigurationPreset`
250/// to simplify token setup and enforce governance constraints consistently.
251#[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    /// No actions are permitted after initialization. All governance and control
266    /// settings are immutable.
267    ///
268    /// Suitable for tokens that should remain fixed and tamper-proof.
269    MostRestrictive,
270
271    /// Only emergency actions (e.g., pausing the token) are permitted.
272    ///
273    /// Minting, burning, and advanced operations (such as freezing) are disallowed.
274    /// This preset allows minimal control for critical situations without risking
275    /// token supply or ownership manipulation.
276    WithOnlyEmergencyAction,
277
278    /// Allows minting and burning operations, but not advanced features such as freezing.
279    ///
280    /// Enables supply management without enabling full administrative capabilities.
281    WithMintingAndBurningActions,
282
283    /// Grants the ability to perform advanced actions, including freezing and unfreezing balances.
284    ///
285    /// Minting and burning are also permitted. Suitable for tokens that require
286    /// moderate administrative control without total override capabilities.
287    WithAllAdvancedActions,
288
289    /// The action taker is a god, he can do everything, even taking away his own power.
290    /// This grants unrestricted control to the action taker, including the ability to revoke
291    /// their own permissions or transfer all governance.
292    ///
293    /// This includes minting, burning, freezing, emergency actions, and full rule modification.
294    /// Should only be used with trusted or self-destructible authorities.
295    WithExtremeActions,
296}
297
298/// A high-level preset representing common configurations for token governance and control.
299///
300/// `TokenConfigurationPreset` provides a simplified way to initialize a set of
301/// predefined token rules (e.g., minting, burning, freezing, emergency actions)
302/// by selecting a feature set (`features`) and defining the authorized actor (`action_taker`)
303/// responsible for performing allowed actions.
304///
305/// This abstraction allows users to choose between common control configurations
306/// ranging from immutable tokens to fully administrator-controlled assets.
307#[derive(
308    Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq, Eq, PartialOrd, DecodeUntrusted,
309)]
310#[serde(rename_all = "camelCase")]
311pub struct TokenConfigurationPreset {
312    /// Defines the set of capabilities enabled in this preset (e.g., whether minting,
313    /// burning, freezing, or emergency actions are permitted).
314    ///
315    /// The selected feature set determines the default rule behavior for all change control
316    /// and governance actions within the token configuration.
317    pub features: TokenConfigurationPresetFeatures,
318
319    /// The identity or group authorized to perform actions defined by the preset.
320    ///
321    /// This includes acting as the admin for various rule changes, executing allowed token
322    /// operations, or performing emergency control (depending on the selected feature set).
323    pub action_taker: AuthorizedActionTakers,
324}
325
326// Manual impls because the preset types are flat (not versioned V0/V1).
327#[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        // `features` is a unit-only enum (bare PascalCase string);
363        // `actionTaker` uses AuthorizedActionTakers' internally-tagged shape.
364        // `position` is u16 — JSON erases the size; the value path locks it.
365        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    // --- default_main_control_group_can_be_modified ---
652
653    #[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    // --- default_basic_change_control_rules_v0 ---
709
710    #[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        // but not to no-one
752        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    // --- default_advanced_change_control_rules_v0 ---
780
781    #[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        // Minting/burning does NOT open up advanced operations -> advanced remains NoOne
802        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    // --- default_emergency_action_change_control_rules_v0 ---
847
848    #[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    // --- default_distribution_rules_v0 with/without direct pricing ---
905
906    #[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        // With direct pricing enabled, the rules match basic (extreme -> owner, all permissive)
912        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        // Without direct pricing, change_direct_purchase_pricing_rules is hard-coded to NoOne
926        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    // --- default_marketplace_rules_v0 ---
948
949    #[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    // --- token_configuration_v0 full config ---
960
961    #[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        // start_as_paused is fixed false by constructor
979        assert!(!config.start_as_paused);
980        assert!(config.allow_transfer_to_frozen_balance);
981        assert_eq!(config.main_control_group, None);
982        // extreme => main_control_group_can_be_modified becomes taker
983        assert_eq!(config.main_control_group_can_be_modified, taker);
984        // description is none
985        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        // keeps_history is TokenKeepsHistoryRules::V0; all fields should be true
1000        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    // --- default_most_restrictive + with_base_supply chaining ---
1032
1033    #[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    // --- Display trait ---
1051
1052    #[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    // --- all_used_group_positions: the interesting branches ---
1062
1063    #[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    // --- all_change_control_rules ---
1133
1134    #[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        // 13 rules total per the implementation
1149        assert_eq!(rules.len(), 13);
1150    }
1151
1152    // --- setters exercise the right fields ---
1153
1154    #[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}