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