Skip to main content

dpp/serialization/json/
safe_fields.rs

1use crate::contract_group::{ContractGroupMembership, ContractGroupRegistration};
2use crate::data_contract::associated_token::token_configuration_item::TokenConfigurationChangeItem;
3use crate::data_contract::associated_token::token_distribution_key::{
4    TokenDistributionInfo, TokenDistributionType,
5};
6use crate::data_contract::associated_token::token_perpetual_distribution::reward_distribution_moment::RewardDistributionMoment;
7use crate::data_contract::document_type::ContestedIndexFieldMatch;
8#[cfg(feature = "state-transitions")]
9use crate::state_transition::batch_transition::batched_transition::{
10    BatchedTransition, DocumentTransition, TokenTransition,
11};
12#[cfg(feature = "state-transitions")]
13use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition;
14#[cfg(feature = "state-transitions")]
15use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition;
16use crate::tokens::emergency_action::TokenEmergencyAction;
17use crate::tokens::gas_fees_paid_by::GasFeesPaidBy;
18use crate::tokens::token_payment_info::TokenPaymentInfo;
19use crate::tokens::token_pricing_schedule::TokenPricingSchedule;
20
21/// Marker trait proving a type's u64/i64 fields are protected for JS-safe JSON serialization.
22///
23/// # How it works
24///
25/// The `#[json_safe_fields]` attribute macro auto-implements this trait for annotated types.
26/// The `#[derive(JsonConvertible)]` macro implements it for versioned enums and asserts
27/// that all inner variant types also implement it.
28///
29/// # Compile errors
30///
31/// If you see `` the trait `JsonSafeFields` is not satisfied ``, it means a field type
32/// in an annotated struct doesn't implement this trait. Fix it by one of:
33///
34/// - **Struct with u64 fields**: add `#[cfg_attr(feature = "json-conversion", json_safe_fields)]`
35/// - **Simple enum/struct without u64**: add `impl JsonSafeFields for MyType {}` below
36/// - **`BTreeMap<K, u64>` field**: add `#[serde(with = "json_safe_generic_u64_value_map")]`
37/// - **New `type Foo = u64` alias**: add it to `U64_ALIASES` in the proc macro crate
38///
39/// # Why u64/i64 don't implement this trait
40///
41/// A bare `u64` is NOT JS-safe. Safety comes from `#[serde(with = "json_safe_u64")]`
42/// applied at the field level. By excluding u64/i64 from this trait, the compiler
43/// catches unprotected type aliases (`type Foo = u64`) and containers (`Vec<u64>`)
44/// at compile time.
45pub trait JsonSafeFields {}
46
47// --- Primitive types (no u64/i64 risk) ---
48// NOTE: u64 and i64 are intentionally excluded — see trait doc above.
49
50impl JsonSafeFields for bool {}
51impl JsonSafeFields for u8 {}
52impl JsonSafeFields for u16 {}
53impl JsonSafeFields for u32 {}
54impl JsonSafeFields for i8 {}
55impl JsonSafeFields for i16 {}
56impl JsonSafeFields for i32 {}
57impl JsonSafeFields for f32 {}
58impl JsonSafeFields for f64 {}
59impl JsonSafeFields for usize {}
60impl JsonSafeFields for isize {}
61impl JsonSafeFields for char {}
62impl JsonSafeFields for String {}
63impl JsonSafeFields for () {}
64impl<T: JsonSafeFields> JsonSafeFields for &T {}
65impl<const N: usize> JsonSafeFields for [u8; N] {}
66
67// --- Standard collections (safe if inner types are safe) ---
68// NOTE: Vec<u64>, BTreeMap<K, u64> etc. will NOT satisfy these bounds because
69// u64 doesn't implement JsonSafeFields. Fields with such types must use a
70// custom `#[serde(with = "...")]` module (e.g., json_safe_u64_u64_map).
71
72impl<T: JsonSafeFields> JsonSafeFields for Vec<T> {}
73impl<T: JsonSafeFields> JsonSafeFields for Option<T> {}
74impl<T: JsonSafeFields> JsonSafeFields for Box<T> {}
75impl<K: JsonSafeFields, V: JsonSafeFields> JsonSafeFields for std::collections::BTreeMap<K, V> {}
76impl<T: JsonSafeFields> JsonSafeFields for std::collections::BTreeSet<T> {}
77impl<K: JsonSafeFields, V: JsonSafeFields> JsonSafeFields for std::collections::HashMap<K, V> {}
78impl<T: JsonSafeFields> JsonSafeFields for std::collections::HashSet<T> {}
79
80// --- Platform types (external, don't contain unprotected u64/i64) ---
81
82impl JsonSafeFields for platform_value::Identifier {}
83impl JsonSafeFields for platform_value::BinaryData {}
84impl JsonSafeFields for platform_value::Bytes20 {}
85impl JsonSafeFields for platform_value::Bytes32 {}
86impl JsonSafeFields for platform_value::Bytes36 {}
87impl JsonSafeFields for platform_value::Value {}
88impl JsonSafeFields for platform_value::string_encoding::Encoding {}
89
90// --- External crate types ---
91
92impl JsonSafeFields for dashcore::OutPoint {}
93
94// --- rs-dpp types that don't contain u64/i64 or have their own safe handling ---
95// Add new entries here when a json_safe_fields-annotated struct has a field whose
96// type is a simple enum/struct without u64/i64. The compiler will tell you which
97// type is missing via a `JsonSafeFields is not satisfied` error.
98
99impl JsonSafeFields
100    for crate::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers
101{
102}
103impl JsonSafeFields
104    for crate::data_contract::storage_requirements::keys_for_document_type::StorageKeyRequirements
105{
106}
107impl JsonSafeFields
108    for crate::data_contract::associated_token::token_marketplace_rules::v0::TokenTradeMode
109{
110}
111impl JsonSafeFields for crate::data_contract::associated_token::token_perpetual_distribution::distribution_recipient::TokenDistributionRecipient {}
112impl JsonSafeFields for crate::identity::Purpose {}
113impl JsonSafeFields for crate::identity::SecurityLevel {}
114impl JsonSafeFields for crate::identity::KeyType {}
115impl JsonSafeFields for crate::block::epoch::Epoch {}
116impl JsonSafeFields for crate::identity::identity_public_key::IdentityPublicKey {}
117impl JsonSafeFields for crate::identity::state_transition::asset_lock_proof::AssetLockProof {}
118impl JsonSafeFields for crate::address_funds::PlatformAddress {}
119impl JsonSafeFields for crate::address_funds::AddressFundsFeeStrategy {}
120// `AddressWitness` is verified via `#[json_safe_fields]` on the type itself
121// (named-field variants of `BinaryData`), so no manual marker is needed here.
122impl JsonSafeFields for crate::withdrawal::Pooling {}
123impl JsonSafeFields for crate::identity::core_script::CoreScript {}
124impl JsonSafeFields for crate::voting::votes::Vote {}
125// `DocumentBaseTransition` wraps `DocumentBaseTransitionV0` / `V1`, both of
126// which are `#[json_safe_fields]`-annotated, so the wrapper enum is safe by
127// induction: every u64 inside is protected by `json_safe_u64`.
128#[cfg(feature = "state-transitions")]
129impl JsonSafeFields for DocumentBaseTransition {}
130// `TokenPaymentInfo` (v0 wrapper) — V0 is `#[json_safe_fields]`-annotated.
131impl JsonSafeFields for TokenPaymentInfo {}
132// `GasFeesPaidBy` is a unit-variant enum (no u64).
133impl JsonSafeFields for GasFeesPaidBy {}
134impl JsonSafeFields for ContractGroupRegistration {}
135impl JsonSafeFields for ContractGroupMembership {}
136// `GroupStateTransitionInfo` is verified via `#[json_safe_fields]` on the type
137// itself (named `u16` / `Identifier` / `bool` fields) — no manual marker needed.
138// `TokenBaseTransition` wraps `TokenBaseTransitionV0` which is
139// `#[json_safe_fields]`-annotated, so the wrapper is safe by induction.
140#[cfg(feature = "state-transitions")]
141impl JsonSafeFields for TokenBaseTransition {}
142// BatchTransition family wrappers — each variant's outer enum is itself
143// safe by induction (every V0 inner is `#[json_safe_fields]`-annotated;
144// the outer-enum manual `impl JsonConvertible` doesn't auto-impl
145// JsonSafeFields, so we declare it explicitly here).
146#[cfg(feature = "state-transitions")]
147impl JsonSafeFields for DocumentTransition {}
148#[cfg(feature = "state-transitions")]
149impl JsonSafeFields for TokenTransition {}
150#[cfg(feature = "state-transitions")]
151impl JsonSafeFields for BatchedTransition {}
152impl JsonSafeFields for crate::voting::vote_choices::resource_vote_choice::ResourceVoteChoice {}
153impl JsonSafeFields for crate::group::action_event::GroupActionEvent {}
154// TokenEvent contains u64 aliases (TokenAmount, Credits) in tuple variants that
155// `#[json_safe_fields]` can't auto-annotate. Developer takes responsibility for
156// JS-safe serialization of these fields. See token_event.rs for details.
157impl JsonSafeFields for crate::tokens::token_event::TokenEvent {}
158// `TokenEmergencyAction` is a unit-variant enum (Pause / Resume).
159impl JsonSafeFields for TokenEmergencyAction {}
160// `TokenDistributionType` is a unit-variant enum.
161impl JsonSafeFields for TokenDistributionType {}
162// `TokenPricingSchedule` has tuple variants holding `Credits` (u64) and
163// `BTreeMap<TokenAmount, Credits>`. `#[json_safe_fields]` can't auto-annotate
164// variant-internal u64s, so it serializes through an internally-`$type`-tagged
165// `Repr` that routes both through `json_safe_u64` / `json_safe_u64_u64_map` —
166// this marker is therefore truthful, not a bare escape hatch.
167impl JsonSafeFields for TokenPricingSchedule {}
168// `TokenConfigurationChangeItem` has tuple variants with `Option<TokenAmount>`
169// and `Option<GroupContractPosition>` (u64-shaped). Same escape-hatch pattern.
170impl JsonSafeFields for TokenConfigurationChangeItem {}
171// `RewardDistributionMoment` carries `BlockHeight`/`TimestampMillis` (u64) in
172// tuple variants. Unlike the bare escape-hatches above, its u64 fields are
173// *actually* JS-safe: `#[serde(with = "json_safe_u64")]` is applied directly on
174// the variant fields (see reward_distribution_moment/mod.rs).
175impl JsonSafeFields for RewardDistributionMoment {}
176// `ContestedIndexFieldMatch::PositiveIntegerMatch(u128)` is made JS-safe via
177// `#[serde(with = "json_safe_u128")]` on the variant field (see
178// document_type/index/mod.rs); `Regex(LazyRegex)` round-trips as a string.
179impl JsonSafeFields for ContestedIndexFieldMatch {}
180// `TokenDistributionInfo::PreProgrammed` carries a `TimestampMillis` (u64) made
181// JS-safe via `#[serde(with = "json_safe_u64")]`; `Perpetual`'s
182// `RewardDistributionMoment` is JS-safe via its own annotation.
183impl JsonSafeFields for TokenDistributionInfo {}