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, 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)]
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(Serialize, Deserialize, Decode, Encode, Debug, Clone, Copy, PartialEq, Eq, PartialOrd)]
252pub enum TokenConfigurationPresetFeatures {
253    /// No actions are permitted after initialization. All governance and control
254    /// settings are immutable.
255    ///
256    /// Suitable for tokens that should remain fixed and tamper-proof.
257    MostRestrictive,
258
259    /// Only emergency actions (e.g., pausing the token) are permitted.
260    ///
261    /// Minting, burning, and advanced operations (such as freezing) are disallowed.
262    /// This preset allows minimal control for critical situations without risking
263    /// token supply or ownership manipulation.
264    WithOnlyEmergencyAction,
265
266    /// Allows minting and burning operations, but not advanced features such as freezing.
267    ///
268    /// Enables supply management without enabling full administrative capabilities.
269    WithMintingAndBurningActions,
270
271    /// Grants the ability to perform advanced actions, including freezing and unfreezing balances.
272    ///
273    /// Minting and burning are also permitted. Suitable for tokens that require
274    /// moderate administrative control without total override capabilities.
275    WithAllAdvancedActions,
276
277    /// The action taker is a god, he can do everything, even taking away his own power.
278    /// This grants unrestricted control to the action taker, including the ability to revoke
279    /// their own permissions or transfer all governance.
280    ///
281    /// This includes minting, burning, freezing, emergency actions, and full rule modification.
282    /// Should only be used with trusted or self-destructible authorities.
283    WithExtremeActions,
284}
285
286/// A high-level preset representing common configurations for token governance and control.
287///
288/// `TokenConfigurationPreset` provides a simplified way to initialize a set of
289/// predefined token rules (e.g., minting, burning, freezing, emergency actions)
290/// by selecting a feature set (`features`) and defining the authorized actor (`action_taker`)
291/// responsible for performing allowed actions.
292///
293/// This abstraction allows users to choose between common control configurations
294/// ranging from immutable tokens to fully administrator-controlled assets.
295#[derive(Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq, Eq, PartialOrd)]
296pub struct TokenConfigurationPreset {
297    /// Defines the set of capabilities enabled in this preset (e.g., whether minting,
298    /// burning, freezing, or emergency actions are permitted).
299    ///
300    /// The selected feature set determines the default rule behavior for all change control
301    /// and governance actions within the token configuration.
302    pub features: TokenConfigurationPresetFeatures,
303
304    /// The identity or group authorized to perform actions defined by the preset.
305    ///
306    /// This includes acting as the admin for various rule changes, executing allowed token
307    /// operations, or performing emergency control (depending on the selected feature set).
308    pub action_taker: AuthorizedActionTakers,
309}
310impl TokenConfigurationPreset {
311    pub fn default_main_control_group_can_be_modified(&self) -> AuthorizedActionTakers {
312        match self.features {
313            TokenConfigurationPresetFeatures::MostRestrictive
314            | TokenConfigurationPresetFeatures::WithOnlyEmergencyAction
315            | TokenConfigurationPresetFeatures::WithMintingAndBurningActions
316            | TokenConfigurationPresetFeatures::WithAllAdvancedActions => {
317                AuthorizedActionTakers::NoOne
318            }
319            TokenConfigurationPresetFeatures::WithExtremeActions => self.action_taker,
320        }
321    }
322    pub fn default_basic_change_control_rules_v0(&self) -> ChangeControlRulesV0 {
323        match self.features {
324            TokenConfigurationPresetFeatures::MostRestrictive
325            | TokenConfigurationPresetFeatures::WithOnlyEmergencyAction => ChangeControlRulesV0 {
326                authorized_to_make_change: AuthorizedActionTakers::NoOne,
327                admin_action_takers: AuthorizedActionTakers::NoOne,
328                changing_authorized_action_takers_to_no_one_allowed: false,
329                changing_admin_action_takers_to_no_one_allowed: false,
330                self_changing_admin_action_takers_allowed: false,
331            },
332            TokenConfigurationPresetFeatures::WithMintingAndBurningActions
333            | TokenConfigurationPresetFeatures::WithAllAdvancedActions => ChangeControlRulesV0 {
334                authorized_to_make_change: self.action_taker,
335                admin_action_takers: self.action_taker,
336                changing_authorized_action_takers_to_no_one_allowed: false,
337                changing_admin_action_takers_to_no_one_allowed: false,
338                self_changing_admin_action_takers_allowed: true,
339            },
340            TokenConfigurationPresetFeatures::WithExtremeActions => ChangeControlRulesV0 {
341                authorized_to_make_change: self.action_taker,
342                admin_action_takers: self.action_taker,
343                changing_authorized_action_takers_to_no_one_allowed: true,
344                changing_admin_action_takers_to_no_one_allowed: true,
345                self_changing_admin_action_takers_allowed: true,
346            },
347        }
348    }
349
350    pub fn default_advanced_change_control_rules_v0(&self) -> ChangeControlRulesV0 {
351        match self.features {
352            TokenConfigurationPresetFeatures::MostRestrictive
353            | TokenConfigurationPresetFeatures::WithOnlyEmergencyAction
354            | TokenConfigurationPresetFeatures::WithMintingAndBurningActions => {
355                ChangeControlRulesV0 {
356                    authorized_to_make_change: AuthorizedActionTakers::NoOne,
357                    admin_action_takers: AuthorizedActionTakers::NoOne,
358                    changing_authorized_action_takers_to_no_one_allowed: false,
359                    changing_admin_action_takers_to_no_one_allowed: false,
360                    self_changing_admin_action_takers_allowed: false,
361                }
362            }
363            TokenConfigurationPresetFeatures::WithAllAdvancedActions => ChangeControlRulesV0 {
364                authorized_to_make_change: self.action_taker,
365                admin_action_takers: self.action_taker,
366                changing_authorized_action_takers_to_no_one_allowed: false,
367                changing_admin_action_takers_to_no_one_allowed: false,
368                self_changing_admin_action_takers_allowed: true,
369            },
370            TokenConfigurationPresetFeatures::WithExtremeActions => ChangeControlRulesV0 {
371                authorized_to_make_change: self.action_taker,
372                admin_action_takers: self.action_taker,
373                changing_authorized_action_takers_to_no_one_allowed: true,
374                changing_admin_action_takers_to_no_one_allowed: true,
375                self_changing_admin_action_takers_allowed: true,
376            },
377        }
378    }
379
380    pub fn default_emergency_action_change_control_rules_v0(&self) -> ChangeControlRulesV0 {
381        match self.features {
382            TokenConfigurationPresetFeatures::MostRestrictive => ChangeControlRulesV0 {
383                authorized_to_make_change: AuthorizedActionTakers::NoOne,
384                admin_action_takers: AuthorizedActionTakers::NoOne,
385                changing_authorized_action_takers_to_no_one_allowed: false,
386                changing_admin_action_takers_to_no_one_allowed: false,
387                self_changing_admin_action_takers_allowed: false,
388            },
389            TokenConfigurationPresetFeatures::WithAllAdvancedActions
390            | TokenConfigurationPresetFeatures::WithMintingAndBurningActions
391            | TokenConfigurationPresetFeatures::WithOnlyEmergencyAction => ChangeControlRulesV0 {
392                authorized_to_make_change: self.action_taker,
393                admin_action_takers: self.action_taker,
394                changing_authorized_action_takers_to_no_one_allowed: false,
395                changing_admin_action_takers_to_no_one_allowed: false,
396                self_changing_admin_action_takers_allowed: true,
397            },
398            TokenConfigurationPresetFeatures::WithExtremeActions => ChangeControlRulesV0 {
399                authorized_to_make_change: self.action_taker,
400                admin_action_takers: self.action_taker,
401                changing_authorized_action_takers_to_no_one_allowed: true,
402                changing_admin_action_takers_to_no_one_allowed: true,
403                self_changing_admin_action_takers_allowed: true,
404            },
405        }
406    }
407
408    pub fn default_distribution_rules_v0(
409        &self,
410        perpetual_distribution: Option<TokenPerpetualDistribution>,
411        pre_programmed_distribution: Option<TokenPreProgrammedDistribution>,
412        with_direct_pricing: bool,
413    ) -> TokenDistributionRulesV0 {
414        TokenDistributionRulesV0 {
415            perpetual_distribution,
416            perpetual_distribution_rules: self.default_advanced_change_control_rules_v0().into(),
417            pre_programmed_distribution,
418            new_tokens_destination_identity: None,
419            new_tokens_destination_identity_rules: self
420                .default_basic_change_control_rules_v0()
421                .into(),
422            minting_allow_choosing_destination: true,
423            minting_allow_choosing_destination_rules: self
424                .default_basic_change_control_rules_v0()
425                .into(),
426            change_direct_purchase_pricing_rules: if with_direct_pricing {
427                self.default_basic_change_control_rules_v0().into()
428            } else {
429                ChangeControlRulesV0 {
430                    authorized_to_make_change: AuthorizedActionTakers::NoOne,
431                    admin_action_takers: AuthorizedActionTakers::NoOne,
432                    changing_authorized_action_takers_to_no_one_allowed: false,
433                    changing_admin_action_takers_to_no_one_allowed: false,
434                    self_changing_admin_action_takers_allowed: false,
435                }
436                .into()
437            },
438        }
439    }
440
441    pub fn default_marketplace_rules_v0(&self) -> TokenMarketplaceRulesV0 {
442        TokenMarketplaceRulesV0 {
443            trade_mode: TokenTradeMode::NotTradeable,
444            trade_mode_change_rules: self.default_basic_change_control_rules_v0().into(),
445        }
446    }
447
448    pub fn token_configuration_v0(
449        &self,
450        conventions: TokenConfigurationConvention,
451        base_supply: TokenAmount,
452        max_supply: Option<TokenAmount>,
453        keeps_all_history: bool,
454        with_direct_pricing: bool,
455    ) -> TokenConfigurationV0 {
456        TokenConfigurationV0 {
457            conventions,
458            conventions_change_rules: self.default_basic_change_control_rules_v0().into(),
459            base_supply,
460            max_supply,
461            keeps_history: TokenKeepsHistoryRulesV0::default_for_keeping_all_history(
462                keeps_all_history,
463            )
464            .into(),
465            start_as_paused: false,
466            allow_transfer_to_frozen_balance: true,
467            max_supply_change_rules: self.default_advanced_change_control_rules_v0().into(),
468            distribution_rules: self
469                .default_distribution_rules_v0(None, None, with_direct_pricing)
470                .into(),
471            marketplace_rules: self.default_marketplace_rules_v0().into(),
472            manual_minting_rules: self.default_basic_change_control_rules_v0().into(),
473            manual_burning_rules: self.default_basic_change_control_rules_v0().into(),
474            freeze_rules: self.default_advanced_change_control_rules_v0().into(),
475            unfreeze_rules: self.default_advanced_change_control_rules_v0().into(),
476            destroy_frozen_funds_rules: self.default_advanced_change_control_rules_v0().into(),
477            emergency_action_rules: self
478                .default_emergency_action_change_control_rules_v0()
479                .into(),
480            main_control_group: None,
481            main_control_group_can_be_modified: self.default_main_control_group_can_be_modified(),
482            description: None,
483        }
484    }
485}
486
487impl TokenConfigurationV0 {
488    pub fn default_most_restrictive() -> Self {
489        TokenConfigurationPreset {
490            features: TokenConfigurationPresetFeatures::MostRestrictive,
491            action_taker: AuthorizedActionTakers::NoOne,
492        }
493        .token_configuration_v0(
494            TokenConfigurationConvention::V0(TokenConfigurationConventionV0 {
495                localizations: Default::default(),
496                decimals: 8,
497            }),
498            100000,
499            None,
500            true,
501            false,
502        )
503    }
504
505    pub fn with_base_supply(mut self, base_supply: TokenAmount) -> Self {
506        self.base_supply = base_supply;
507        self
508    }
509}