Skip to main content

json_safe_fields

Attribute Macro json_safe_fields 

Source
#[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 typeHelper injectedWire shape
u64 / Option<u64> and known aliases (Credits, TokenAmount, TimestampMillis, BlockHeight, …)json_safe_u64 / json_safe_option_u64number ≤ MAX_SAFE_INTEGER, otherwise string — avoids JS precision loss
i64 / Option<i64> and known aliasesjson_safe_i64 / json_safe_option_i64same, signed
[u8; N] (any N, via const generics)serde_bytesraw bytes in binary, base64 string in JSON
Vec<u8>serde_bytes_varraw 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
}