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