1use crate::balances::credits::TokenAmount;
2use crate::data_contract::associated_token::token_configuration_convention::TokenConfigurationConvention;
3use crate::data_contract::associated_token::token_marketplace_rules::v0::TokenTradeMode;
4use crate::data_contract::associated_token::token_perpetual_distribution::TokenPerpetualDistribution;
5use crate::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers;
6use crate::data_contract::GroupContractPosition;
7#[cfg(all(feature = "json-conversion", feature = "serde-conversion"))]
8use crate::serialization::JsonConvertible;
9#[cfg(all(feature = "value-conversion", feature = "serde-conversion"))]
10use crate::serialization::ValueConvertible;
11use crate::ProtocolError;
12use bincode::{DecodeUntrusted, Encode};
13use platform_serialization::de::Decode;
14use platform_serialization_derive::{
15 PlatformDeserializeTrusted, PlatformDeserializeUntrusted, PlatformSerialize,
16};
17use platform_value::Identifier;
18#[cfg(feature = "serde-conversion")]
19use serde::{Deserialize, Serialize};
20use std::fmt;
21
22#[derive(
23 Debug,
24 Clone,
25 Default,
26 PartialOrd,
27 Encode,
28 Decode,
29 PlatformSerialize,
30 PlatformDeserializeTrusted,
31 PlatformDeserializeUntrusted,
32 PartialEq,
33 Eq,
34 DecodeUntrusted,
35)]
36#[cfg_attr(
37 feature = "serde-conversion",
38 derive(Serialize, Deserialize),
39 serde(
40 into = "TokenConfigurationChangeItemRepr",
41 from = "TokenConfigurationChangeItemRepr"
42 )
43)]
44pub enum TokenConfigurationChangeItem {
45 #[default]
46 TokenConfigurationNoChange,
47 Conventions(TokenConfigurationConvention),
48 ConventionsControlGroup(AuthorizedActionTakers),
49 ConventionsAdminGroup(AuthorizedActionTakers),
50 MaxSupply(Option<TokenAmount>),
51 MaxSupplyControlGroup(AuthorizedActionTakers),
52 MaxSupplyAdminGroup(AuthorizedActionTakers),
53 PerpetualDistribution(Option<TokenPerpetualDistribution>),
54 PerpetualDistributionControlGroup(AuthorizedActionTakers),
55 PerpetualDistributionAdminGroup(AuthorizedActionTakers),
56 NewTokensDestinationIdentity(Option<Identifier>),
57 NewTokensDestinationIdentityControlGroup(AuthorizedActionTakers),
58 NewTokensDestinationIdentityAdminGroup(AuthorizedActionTakers),
59 MintingAllowChoosingDestination(bool),
60 MintingAllowChoosingDestinationControlGroup(AuthorizedActionTakers),
61 MintingAllowChoosingDestinationAdminGroup(AuthorizedActionTakers),
62 ManualMinting(AuthorizedActionTakers),
63 ManualMintingAdminGroup(AuthorizedActionTakers),
64 ManualBurning(AuthorizedActionTakers),
65 ManualBurningAdminGroup(AuthorizedActionTakers),
66 Freeze(AuthorizedActionTakers),
67 FreezeAdminGroup(AuthorizedActionTakers),
68 Unfreeze(AuthorizedActionTakers),
69 UnfreezeAdminGroup(AuthorizedActionTakers),
70 DestroyFrozenFunds(AuthorizedActionTakers),
71 DestroyFrozenFundsAdminGroup(AuthorizedActionTakers),
72 EmergencyAction(AuthorizedActionTakers),
73 EmergencyActionAdminGroup(AuthorizedActionTakers),
74 MarketplaceTradeMode(TokenTradeMode),
75 MarketplaceTradeModeControlGroup(AuthorizedActionTakers),
76 MarketplaceTradeModeAdminGroup(AuthorizedActionTakers),
77 MainControlGroup(Option<GroupContractPosition>),
78 MinimumPoolNotesForOutgoing(u64),
81 MinimumPoolNotesForOutgoingControlGroup(AuthorizedActionTakers),
82 MinimumPoolNotesForOutgoingAdminGroup(AuthorizedActionTakers),
83}
84
85macro_rules! token_configuration_v0_change_items {
91 () => {
92 TokenConfigurationChangeItem::TokenConfigurationNoChange
93 | TokenConfigurationChangeItem::Conventions(_)
94 | TokenConfigurationChangeItem::ConventionsControlGroup(_)
95 | TokenConfigurationChangeItem::ConventionsAdminGroup(_)
96 | TokenConfigurationChangeItem::MaxSupply(_)
97 | TokenConfigurationChangeItem::MaxSupplyControlGroup(_)
98 | TokenConfigurationChangeItem::MaxSupplyAdminGroup(_)
99 | TokenConfigurationChangeItem::PerpetualDistribution(_)
100 | TokenConfigurationChangeItem::PerpetualDistributionControlGroup(_)
101 | TokenConfigurationChangeItem::PerpetualDistributionAdminGroup(_)
102 | TokenConfigurationChangeItem::NewTokensDestinationIdentity(_)
103 | TokenConfigurationChangeItem::NewTokensDestinationIdentityControlGroup(_)
104 | TokenConfigurationChangeItem::NewTokensDestinationIdentityAdminGroup(_)
105 | TokenConfigurationChangeItem::MintingAllowChoosingDestination(_)
106 | TokenConfigurationChangeItem::MintingAllowChoosingDestinationControlGroup(_)
107 | TokenConfigurationChangeItem::MintingAllowChoosingDestinationAdminGroup(_)
108 | TokenConfigurationChangeItem::ManualMinting(_)
109 | TokenConfigurationChangeItem::ManualMintingAdminGroup(_)
110 | TokenConfigurationChangeItem::ManualBurning(_)
111 | TokenConfigurationChangeItem::ManualBurningAdminGroup(_)
112 | TokenConfigurationChangeItem::Freeze(_)
113 | TokenConfigurationChangeItem::FreezeAdminGroup(_)
114 | TokenConfigurationChangeItem::Unfreeze(_)
115 | TokenConfigurationChangeItem::UnfreezeAdminGroup(_)
116 | TokenConfigurationChangeItem::DestroyFrozenFunds(_)
117 | TokenConfigurationChangeItem::DestroyFrozenFundsAdminGroup(_)
118 | TokenConfigurationChangeItem::EmergencyAction(_)
119 | TokenConfigurationChangeItem::EmergencyActionAdminGroup(_)
120 | TokenConfigurationChangeItem::MarketplaceTradeMode(_)
121 | TokenConfigurationChangeItem::MarketplaceTradeModeControlGroup(_)
122 | TokenConfigurationChangeItem::MarketplaceTradeModeAdminGroup(_)
123 | TokenConfigurationChangeItem::MainControlGroup(_)
124 };
125}
126pub(crate) use token_configuration_v0_change_items;
127
128#[cfg(feature = "serde-conversion")]
137macro_rules! token_configuration_change_item_repr {
138 (
139 unit: $unit:ident,
140 $( $variant:ident : $ty:ty $(, with = $with:literal)? );* $(;)?
141 ) => {
142 #[derive(Serialize, Deserialize)]
143 #[serde(tag = "$type", rename_all = "camelCase")]
144 enum TokenConfigurationChangeItemRepr {
145 $unit,
146 $( $variant {
147 $(#[serde(with = $with)])?
148 value: $ty,
149 } ),*
150 }
151
152 impl From<TokenConfigurationChangeItem> for TokenConfigurationChangeItemRepr {
153 fn from(item: TokenConfigurationChangeItem) -> Self {
154 match item {
155 TokenConfigurationChangeItem::$unit => Self::$unit,
156 $( TokenConfigurationChangeItem::$variant(value) => Self::$variant { value }, )*
157 }
158 }
159 }
160
161 impl From<TokenConfigurationChangeItemRepr> for TokenConfigurationChangeItem {
162 fn from(repr: TokenConfigurationChangeItemRepr) -> Self {
163 match repr {
164 TokenConfigurationChangeItemRepr::$unit => Self::$unit,
165 $( TokenConfigurationChangeItemRepr::$variant { value } => Self::$variant(value), )*
166 }
167 }
168 }
169 };
170}
171
172#[cfg(feature = "serde-conversion")]
173token_configuration_change_item_repr! {
174 unit: TokenConfigurationNoChange,
175 Conventions: TokenConfigurationConvention;
176 ConventionsControlGroup: AuthorizedActionTakers;
177 ConventionsAdminGroup: AuthorizedActionTakers;
178 MaxSupply: Option<TokenAmount>, with = "crate::serialization::json_safe_option_u64";
179 MaxSupplyControlGroup: AuthorizedActionTakers;
180 MaxSupplyAdminGroup: AuthorizedActionTakers;
181 PerpetualDistribution: Option<TokenPerpetualDistribution>;
182 PerpetualDistributionControlGroup: AuthorizedActionTakers;
183 PerpetualDistributionAdminGroup: AuthorizedActionTakers;
184 NewTokensDestinationIdentity: Option<Identifier>;
185 NewTokensDestinationIdentityControlGroup: AuthorizedActionTakers;
186 NewTokensDestinationIdentityAdminGroup: AuthorizedActionTakers;
187 MintingAllowChoosingDestination: bool;
188 MintingAllowChoosingDestinationControlGroup: AuthorizedActionTakers;
189 MintingAllowChoosingDestinationAdminGroup: AuthorizedActionTakers;
190 ManualMinting: AuthorizedActionTakers;
191 ManualMintingAdminGroup: AuthorizedActionTakers;
192 ManualBurning: AuthorizedActionTakers;
193 ManualBurningAdminGroup: AuthorizedActionTakers;
194 Freeze: AuthorizedActionTakers;
195 FreezeAdminGroup: AuthorizedActionTakers;
196 Unfreeze: AuthorizedActionTakers;
197 UnfreezeAdminGroup: AuthorizedActionTakers;
198 DestroyFrozenFunds: AuthorizedActionTakers;
199 DestroyFrozenFundsAdminGroup: AuthorizedActionTakers;
200 EmergencyAction: AuthorizedActionTakers;
201 EmergencyActionAdminGroup: AuthorizedActionTakers;
202 MarketplaceTradeMode: TokenTradeMode;
203 MarketplaceTradeModeControlGroup: AuthorizedActionTakers;
204 MarketplaceTradeModeAdminGroup: AuthorizedActionTakers;
205 MainControlGroup: Option<GroupContractPosition>;
206 MinimumPoolNotesForOutgoing: u64, with = "crate::serialization::json_safe_u64";
207 MinimumPoolNotesForOutgoingControlGroup: AuthorizedActionTakers;
208 MinimumPoolNotesForOutgoingAdminGroup: AuthorizedActionTakers;
209}
210
211impl TokenConfigurationChangeItem {
212 pub fn payload_serialization(&self) -> Result<Option<Vec<u8>>, ProtocolError> {
213 Ok(match self {
214 TokenConfigurationChangeItem::TokenConfigurationNoChange => None,
215 TokenConfigurationChangeItem::Conventions(convention) => Some(
216 bincode::encode_to_vec(convention, bincode::config::standard())
217 .map_err(|e| ProtocolError::EncodingError(e.to_string()))?,
218 ),
219 TokenConfigurationChangeItem::ConventionsControlGroup(a)
220 | TokenConfigurationChangeItem::ConventionsAdminGroup(a)
221 | TokenConfigurationChangeItem::MaxSupplyControlGroup(a)
222 | TokenConfigurationChangeItem::MaxSupplyAdminGroup(a)
223 | TokenConfigurationChangeItem::PerpetualDistributionControlGroup(a)
224 | TokenConfigurationChangeItem::PerpetualDistributionAdminGroup(a)
225 | TokenConfigurationChangeItem::NewTokensDestinationIdentityControlGroup(a)
226 | TokenConfigurationChangeItem::NewTokensDestinationIdentityAdminGroup(a)
227 | TokenConfigurationChangeItem::MintingAllowChoosingDestinationControlGroup(a)
228 | TokenConfigurationChangeItem::MintingAllowChoosingDestinationAdminGroup(a)
229 | TokenConfigurationChangeItem::ManualMinting(a)
230 | TokenConfigurationChangeItem::ManualMintingAdminGroup(a)
231 | TokenConfigurationChangeItem::ManualBurning(a)
232 | TokenConfigurationChangeItem::ManualBurningAdminGroup(a)
233 | TokenConfigurationChangeItem::Freeze(a)
234 | TokenConfigurationChangeItem::FreezeAdminGroup(a)
235 | TokenConfigurationChangeItem::Unfreeze(a)
236 | TokenConfigurationChangeItem::UnfreezeAdminGroup(a)
237 | TokenConfigurationChangeItem::DestroyFrozenFunds(a)
238 | TokenConfigurationChangeItem::DestroyFrozenFundsAdminGroup(a)
239 | TokenConfigurationChangeItem::EmergencyAction(a)
240 | TokenConfigurationChangeItem::EmergencyActionAdminGroup(a)
241 | TokenConfigurationChangeItem::MarketplaceTradeModeControlGroup(a)
242 | TokenConfigurationChangeItem::MarketplaceTradeModeAdminGroup(a)
243 | TokenConfigurationChangeItem::MinimumPoolNotesForOutgoingControlGroup(a)
244 | TokenConfigurationChangeItem::MinimumPoolNotesForOutgoingAdminGroup(a) => {
245 Some(a.to_bytes())
246 }
247 TokenConfigurationChangeItem::MaxSupply(max_supply) => {
248 max_supply.map(|amount| amount.to_be_bytes().to_vec())
249 }
250 TokenConfigurationChangeItem::PerpetualDistribution(distribution) => distribution
251 .as_ref()
252 .map(|dist| {
253 bincode::encode_to_vec(dist, bincode::config::standard())
254 .map_err(|e| ProtocolError::EncodingError(e.to_string()))
255 })
256 .transpose()?,
257 TokenConfigurationChangeItem::NewTokensDestinationIdentity(identity) => {
258 identity.map(|id| id.to_vec())
259 }
260 TokenConfigurationChangeItem::MintingAllowChoosingDestination(allow) => {
261 Some(vec![*allow as u8])
262 }
263 TokenConfigurationChangeItem::MarketplaceTradeMode(mode) => Some(
264 bincode::encode_to_vec(mode, bincode::config::standard())
265 .map_err(|e| ProtocolError::EncodingError(e.to_string()))?,
266 ),
267 TokenConfigurationChangeItem::MainControlGroup(position) => {
268 position.map(|pos| pos.to_be_bytes().to_vec())
269 }
270 TokenConfigurationChangeItem::MinimumPoolNotesForOutgoing(minimum_pool_notes) => {
271 Some(minimum_pool_notes.to_be_bytes().to_vec())
272 }
273 })
274 }
275 pub fn u8_item_index(&self) -> u8 {
276 match self {
277 TokenConfigurationChangeItem::TokenConfigurationNoChange => 0,
278 TokenConfigurationChangeItem::Conventions(_) => 1,
279 TokenConfigurationChangeItem::ConventionsControlGroup(_) => 2,
280 TokenConfigurationChangeItem::ConventionsAdminGroup(_) => 3,
281 TokenConfigurationChangeItem::MaxSupply(_) => 4,
282 TokenConfigurationChangeItem::MaxSupplyControlGroup(_) => 5,
283 TokenConfigurationChangeItem::MaxSupplyAdminGroup(_) => 6,
284 TokenConfigurationChangeItem::PerpetualDistribution(_) => 7,
285 TokenConfigurationChangeItem::PerpetualDistributionControlGroup(_) => 8,
286 TokenConfigurationChangeItem::PerpetualDistributionAdminGroup(_) => 9,
287 TokenConfigurationChangeItem::NewTokensDestinationIdentity(_) => 10,
288 TokenConfigurationChangeItem::NewTokensDestinationIdentityControlGroup(_) => 11,
289 TokenConfigurationChangeItem::NewTokensDestinationIdentityAdminGroup(_) => 12,
290 TokenConfigurationChangeItem::MintingAllowChoosingDestination(_) => 13,
291 TokenConfigurationChangeItem::MintingAllowChoosingDestinationControlGroup(_) => 14,
292 TokenConfigurationChangeItem::MintingAllowChoosingDestinationAdminGroup(_) => 15,
293 TokenConfigurationChangeItem::ManualMinting(_) => 16,
294 TokenConfigurationChangeItem::ManualMintingAdminGroup(_) => 17,
295 TokenConfigurationChangeItem::ManualBurning(_) => 18,
296 TokenConfigurationChangeItem::ManualBurningAdminGroup(_) => 19,
297 TokenConfigurationChangeItem::Freeze(_) => 20,
298 TokenConfigurationChangeItem::FreezeAdminGroup(_) => 21,
299 TokenConfigurationChangeItem::Unfreeze(_) => 22,
300 TokenConfigurationChangeItem::UnfreezeAdminGroup(_) => 23,
301 TokenConfigurationChangeItem::DestroyFrozenFunds(_) => 24,
302 TokenConfigurationChangeItem::DestroyFrozenFundsAdminGroup(_) => 25,
303 TokenConfigurationChangeItem::EmergencyAction(_) => 26,
304 TokenConfigurationChangeItem::EmergencyActionAdminGroup(_) => 27,
305 TokenConfigurationChangeItem::MarketplaceTradeMode(_) => 28,
306 TokenConfigurationChangeItem::MarketplaceTradeModeControlGroup(_) => 29,
307 TokenConfigurationChangeItem::MarketplaceTradeModeAdminGroup(_) => 30,
308 TokenConfigurationChangeItem::MainControlGroup(_) => 31,
309 TokenConfigurationChangeItem::MinimumPoolNotesForOutgoing(_) => 32,
310 TokenConfigurationChangeItem::MinimumPoolNotesForOutgoingControlGroup(_) => 33,
311 TokenConfigurationChangeItem::MinimumPoolNotesForOutgoingAdminGroup(_) => 34,
312 }
313 }
314}
315
316impl fmt::Display for TokenConfigurationChangeItem {
317 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
318 match self {
319 TokenConfigurationChangeItem::TokenConfigurationNoChange => {
320 write!(f, "No Change in Token Configuration")
321 }
322 TokenConfigurationChangeItem::Conventions(convention) => {
323 write!(f, "Conventions: {}", convention)
324 }
325 TokenConfigurationChangeItem::ConventionsControlGroup(control_group) => {
326 write!(f, "Conventions Control Group: {}", control_group)
327 }
328 TokenConfigurationChangeItem::ConventionsAdminGroup(admin_group) => {
329 write!(f, "Conventions Admin Group: {}", admin_group)
330 }
331 TokenConfigurationChangeItem::MaxSupply(max_supply) => match max_supply {
332 Some(amount) => write!(f, "Max Supply: {}", amount),
333 None => write!(f, "Max Supply: No Limit"),
334 },
335 TokenConfigurationChangeItem::MaxSupplyControlGroup(control_group) => {
336 write!(f, "Max Supply Control Group: {}", control_group)
337 }
338 TokenConfigurationChangeItem::MaxSupplyAdminGroup(admin_group) => {
339 write!(f, "Max Supply Admin Group: {}", admin_group)
340 }
341 TokenConfigurationChangeItem::PerpetualDistribution(distribution) => match distribution
342 {
343 Some(dist) => write!(f, "Perpetual Distribution: {}", dist),
344 None => write!(f, "Perpetual Distribution: None"),
345 },
346 TokenConfigurationChangeItem::PerpetualDistributionControlGroup(control_group) => {
347 write!(f, "Perpetual Distribution Control Group: {}", control_group)
348 }
349 TokenConfigurationChangeItem::PerpetualDistributionAdminGroup(admin_group) => {
350 write!(f, "Perpetual Distribution Admin Group: {}", admin_group)
351 }
352 TokenConfigurationChangeItem::NewTokensDestinationIdentity(identity) => {
353 match identity {
354 Some(id) => write!(f, "New Tokens Destination Identity: {}", id),
355 None => write!(f, "New Tokens Destination Identity: None"),
356 }
357 }
358 TokenConfigurationChangeItem::NewTokensDestinationIdentityControlGroup(
359 control_group,
360 ) => {
361 write!(
362 f,
363 "New Tokens Destination Identity Control Group: {}",
364 control_group
365 )
366 }
367 TokenConfigurationChangeItem::NewTokensDestinationIdentityAdminGroup(admin_group) => {
368 write!(
369 f,
370 "New Tokens Destination Identity Admin Group: {}",
371 admin_group
372 )
373 }
374 TokenConfigurationChangeItem::MintingAllowChoosingDestination(allow) => {
375 write!(f, "Minting Allow Choosing Destination: {}", allow)
376 }
377 TokenConfigurationChangeItem::MintingAllowChoosingDestinationControlGroup(
378 control_group,
379 ) => {
380 write!(
381 f,
382 "Minting Allow Choosing Destination Control Group: {}",
383 control_group
384 )
385 }
386 TokenConfigurationChangeItem::MintingAllowChoosingDestinationAdminGroup(
387 admin_group,
388 ) => {
389 write!(
390 f,
391 "Minting Allow Choosing Destination Admin Group: {}",
392 admin_group
393 )
394 }
395 TokenConfigurationChangeItem::ManualMinting(control_group) => {
396 write!(f, "Manual Minting: {}", control_group)
397 }
398 TokenConfigurationChangeItem::ManualMintingAdminGroup(admin_group) => {
399 write!(f, "Manual Minting Admin Group: {}", admin_group)
400 }
401 TokenConfigurationChangeItem::ManualBurning(control_group) => {
402 write!(f, "Manual Burning: {}", control_group)
403 }
404 TokenConfigurationChangeItem::ManualBurningAdminGroup(admin_group) => {
405 write!(f, "Manual Burning Admin Group: {}", admin_group)
406 }
407 TokenConfigurationChangeItem::Freeze(control_group) => {
408 write!(f, "Freeze: {}", control_group)
409 }
410 TokenConfigurationChangeItem::FreezeAdminGroup(admin_group) => {
411 write!(f, "Freeze Admin Group: {}", admin_group)
412 }
413 TokenConfigurationChangeItem::Unfreeze(control_group) => {
414 write!(f, "Unfreeze: {}", control_group)
415 }
416 TokenConfigurationChangeItem::UnfreezeAdminGroup(admin_group) => {
417 write!(f, "Unfreeze Admin Group: {}", admin_group)
418 }
419 TokenConfigurationChangeItem::DestroyFrozenFunds(control_group) => {
420 write!(f, "Destroy Frozen Funds: {}", control_group)
421 }
422 TokenConfigurationChangeItem::DestroyFrozenFundsAdminGroup(admin_group) => {
423 write!(f, "Destroy Frozen Funds Admin Group: {}", admin_group)
424 }
425 TokenConfigurationChangeItem::EmergencyAction(control_group) => {
426 write!(f, "Emergency Action: {}", control_group)
427 }
428 TokenConfigurationChangeItem::EmergencyActionAdminGroup(admin_group) => {
429 write!(f, "Emergency Action Admin Group: {}", admin_group)
430 }
431 TokenConfigurationChangeItem::MainControlGroup(position) => match position {
432 Some(pos) => write!(f, "Main Control Group: {}", pos),
433 None => write!(f, "Main Control Group: None"),
434 },
435 TokenConfigurationChangeItem::MarketplaceTradeMode(mode) => {
436 write!(f, "Marketplace Trade Mode: {:?}", mode)
437 }
438 TokenConfigurationChangeItem::MarketplaceTradeModeControlGroup(control_group) => {
439 write!(f, "Marketplace Trade Mode Control Group: {}", control_group)
440 }
441 TokenConfigurationChangeItem::MarketplaceTradeModeAdminGroup(admin_group) => {
442 write!(f, "Marketplace Trade Mode Admin Group: {}", admin_group)
443 }
444 TokenConfigurationChangeItem::MinimumPoolNotesForOutgoing(minimum_pool_notes) => {
445 write!(f, "Minimum Pool Notes For Outgoing: {}", minimum_pool_notes)
446 }
447 TokenConfigurationChangeItem::MinimumPoolNotesForOutgoingControlGroup(
448 control_group,
449 ) => {
450 write!(
451 f,
452 "Minimum Pool Notes For Outgoing Control Group: {}",
453 control_group
454 )
455 }
456 TokenConfigurationChangeItem::MinimumPoolNotesForOutgoingAdminGroup(admin_group) => {
457 write!(
458 f,
459 "Minimum Pool Notes For Outgoing Admin Group: {}",
460 admin_group
461 )
462 }
463 }
464 }
465}
466
467#[cfg(test)]
468mod tests {
469 use super::*;
470 use std::collections::BTreeSet;
471
472 fn all_variants() -> Vec<TokenConfigurationChangeItem> {
474 let aat = AuthorizedActionTakers::NoOne;
475 vec![
476 TokenConfigurationChangeItem::TokenConfigurationNoChange,
477 TokenConfigurationChangeItem::Conventions(
478 TokenConfigurationConvention::V0(
479 crate::data_contract::associated_token::token_configuration_convention::v0::TokenConfigurationConventionV0::default(),
480 ),
481 ),
482 TokenConfigurationChangeItem::ConventionsControlGroup(aat),
483 TokenConfigurationChangeItem::ConventionsAdminGroup(aat),
484 TokenConfigurationChangeItem::MaxSupply(None),
485 TokenConfigurationChangeItem::MaxSupplyControlGroup(aat),
486 TokenConfigurationChangeItem::MaxSupplyAdminGroup(aat),
487 TokenConfigurationChangeItem::PerpetualDistribution(None),
488 TokenConfigurationChangeItem::PerpetualDistributionControlGroup(aat),
489 TokenConfigurationChangeItem::PerpetualDistributionAdminGroup(aat),
490 TokenConfigurationChangeItem::NewTokensDestinationIdentity(None),
491 TokenConfigurationChangeItem::NewTokensDestinationIdentityControlGroup(aat),
492 TokenConfigurationChangeItem::NewTokensDestinationIdentityAdminGroup(aat),
493 TokenConfigurationChangeItem::MintingAllowChoosingDestination(false),
494 TokenConfigurationChangeItem::MintingAllowChoosingDestinationControlGroup(aat),
495 TokenConfigurationChangeItem::MintingAllowChoosingDestinationAdminGroup(aat),
496 TokenConfigurationChangeItem::ManualMinting(aat),
497 TokenConfigurationChangeItem::ManualMintingAdminGroup(aat),
498 TokenConfigurationChangeItem::ManualBurning(aat),
499 TokenConfigurationChangeItem::ManualBurningAdminGroup(aat),
500 TokenConfigurationChangeItem::Freeze(aat),
501 TokenConfigurationChangeItem::FreezeAdminGroup(aat),
502 TokenConfigurationChangeItem::Unfreeze(aat),
503 TokenConfigurationChangeItem::UnfreezeAdminGroup(aat),
504 TokenConfigurationChangeItem::DestroyFrozenFunds(aat),
505 TokenConfigurationChangeItem::DestroyFrozenFundsAdminGroup(aat),
506 TokenConfigurationChangeItem::EmergencyAction(aat),
507 TokenConfigurationChangeItem::EmergencyActionAdminGroup(aat),
508 TokenConfigurationChangeItem::MarketplaceTradeMode(TokenTradeMode::default()),
509 TokenConfigurationChangeItem::MarketplaceTradeModeControlGroup(aat),
510 TokenConfigurationChangeItem::MarketplaceTradeModeAdminGroup(aat),
511 TokenConfigurationChangeItem::MainControlGroup(None),
512 TokenConfigurationChangeItem::MinimumPoolNotesForOutgoing(0),
513 TokenConfigurationChangeItem::MinimumPoolNotesForOutgoingControlGroup(aat),
514 TokenConfigurationChangeItem::MinimumPoolNotesForOutgoingAdminGroup(aat),
515 ]
516 }
517
518 fn discriminant_of(item: &TokenConfigurationChangeItem) -> u8 {
524 let bytes = bincode::encode_to_vec(item, bincode::config::standard())
525 .expect("expected to encode the change item");
526 bytes[0]
528 }
529
530 #[test]
531 fn change_item_discriminants_are_frozen() {
532 let aat = AuthorizedActionTakers::NoOne;
533 assert_eq!(
534 discriminant_of(&TokenConfigurationChangeItem::TokenConfigurationNoChange),
535 0
536 );
537 assert_eq!(
538 discriminant_of(&TokenConfigurationChangeItem::MainControlGroup(None)),
539 31
540 );
541 assert_eq!(
542 discriminant_of(&TokenConfigurationChangeItem::MinimumPoolNotesForOutgoing(
543 0
544 )),
545 32
546 );
547 assert_eq!(
548 discriminant_of(
549 &TokenConfigurationChangeItem::MinimumPoolNotesForOutgoingControlGroup(aat)
550 ),
551 33
552 );
553 assert_eq!(
554 discriminant_of(
555 &TokenConfigurationChangeItem::MinimumPoolNotesForOutgoingAdminGroup(aat)
556 ),
557 34
558 );
559 for item in all_variants() {
560 assert_eq!(
561 discriminant_of(&item),
562 item.u8_item_index(),
563 "bincode discriminant of {:?} moved",
564 item
565 );
566 }
567 }
568
569 #[test]
572 fn u8_item_index_values_are_unique() {
573 let variants = all_variants();
574 let indices: Vec<u8> = variants.iter().map(|v| v.u8_item_index()).collect();
575 let unique: BTreeSet<u8> = indices.iter().cloned().collect();
576 assert_eq!(
577 indices.len(),
578 unique.len(),
579 "Duplicate u8_item_index values found: {:?}",
580 indices
581 );
582 }
583
584 #[test]
585 fn u8_item_index_covers_0_through_34() {
586 let variants = all_variants();
587 let indices: BTreeSet<u8> = variants.iter().map(|v| v.u8_item_index()).collect();
588 for i in 0u8..=34 {
589 assert!(indices.contains(&i), "Missing u8_item_index value: {}", i);
590 }
591 }
592
593 #[test]
594 fn u8_item_index_all_within_range() {
595 let variants = all_variants();
596 for v in &variants {
597 let idx = v.u8_item_index();
598 assert!(idx <= 34, "Index {} exceeds expected max of 34", idx);
599 }
600 }
601
602 #[test]
603 fn u8_item_index_specific_known_values() {
604 assert_eq!(
605 TokenConfigurationChangeItem::TokenConfigurationNoChange.u8_item_index(),
606 0
607 );
608 assert_eq!(
609 TokenConfigurationChangeItem::MaxSupply(Some(100)).u8_item_index(),
610 4
611 );
612 assert_eq!(
613 TokenConfigurationChangeItem::ManualMinting(AuthorizedActionTakers::NoOne)
614 .u8_item_index(),
615 16
616 );
617 assert_eq!(
618 TokenConfigurationChangeItem::MainControlGroup(Some(5)).u8_item_index(),
619 31
620 );
621 assert_eq!(
622 TokenConfigurationChangeItem::MinimumPoolNotesForOutgoing(10).u8_item_index(),
623 32
624 );
625 assert_eq!(
626 TokenConfigurationChangeItem::MinimumPoolNotesForOutgoingControlGroup(
627 AuthorizedActionTakers::NoOne
628 )
629 .u8_item_index(),
630 33
631 );
632 assert_eq!(
633 TokenConfigurationChangeItem::MinimumPoolNotesForOutgoingAdminGroup(
634 AuthorizedActionTakers::NoOne
635 )
636 .u8_item_index(),
637 34
638 );
639 }
640
641 #[test]
642 fn u8_item_index_variant_count() {
643 let variants = all_variants();
645 assert_eq!(variants.len(), 35);
646 }
647
648 #[test]
651 fn payload_serialization_no_change_is_none() {
652 let item = TokenConfigurationChangeItem::TokenConfigurationNoChange;
653 assert!(item.payload_serialization().unwrap().is_none());
654 }
655
656 #[test]
657 fn payload_serialization_max_supply_none_is_none() {
658 let item = TokenConfigurationChangeItem::MaxSupply(None);
659 assert!(item.payload_serialization().unwrap().is_none());
660 }
661
662 #[test]
663 fn payload_serialization_max_supply_some_encodes_be_bytes() {
664 let amount: u64 = 0x0102_0304_0506_0708;
665 let item = TokenConfigurationChangeItem::MaxSupply(Some(amount));
666 let bytes = item.payload_serialization().unwrap().unwrap();
667 assert_eq!(bytes, amount.to_be_bytes().to_vec());
668 assert_eq!(bytes.len(), 8);
669 }
670
671 #[test]
672 fn payload_serialization_new_tokens_destination_identity_none_is_none() {
673 let item = TokenConfigurationChangeItem::NewTokensDestinationIdentity(None);
674 assert!(item.payload_serialization().unwrap().is_none());
675 }
676
677 #[test]
678 fn payload_serialization_new_tokens_destination_identity_some_is_32_bytes() {
679 let id = Identifier::from([0x77u8; 32]);
680 let item = TokenConfigurationChangeItem::NewTokensDestinationIdentity(Some(id));
681 let bytes = item.payload_serialization().unwrap().unwrap();
682 assert_eq!(bytes.len(), 32);
683 assert_eq!(bytes, vec![0x77u8; 32]);
684 }
685
686 #[test]
687 fn payload_serialization_perpetual_distribution_none_is_none() {
688 let item = TokenConfigurationChangeItem::PerpetualDistribution(None);
689 assert!(item.payload_serialization().unwrap().is_none());
690 }
691
692 #[test]
693 fn payload_serialization_main_control_group_none_is_none() {
694 let item = TokenConfigurationChangeItem::MainControlGroup(None);
695 assert!(item.payload_serialization().unwrap().is_none());
696 }
697
698 #[test]
699 fn payload_serialization_main_control_group_some_is_two_be_bytes() {
700 let pos: u16 = 0xABCD;
701 let item = TokenConfigurationChangeItem::MainControlGroup(Some(pos));
702 let bytes = item.payload_serialization().unwrap().unwrap();
703 assert_eq!(bytes, pos.to_be_bytes().to_vec());
704 assert_eq!(bytes.len(), 2);
705 }
706
707 #[test]
708 fn payload_serialization_minting_allow_choosing_destination_true() {
709 let item = TokenConfigurationChangeItem::MintingAllowChoosingDestination(true);
710 let bytes = item.payload_serialization().unwrap().unwrap();
711 assert_eq!(bytes, vec![1]);
712 }
713
714 #[test]
715 fn payload_serialization_minting_allow_choosing_destination_false() {
716 let item = TokenConfigurationChangeItem::MintingAllowChoosingDestination(false);
717 let bytes = item.payload_serialization().unwrap().unwrap();
718 assert_eq!(bytes, vec![0]);
719 }
720
721 #[test]
722 fn payload_serialization_authorized_action_takers_variants_use_to_bytes() {
723 let aat = AuthorizedActionTakers::ContractOwner;
726 let expected = aat.to_bytes();
727
728 let variants = [
729 TokenConfigurationChangeItem::ConventionsControlGroup(aat),
730 TokenConfigurationChangeItem::ConventionsAdminGroup(aat),
731 TokenConfigurationChangeItem::MaxSupplyControlGroup(aat),
732 TokenConfigurationChangeItem::MaxSupplyAdminGroup(aat),
733 TokenConfigurationChangeItem::PerpetualDistributionControlGroup(aat),
734 TokenConfigurationChangeItem::PerpetualDistributionAdminGroup(aat),
735 TokenConfigurationChangeItem::NewTokensDestinationIdentityControlGroup(aat),
736 TokenConfigurationChangeItem::NewTokensDestinationIdentityAdminGroup(aat),
737 TokenConfigurationChangeItem::MintingAllowChoosingDestinationControlGroup(aat),
738 TokenConfigurationChangeItem::MintingAllowChoosingDestinationAdminGroup(aat),
739 TokenConfigurationChangeItem::ManualMinting(aat),
740 TokenConfigurationChangeItem::ManualMintingAdminGroup(aat),
741 TokenConfigurationChangeItem::ManualBurning(aat),
742 TokenConfigurationChangeItem::ManualBurningAdminGroup(aat),
743 TokenConfigurationChangeItem::Freeze(aat),
744 TokenConfigurationChangeItem::FreezeAdminGroup(aat),
745 TokenConfigurationChangeItem::Unfreeze(aat),
746 TokenConfigurationChangeItem::UnfreezeAdminGroup(aat),
747 TokenConfigurationChangeItem::DestroyFrozenFunds(aat),
748 TokenConfigurationChangeItem::DestroyFrozenFundsAdminGroup(aat),
749 TokenConfigurationChangeItem::EmergencyAction(aat),
750 TokenConfigurationChangeItem::EmergencyActionAdminGroup(aat),
751 TokenConfigurationChangeItem::MarketplaceTradeModeControlGroup(aat),
752 TokenConfigurationChangeItem::MarketplaceTradeModeAdminGroup(aat),
753 ];
754 for v in &variants {
755 let bytes = v.payload_serialization().unwrap().unwrap();
756 assert_eq!(bytes, expected, "mismatch for variant {:?}", v);
757 }
758 }
759
760 #[test]
761 fn payload_serialization_conventions_roundtrips_via_bincode() {
762 use crate::data_contract::associated_token::token_configuration_convention::v0::TokenConfigurationConventionV0;
765 let convention = TokenConfigurationConvention::V0(TokenConfigurationConventionV0 {
766 localizations: Default::default(),
767 decimals: 5,
768 });
769 let item = TokenConfigurationChangeItem::Conventions(convention.clone());
770 let bytes = item.payload_serialization().unwrap().unwrap();
771 assert!(!bytes.is_empty());
772 let (decoded, _): (TokenConfigurationConvention, _) =
773 bincode::decode_from_slice(&bytes, bincode::config::standard()).unwrap();
774 assert_eq!(decoded, convention);
775 }
776
777 #[test]
778 fn payload_serialization_marketplace_trade_mode_produces_bytes() {
779 let item = TokenConfigurationChangeItem::MarketplaceTradeMode(TokenTradeMode::NotTradeable);
780 let bytes = item.payload_serialization().unwrap().unwrap();
781 assert!(!bytes.is_empty());
782 let (decoded, _): (TokenTradeMode, _) =
784 bincode::decode_from_slice(&bytes, bincode::config::standard()).unwrap();
785 assert_eq!(decoded, TokenTradeMode::NotTradeable);
786 }
787
788 #[test]
791 fn display_no_change() {
792 let s = format!(
793 "{}",
794 TokenConfigurationChangeItem::TokenConfigurationNoChange
795 );
796 assert_eq!(s, "No Change in Token Configuration");
797 }
798
799 #[test]
800 fn display_max_supply_some_vs_none() {
801 let some = format!("{}", TokenConfigurationChangeItem::MaxSupply(Some(500)));
802 let none = format!("{}", TokenConfigurationChangeItem::MaxSupply(None));
803 assert!(some.contains("500"));
804 assert!(none.contains("No Limit"));
805 }
806
807 #[test]
808 fn display_perpetual_distribution_none_uses_none_marker() {
809 let s = format!(
810 "{}",
811 TokenConfigurationChangeItem::PerpetualDistribution(None)
812 );
813 assert!(s.contains("None"));
814 }
815
816 #[test]
817 fn display_new_tokens_destination_identity_none_uses_none_marker() {
818 let s = format!(
819 "{}",
820 TokenConfigurationChangeItem::NewTokensDestinationIdentity(None)
821 );
822 assert!(s.contains("None"));
823 }
824
825 #[test]
826 fn display_new_tokens_destination_identity_some_includes_id() {
827 let id = Identifier::from([3u8; 32]);
828 let s = format!(
829 "{}",
830 TokenConfigurationChangeItem::NewTokensDestinationIdentity(Some(id))
831 );
832 assert!(s.contains("New Tokens Destination Identity"));
833 }
834
835 #[test]
836 fn display_main_control_group_none_uses_none_marker() {
837 let s = format!("{}", TokenConfigurationChangeItem::MainControlGroup(None));
838 assert!(s.contains("None"));
839 }
840
841 #[test]
842 fn display_main_control_group_some_contains_position() {
843 let s = format!(
844 "{}",
845 TokenConfigurationChangeItem::MainControlGroup(Some(7))
846 );
847 assert!(s.contains("7"));
848 }
849
850 #[test]
851 fn display_minting_allow_choosing_destination_contains_value() {
852 let s_true = format!(
853 "{}",
854 TokenConfigurationChangeItem::MintingAllowChoosingDestination(true)
855 );
856 let s_false = format!(
857 "{}",
858 TokenConfigurationChangeItem::MintingAllowChoosingDestination(false)
859 );
860 assert!(s_true.contains("true"));
861 assert!(s_false.contains("false"));
862 }
863
864 #[test]
865 fn display_marketplace_trade_mode_uses_debug() {
866 let s = format!(
867 "{}",
868 TokenConfigurationChangeItem::MarketplaceTradeMode(TokenTradeMode::NotTradeable)
869 );
870 assert!(s.contains("NotTradeable"));
871 }
872
873 #[test]
874 fn display_action_takers_group_variants() {
875 let aat = AuthorizedActionTakers::ContractOwner;
878 let cases = vec![
879 (
880 format!("{}", TokenConfigurationChangeItem::ManualMinting(aat)),
881 "Manual Minting",
882 ),
883 (
884 format!(
885 "{}",
886 TokenConfigurationChangeItem::ManualMintingAdminGroup(aat)
887 ),
888 "Manual Minting Admin Group",
889 ),
890 (
891 format!("{}", TokenConfigurationChangeItem::ManualBurning(aat)),
892 "Manual Burning",
893 ),
894 (
895 format!("{}", TokenConfigurationChangeItem::Freeze(aat)),
896 "Freeze",
897 ),
898 (
899 format!("{}", TokenConfigurationChangeItem::Unfreeze(aat)),
900 "Unfreeze",
901 ),
902 (
903 format!("{}", TokenConfigurationChangeItem::DestroyFrozenFunds(aat)),
904 "Destroy Frozen Funds",
905 ),
906 (
907 format!("{}", TokenConfigurationChangeItem::EmergencyAction(aat)),
908 "Emergency Action",
909 ),
910 (
911 format!(
912 "{}",
913 TokenConfigurationChangeItem::MarketplaceTradeModeControlGroup(aat)
914 ),
915 "Marketplace Trade Mode Control Group",
916 ),
917 (
918 format!(
919 "{}",
920 TokenConfigurationChangeItem::ConventionsControlGroup(aat)
921 ),
922 "Conventions Control Group",
923 ),
924 ];
925 for (output, expected_prefix) in cases {
926 assert!(
927 output.contains(expected_prefix),
928 "expected {:?} in {:?}",
929 expected_prefix,
930 output
931 );
932 }
933 }
934
935 #[test]
938 fn equality_same_variant_same_data() {
939 let a = TokenConfigurationChangeItem::MaxSupply(Some(42));
940 let b = TokenConfigurationChangeItem::MaxSupply(Some(42));
941 assert_eq!(a, b);
942 }
943
944 #[test]
945 fn equality_same_variant_different_data_unequal() {
946 let a = TokenConfigurationChangeItem::MaxSupply(Some(42));
947 let b = TokenConfigurationChangeItem::MaxSupply(Some(43));
948 assert_ne!(a, b);
949 }
950
951 #[test]
952 fn equality_different_variants_unequal() {
953 let a = TokenConfigurationChangeItem::MaxSupply(None);
954 let b = TokenConfigurationChangeItem::MainControlGroup(None);
955 assert_ne!(a, b);
956 }
957
958 #[test]
959 fn equality_authorized_action_takers_sensitivity() {
960 let a = TokenConfigurationChangeItem::ManualMinting(AuthorizedActionTakers::NoOne);
961 let b = TokenConfigurationChangeItem::ManualMinting(AuthorizedActionTakers::ContractOwner);
962 assert_ne!(a, b);
963 }
964
965 #[test]
966 fn equality_bool_variant_distinguishes_values() {
967 let a = TokenConfigurationChangeItem::MintingAllowChoosingDestination(true);
968 let b = TokenConfigurationChangeItem::MintingAllowChoosingDestination(false);
969 assert_ne!(a, b);
970 }
971
972 #[test]
975 fn default_is_no_change() {
976 let d: TokenConfigurationChangeItem = Default::default();
977 assert_eq!(d, TokenConfigurationChangeItem::TokenConfigurationNoChange);
978 }
979
980 #[test]
981 fn clone_preserves_variant_and_data() {
982 let aat = AuthorizedActionTakers::Identity(Identifier::from([5u8; 32]));
983 let a = TokenConfigurationChangeItem::Freeze(aat);
984 let b = a.clone();
985 assert_eq!(a, b);
986 }
987
988 #[test]
991 fn debug_trait_contains_variant_name() {
992 let a = TokenConfigurationChangeItem::ManualMinting(AuthorizedActionTakers::NoOne);
993 let dbg = format!("{:?}", a);
994 assert!(dbg.contains("ManualMinting"));
995 }
996}
997
998#[cfg(all(feature = "json-conversion", feature = "serde-conversion"))]
1000impl JsonConvertible for TokenConfigurationChangeItem {}
1001
1002#[cfg(all(feature = "value-conversion", feature = "serde-conversion"))]
1003impl ValueConvertible for TokenConfigurationChangeItem {}
1004
1005#[cfg(all(
1006 test,
1007 feature = "json-conversion",
1008 feature = "value-conversion",
1009 feature = "serde-conversion"
1010))]
1011mod json_convertible_tests {
1012 use super::*;
1013 use platform_value::platform_value;
1014 use serde_json::json;
1015
1016 fn fixture() -> TokenConfigurationChangeItem {
1020 TokenConfigurationChangeItem::MaxSupply(Some(123_456_789u64))
1021 }
1022
1023 #[test]
1024 fn json_round_trip_with_full_wire_shape() {
1025 use crate::serialization::JsonConvertible;
1026 let original = fixture();
1027 let json = original.to_json().expect("to_json");
1028 assert_eq!(json, json!({"$type": "maxSupply", "value": 123_456_789u64}));
1034 let recovered = TokenConfigurationChangeItem::from_json(json).expect("from_json");
1035 assert_eq!(original, recovered);
1036 }
1037
1038 #[test]
1039 fn value_round_trip_with_full_wire_shape() {
1040 use crate::serialization::ValueConvertible;
1041 let original = fixture();
1042 let value = original.to_object().expect("to_object");
1043 assert_eq!(
1046 value,
1047 platform_value!({"$type": "maxSupply", "value": 123_456_789u64})
1048 );
1049 let recovered = TokenConfigurationChangeItem::from_object(value).expect("from_object");
1050 assert_eq!(original, recovered);
1051 }
1052
1053 #[test]
1054 fn json_round_trip_of_the_pool_notes_threshold() {
1055 use crate::serialization::JsonConvertible;
1056 let original = TokenConfigurationChangeItem::MinimumPoolNotesForOutgoing(10);
1057 let json = original.to_json().expect("to_json");
1058 assert_eq!(
1059 json,
1060 json!({"$type": "minimumPoolNotesForOutgoing", "value": 10})
1061 );
1062 let recovered = TokenConfigurationChangeItem::from_json(json).expect("from_json");
1063 assert_eq!(original, recovered);
1064 }
1065
1066 #[test]
1067 fn json_large_max_supply_serializes_as_string_for_js_safety() {
1068 use crate::serialization::JsonConvertible;
1069 let original = TokenConfigurationChangeItem::MaxSupply(Some(9_007_199_254_740_993)); let json = original.to_json().expect("to_json");
1075 assert_eq!(
1076 json,
1077 json!({"$type": "maxSupply", "value": "9007199254740993"})
1078 );
1079 let recovered = TokenConfigurationChangeItem::from_json(json).expect("from_json");
1080 assert_eq!(original, recovered);
1081 }
1082}