#[json_safe_fields]Expand description
Attribute macro that auto-injects #[serde(with = "...")] on fields whose
natural serde shape would round-trip badly through JSON / WASM.
Works on both structs and enums (with named fields in variants).
§What it injects
| Field type | Helper injected | Wire shape |
|---|---|---|
u64 / Option<u64> and known aliases (Credits, TokenAmount, TimestampMillis, BlockHeight, …) | json_safe_u64 / json_safe_option_u64 | number ≤ MAX_SAFE_INTEGER, otherwise string — avoids JS precision loss |
i64 / Option<i64> and known aliases | json_safe_i64 / json_safe_option_i64 | same, signed |
[u8; N] (any N, via const generics) | serde_bytes | raw bytes in binary, base64 string in JSON |
Vec<u8> | serde_bytes_var | raw bytes in binary, base64 string in JSON |
The byte-field handling matches the broader codebase convention used by
Bytes20 / Bytes32 / Bytes36 / BinaryData in rs-platform-value.
Fields that already carry an explicit #[serde(with = "…")] (or
skip / flatten / cfg_attr wrapping a serde(with)) are left
untouched.
§Compile-time transitive guarantee
When applied inside the dpp crate, the macro also implements the marker
trait JsonSafeFields for the type, and emits compile-time assertions that
every nested non-primitive field type (anything not directly handled above)
also implements JsonSafeFields. This propagates the safety check
transitively — adding a new struct that contains a Credits without an
#[json_safe_fields] annotation will fail to compile.
§Feature flags
When serde derives are behind cfg_attr(feature = "..."), the cfg_attr is
evaluated by the compiler BEFORE this macro runs. If the feature is off,
serde derives aren’t visible and #[serde(with)] is NOT generated — which
is correct because serde(with) requires an active serde derive.
§Inside dpp crate (default)
#[json_safe_fields]
pub struct MyStructV0 {
pub supply: u64, // → auto-annotated with crate::serialization::json_safe_u64
pub anchor: [u8; 32], // → auto-annotated with crate::serialization::serde_bytes
pub proof: Vec<u8>, // → auto-annotated with crate::serialization::serde_bytes_var
pub name: String, // → untouched
}§Outside dpp crate
Use crate = "..." to specify the path to the dpp serialization module.
When crate is specified, the JsonSafeFields impl is NOT generated.
#[json_safe_fields(crate = "dash_sdk::dpp")]
pub struct MyWasmStruct {
pub balance: u64, // → annotated with dash_sdk::dpp::serialization::json_safe_u64
}