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///
36/// An unknown key is refused rather than skipped. A token's configuration is fixed when the
37/// token is created, so a key this format version does not carry — `hasShieldedPool` written
38/// beside `$formatVersion: "0"`, say — would otherwise leave the token without what was asked
39/// for and with no way to add it later. The field set is closed: a later format version is a
40/// new generation, never a new field here. `TokenConfigurationV1` reads these fields through
41/// `serde(flatten)`, which does not carry the refusal, so a version 1 configuration is not
42/// held to it.
43#[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    /// Metadata conventions, including decimals and localizations.
48    pub conventions: TokenConfigurationConvention,
49
50    /// Change control rules governing who can modify the conventions field.
51    #[serde(default = "default_change_control_rules")]
52    pub conventions_change_rules: ChangeControlRules,
53
54    /// The initial token supply minted at creation.
55    #[serde(default)]
56    pub base_supply: TokenAmount,
57
58    /// The maximum allowable supply of the token.
59    ///
60    /// If `None`, the supply is unbounded unless otherwise constrained by minting logic.
61    #[serde(default)]
62    pub max_supply: Option<TokenAmount>,
63
64    /// Configuration governing which historical actions are recorded for this token.
65    #[serde(default = "default_token_keeps_history_rules")]
66    pub keeps_history: TokenKeepsHistoryRules,
67
68    /// Indicates whether the token should start in a paused state.
69    ///
70    /// When `true`, transfers are disallowed until explicitly unpaused via an emergency action.
71    #[serde(default = "default_starts_as_paused")]
72    pub start_as_paused: bool,
73
74    /// Allows minting and transferring to frozen token balances if enabled.
75    #[serde(default = "default_allow_transfer_to_frozen_balance")]
76    pub allow_transfer_to_frozen_balance: bool,
77
78    /// Change control rules for updating the `max_supply`.
79    ///
80    /// Note: The `max_supply` can never be reduced below the `base_supply`.
81    #[serde(default = "default_change_control_rules")]
82    pub max_supply_change_rules: ChangeControlRules,
83
84    /// Defines the token's distribution logic, including perpetual and pre-programmed distributions.
85    #[serde(default = "default_token_distribution_rules")]
86    pub distribution_rules: TokenDistributionRules,
87
88    /// Defines the token's marketplace logic.
89    #[serde(default = "default_token_marketplace_rules")]
90    pub marketplace_rules: TokenMarketplaceRules,
91
92    /// Rules controlling who is authorized to perform manual minting of tokens.
93    #[serde(default = "default_contract_owner_change_control_rules")]
94    pub manual_minting_rules: ChangeControlRules,
95
96    /// Rules controlling who is authorized to perform manual burning of tokens.
97    #[serde(default = "default_contract_owner_change_control_rules")]
98    pub manual_burning_rules: ChangeControlRules,
99
100    /// Rules governing who may freeze token balances.
101    #[serde(default = "default_change_control_rules")]
102    pub freeze_rules: ChangeControlRules,
103
104    /// Rules governing who may unfreeze token balances.
105    #[serde(default = "default_change_control_rules")]
106    pub unfreeze_rules: ChangeControlRules,
107
108    /// Rules governing who may destroy frozen funds.
109    #[serde(default = "default_change_control_rules")]
110    pub destroy_frozen_funds_rules: ChangeControlRules,
111
112    /// Rules governing who may invoke emergency actions, such as pausing transfers.
113    #[serde(default = "default_change_control_rules")]
114    pub emergency_action_rules: ChangeControlRules,
115
116    /// Optional reference to the group assigned as the token's main control group.
117    #[serde(default)]
118    pub main_control_group: Option<GroupContractPosition>,
119
120    /// Defines whether and how the main control group assignment may be modified.
121    #[serde(default)]
122    pub main_control_group_can_be_modified: AuthorizedActionTakers,
123
124    /// Optional textual description of the token's purpose, behavior, or metadata.
125    #[serde(default)]
126    pub description: Option<String>,
127}
128
129// Default function for `keeps_history`
130fn default_keeps_history() -> bool {
131    true // Default to `true` for keeps_history
132}
133
134// Default function for `starts_as_paused`
135fn default_starts_as_paused() -> bool {
136    false
137}
138
139// Default function for `allow_transfer_to_frozen_balance`
140fn 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/// Represents predefined capability levels for token control presets.
252///
253/// `TokenConfigurationPresetFeatures` defines a hierarchy of governance capabilities
254/// that can be used to initialize rule sets for a token. Each variant enables a specific
255/// scope of permitted actions, allowing for simple selection of common governance models.
256///
257/// These presets are intended to be used in conjunction with `TokenConfigurationPreset`
258/// to simplify token setup and enforce governance constraints consistently.
259#[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    /// No actions are permitted after initialization. All governance and control
274    /// settings are immutable.
275    ///
276    /// Suitable for tokens that should remain fixed and tamper-proof.
277    MostRestrictive,
278
279    /// Only emergency actions (e.g., pausing the token) are permitted.
280    ///
281    /// Minting, burning, and advanced operations (such as freezing) are disallowed.
282    /// This preset allows minimal control for critical situations without risking
283    /// token supply or ownership manipulation.
284    WithOnlyEmergencyAction,
285
286    /// Allows minting and burning operations, but not advanced features such as freezing.
287    ///
288    /// Enables supply management without enabling full administrative capabilities.
289    WithMintingAndBurningActions,
290
291    /// Grants the ability to perform advanced actions, including freezing and unfreezing balances.
292    ///
293    /// Minting and burning are also permitted. Suitable for tokens that require
294    /// moderate administrative control without total override capabilities.
295    WithAllAdvancedActions,
296
297    /// The action taker is a god, he can do everything, even taking away his own power.
298    /// This grants unrestricted control to the action taker, including the ability to revoke
299    /// their own permissions or transfer all governance.
300    ///
301    /// This includes minting, burning, freezing, emergency actions, and full rule modification.
302    /// Should only be used with trusted or self-destructible authorities.
303    WithExtremeActions,
304}
305
306/// A high-level preset representing common configurations for token governance and control.
307///
308/// `TokenConfigurationPreset` provides a simplified way to initialize a set of
309/// predefined token rules (e.g., minting, burning, freezing, emergency actions)
310/// by selecting a feature set (`features`) and defining the authorized actor (`action_taker`)
311/// responsible for performing allowed actions.
312///
313/// This abstraction allows users to choose between common control configurations
314/// ranging from immutable tokens to fully administrator-controlled assets.
315#[derive(
316    Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq, Eq, PartialOrd, DecodeUntrusted,
317)]
318#[serde(rename_all = "camelCase")]
319pub struct TokenConfigurationPreset {
320    /// Defines the set of capabilities enabled in this preset (e.g., whether minting,
321    /// burning, freezing, or emergency actions are permitted).
322    ///
323    /// The selected feature set determines the default rule behavior for all change control
324    /// and governance actions within the token configuration.
325    pub features: TokenConfigurationPresetFeatures,
326
327    /// The identity or group authorized to perform actions defined by the preset.
328    ///
329    /// This includes acting as the admin for various rule changes, executing allowed token
330    /// operations, or performing emergency control (depending on the selected feature set).
331    pub action_taker: AuthorizedActionTakers,
332}
333
334// Manual impls because the preset types are flat (not versioned V0/V1).
335#[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        // `features` is a unit-only enum (bare PascalCase string);
371        // `actionTaker` uses AuthorizedActionTakers' internally-tagged shape.
372        // `position` is u16 — JSON erases the size; the value path locks it.
373        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    // --- default_main_control_group_can_be_modified ---
660
661    #[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    // --- default_basic_change_control_rules_v0 ---
717
718    #[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        // but not to no-one
760        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    // --- default_advanced_change_control_rules_v0 ---
788
789    #[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        // Minting/burning does NOT open up advanced operations -> advanced remains NoOne
810        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    // --- default_emergency_action_change_control_rules_v0 ---
855
856    #[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    // --- default_distribution_rules_v0 with/without direct pricing ---
913
914    #[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        // With direct pricing enabled, the rules match basic (extreme -> owner, all permissive)
920        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        // Without direct pricing, change_direct_purchase_pricing_rules is hard-coded to NoOne
934        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    // --- default_marketplace_rules_v0 ---
956
957    #[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    // --- token_configuration_v0 full config ---
968
969    #[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        // start_as_paused is fixed false by constructor
987        assert!(!config.start_as_paused);
988        assert!(config.allow_transfer_to_frozen_balance);
989        assert_eq!(config.main_control_group, None);
990        // extreme => main_control_group_can_be_modified becomes taker
991        assert_eq!(config.main_control_group_can_be_modified, taker);
992        // description is none
993        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        // keeps_history is TokenKeepsHistoryRules::V0; all fields should be true
1008        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    // --- default_most_restrictive + with_base_supply chaining ---
1040
1041    #[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    // --- Display trait ---
1059
1060    #[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    // --- all_used_group_positions: the interesting branches ---
1070
1071    #[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    // --- all_change_control_rules ---
1141
1142    #[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        // 13 rules total per the implementation
1157        assert_eq!(rules.len(), 13);
1158    }
1159
1160    // --- setters exercise the right fields ---
1161
1162    #[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}