dpp/data_contract/associated_token/token_distribution_rules/
mod.rs1#[cfg(feature = "json-conversion")]
2use crate::serialization::JsonConvertible;
3#[cfg(feature = "value-conversion")]
4use crate::serialization::ValueConvertible;
5use bincode::{Decode, DecodeUntrusted, Encode};
6use derive_more::From;
7use serde::{Deserialize, Serialize};
8
9pub mod accessors;
10mod methods;
11pub mod v0;
12pub mod v1;
13
14#[cfg_attr(feature = "json-conversion", derive(JsonConvertible))]
15#[cfg_attr(feature = "value-conversion", derive(ValueConvertible))]
16#[derive(
17 Serialize, Deserialize, Encode, Decode, Debug, Clone, PartialEq, Eq, From, DecodeUntrusted,
18)]
19#[serde(tag = "$formatVersion")]
20pub enum TokenDistributionRules {
21 #[serde(rename = "0")]
22 V0(TokenDistributionRulesV0),
23 #[serde(rename = "1")]
25 V1(TokenDistributionRulesV1),
26}
27
28use crate::data_contract::associated_token::token_distribution_rules::v0::TokenDistributionRulesV0;
29use crate::data_contract::associated_token::token_distribution_rules::v1::TokenDistributionRulesV1;
30use std::fmt;
31
32impl fmt::Display for TokenDistributionRules {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 match self {
35 TokenDistributionRules::V0(v0) => {
36 write!(f, "{}", v0) }
38 TokenDistributionRules::V1(v1) => {
39 write!(f, "{}", v1) }
41 }
42 }
43}
44
45#[cfg(all(
46 test,
47 feature = "json-conversion",
48 feature = "value-conversion",
49 feature = "serde-conversion"
50))]
51mod json_convertible_tests {
52 use super::*;
53 use crate::data_contract::associated_token::token_distribution_rules::v0::TokenDistributionRulesV0;
54 use crate::data_contract::change_control_rules::v0::ChangeControlRulesV0;
55 use crate::data_contract::change_control_rules::ChangeControlRules;
56 use platform_value::{platform_value, Identifier, Value};
57 use serde_json::json;
58
59 fn fixture() -> TokenDistributionRules {
63 let ccr = || ChangeControlRules::V0(ChangeControlRulesV0::default());
64 TokenDistributionRules::V0(TokenDistributionRulesV0 {
65 perpetual_distribution: None,
66 perpetual_distribution_rules: ccr(),
67 pre_programmed_distribution: None,
68 new_tokens_destination_identity: Some(Identifier::new([0x42; 32])),
69 new_tokens_destination_identity_rules: ccr(),
70 minting_allow_choosing_destination: true,
71 minting_allow_choosing_destination_rules: ccr(),
72 change_direct_purchase_pricing_rules: ccr(),
73 })
74 }
75
76 fn default_ccr_json() -> serde_json::Value {
77 json!({
78 "$formatVersion": "0",
79 "authorizedToMakeChange": {"$type": "noOne"},
80 "adminActionTakers": {"$type": "noOne"},
81 "changingAuthorizedActionTakersToNoOneAllowed": false,
82 "changingAdminActionTakersToNoOneAllowed": false,
83 "selfChangingAdminActionTakersAllowed": false,
84 })
85 }
86
87 fn default_ccr_value() -> Value {
88 platform_value!({
89 "$formatVersion": "0",
90 "authorizedToMakeChange": {"$type": "noOne"},
91 "adminActionTakers": {"$type": "noOne"},
92 "changingAuthorizedActionTakersToNoOneAllowed": false,
93 "changingAdminActionTakersToNoOneAllowed": false,
94 "selfChangingAdminActionTakersAllowed": false,
95 })
96 }
97
98 #[test]
99 fn json_round_trip_with_full_wire_shape() {
100 use crate::serialization::JsonConvertible;
101 let original = fixture();
102 let json = original.to_json().expect("to_json");
103 assert_eq!(
107 json,
108 json!({
109 "$formatVersion": "0",
110 "perpetualDistribution": null,
111 "perpetualDistributionRules": default_ccr_json(),
112 "preProgrammedDistribution": null,
113 "newTokensDestinationIdentity": "5TeWSsjg2gbxCyWVniXeCmwM7UtHTCK7svzJr5xYJzHf",
114 "newTokensDestinationIdentityRules": default_ccr_json(),
115 "mintingAllowChoosingDestination": true,
116 "mintingAllowChoosingDestinationRules": default_ccr_json(),
117 "changeDirectPurchasePricingRules": default_ccr_json(),
118 })
119 );
120 let recovered = TokenDistributionRules::from_json(json).expect("from_json");
121 assert_eq!(original, recovered);
122 }
123
124 #[test]
125 fn v1_json_round_trip_with_once_per_identity_distribution() {
126 use crate::data_contract::associated_token::token_distribution_rules::accessors::v1::{
127 TokenDistributionRulesV1Getters, TokenDistributionRulesV1Setters,
128 };
129 use crate::data_contract::associated_token::token_once_per_identity_distribution::v0::TokenOncePerIdentityDistributionV0;
130 use crate::data_contract::associated_token::token_once_per_identity_distribution::TokenOncePerIdentityDistribution;
131 use crate::serialization::JsonConvertible;
132 let mut rules = fixture();
134 let distribution =
135 TokenOncePerIdentityDistribution::V0(TokenOncePerIdentityDistributionV0 {
136 amount: 100,
137 });
138 rules.set_once_per_identity_distribution(Some(distribution.clone()));
139 assert!(matches!(rules, TokenDistributionRules::V1(_)));
140 assert_eq!(rules.once_per_identity_distribution(), Some(&distribution));
141
142 let json = rules.to_json().expect("to_json");
143 assert_eq!(
144 json,
145 json!({
146 "$formatVersion": "1",
147 "perpetualDistribution": null,
148 "perpetualDistributionRules": default_ccr_json(),
149 "preProgrammedDistribution": null,
150 "newTokensDestinationIdentity": "5TeWSsjg2gbxCyWVniXeCmwM7UtHTCK7svzJr5xYJzHf",
151 "newTokensDestinationIdentityRules": default_ccr_json(),
152 "mintingAllowChoosingDestination": true,
153 "mintingAllowChoosingDestinationRules": default_ccr_json(),
154 "changeDirectPurchasePricingRules": default_ccr_json(),
155 "oncePerIdentityDistribution": {
156 "$formatVersion": "0",
157 "amount": 100,
158 },
159 })
160 );
161 let recovered = TokenDistributionRules::from_json(json).expect("from_json");
162 assert_eq!(rules, recovered);
163 }
164
165 #[test]
166 fn clearing_once_per_identity_distribution_downgrades_v1_rules_to_v0() {
167 use crate::data_contract::associated_token::token_distribution_rules::accessors::v1::TokenDistributionRulesV1Setters;
168 use crate::data_contract::associated_token::token_once_per_identity_distribution::v0::TokenOncePerIdentityDistributionV0;
169 use crate::data_contract::associated_token::token_once_per_identity_distribution::TokenOncePerIdentityDistribution;
170 let mut rules = fixture();
173 rules.set_once_per_identity_distribution(Some(TokenOncePerIdentityDistribution::V0(
174 TokenOncePerIdentityDistributionV0 { amount: 100 },
175 )));
176 assert!(matches!(rules, TokenDistributionRules::V1(_)));
177 rules.set_once_per_identity_distribution(None);
178 assert_eq!(rules, fixture());
179 }
180
181 #[test]
182 fn v0_rules_stay_v0_when_clearing_once_per_identity_distribution() {
183 use crate::data_contract::associated_token::token_distribution_rules::accessors::v1::{
184 TokenDistributionRulesV1Getters, TokenDistributionRulesV1Setters,
185 };
186 let mut rules = fixture();
187 rules.set_once_per_identity_distribution(None);
188 assert_eq!(rules, fixture());
189 assert_eq!(rules.once_per_identity_distribution(), None);
190 }
191
192 #[test]
193 fn value_round_trip_with_full_wire_shape() {
194 use crate::serialization::ValueConvertible;
195 let original = fixture();
196 let value = original.to_object().expect("to_object");
197 let id = Identifier::new([0x42; 32]);
201 assert_eq!(
202 value,
203 platform_value!({
204 "$formatVersion": "0",
205 "perpetualDistribution": Value::Null,
206 "perpetualDistributionRules": default_ccr_value(),
207 "preProgrammedDistribution": Value::Null,
208 "newTokensDestinationIdentity": id,
209 "newTokensDestinationIdentityRules": default_ccr_value(),
210 "mintingAllowChoosingDestination": true,
211 "mintingAllowChoosingDestinationRules": default_ccr_value(),
212 "changeDirectPurchasePricingRules": default_ccr_value(),
213 })
214 );
215 let recovered = TokenDistributionRules::from_object(value).expect("from_object");
216 assert_eq!(original, recovered);
217 }
218}