From 40f07030c9256996ee208c65981a0eb0acac001d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 11:58:53 +0000 Subject: [PATCH 01/12] Initial plan From 5adefb6da6618e9319109c7333560a2c6a91208b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 12:01:12 +0000 Subject: [PATCH 02/12] Add StateTransitionJsonConvert and StateTransitionValueConvert impls for StateTransition enum Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> --- packages/rs-dpp/Cargo.toml | 1 + .../src/state_transition/json_conversion.rs | 31 ++++ packages/rs-dpp/src/state_transition/mod.rs | 4 + .../src/state_transition/value_conversion.rs | 164 ++++++++++++++++++ 4 files changed, 200 insertions(+) create mode 100644 packages/rs-dpp/src/state_transition/json_conversion.rs create mode 100644 packages/rs-dpp/src/state_transition/value_conversion.rs diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index 09643a4a23b..75f60dc3920 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -147,6 +147,7 @@ dash-sdk-features = [ "data-contract-json-conversion", "identity-value-conversion", "state-transition-value-conversion", + "state-transition-json-conversion", "state-transition-signing", "client", "platform-value-cbor", diff --git a/packages/rs-dpp/src/state_transition/json_conversion.rs b/packages/rs-dpp/src/state_transition/json_conversion.rs new file mode 100644 index 00000000000..93adfd516fb --- /dev/null +++ b/packages/rs-dpp/src/state_transition/json_conversion.rs @@ -0,0 +1,31 @@ +use crate::state_transition::{ + JsonStateTransitionSerializationOptions, StateTransition, StateTransitionJsonConvert, +}; +use crate::ProtocolError; +use serde_json::Value as JsonValue; + +#[cfg(feature = "state-transition-json-conversion")] +impl StateTransitionJsonConvert<'_> for StateTransition { + fn to_json( + &self, + options: JsonStateTransitionSerializationOptions, + ) -> Result { + match self { + StateTransition::DataContractCreate(st) => st.to_json(options), + StateTransition::DataContractUpdate(st) => st.to_json(options), + StateTransition::Batch(st) => st.to_json(options), + StateTransition::IdentityCreate(st) => st.to_json(options), + StateTransition::IdentityTopUp(st) => st.to_json(options), + StateTransition::IdentityCreditWithdrawal(st) => st.to_json(options), + StateTransition::IdentityUpdate(st) => st.to_json(options), + StateTransition::IdentityCreditTransfer(st) => st.to_json(options), + StateTransition::MasternodeVote(st) => st.to_json(options), + StateTransition::IdentityCreditTransferToAddresses(st) => st.to_json(options), + StateTransition::IdentityCreateFromAddresses(st) => st.to_json(options), + StateTransition::IdentityTopUpFromAddresses(st) => st.to_json(options), + StateTransition::AddressFundsTransfer(st) => st.to_json(options), + StateTransition::AddressFundingFromAssetLock(st) => st.to_json(options), + StateTransition::AddressCreditWithdrawal(st) => st.to_json(options), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/mod.rs b/packages/rs-dpp/src/state_transition/mod.rs index 8f41b601ded..d7e3d7b40bd 100644 --- a/packages/rs-dpp/src/state_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/mod.rs @@ -42,6 +42,10 @@ pub mod proof_result; mod serialization; pub mod state_transitions; mod traits; +#[cfg(feature = "state-transition-value-conversion")] +mod value_conversion; +#[cfg(feature = "state-transition-json-conversion")] +mod json_conversion; // pub mod state_transition_fee; diff --git a/packages/rs-dpp/src/state_transition/value_conversion.rs b/packages/rs-dpp/src/state_transition/value_conversion.rs new file mode 100644 index 00000000000..ca8d8c83ae7 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/value_conversion.rs @@ -0,0 +1,164 @@ +use crate::state_transition::{StateTransition, StateTransitionValueConvert}; +use crate::ProtocolError; +use platform_value::Value; +use platform_version::version::PlatformVersion; +use std::collections::BTreeMap; + +#[cfg(feature = "state-transition-value-conversion")] +impl StateTransitionValueConvert<'_> for StateTransition { + fn to_object(&self, skip_signature: bool) -> Result { + match self { + StateTransition::DataContractCreate(st) => st.to_object(skip_signature), + StateTransition::DataContractUpdate(st) => st.to_object(skip_signature), + StateTransition::Batch(st) => st.to_object(skip_signature), + StateTransition::IdentityCreate(st) => st.to_object(skip_signature), + StateTransition::IdentityTopUp(st) => st.to_object(skip_signature), + StateTransition::IdentityCreditWithdrawal(st) => st.to_object(skip_signature), + StateTransition::IdentityUpdate(st) => st.to_object(skip_signature), + StateTransition::IdentityCreditTransfer(st) => st.to_object(skip_signature), + StateTransition::MasternodeVote(st) => st.to_object(skip_signature), + StateTransition::IdentityCreditTransferToAddresses(st) => st.to_object(skip_signature), + StateTransition::IdentityCreateFromAddresses(st) => st.to_object(skip_signature), + StateTransition::IdentityTopUpFromAddresses(st) => st.to_object(skip_signature), + StateTransition::AddressFundsTransfer(st) => st.to_object(skip_signature), + StateTransition::AddressFundingFromAssetLock(st) => st.to_object(skip_signature), + StateTransition::AddressCreditWithdrawal(st) => st.to_object(skip_signature), + } + } + + fn to_canonical_object(&self, skip_signature: bool) -> Result { + match self { + StateTransition::DataContractCreate(st) => st.to_canonical_object(skip_signature), + StateTransition::DataContractUpdate(st) => st.to_canonical_object(skip_signature), + StateTransition::Batch(st) => st.to_canonical_object(skip_signature), + StateTransition::IdentityCreate(st) => st.to_canonical_object(skip_signature), + StateTransition::IdentityTopUp(st) => st.to_canonical_object(skip_signature), + StateTransition::IdentityCreditWithdrawal(st) => { + st.to_canonical_object(skip_signature) + } + StateTransition::IdentityUpdate(st) => st.to_canonical_object(skip_signature), + StateTransition::IdentityCreditTransfer(st) => st.to_canonical_object(skip_signature), + StateTransition::MasternodeVote(st) => st.to_canonical_object(skip_signature), + StateTransition::IdentityCreditTransferToAddresses(st) => { + st.to_canonical_object(skip_signature) + } + StateTransition::IdentityCreateFromAddresses(st) => { + st.to_canonical_object(skip_signature) + } + StateTransition::IdentityTopUpFromAddresses(st) => { + st.to_canonical_object(skip_signature) + } + StateTransition::AddressFundsTransfer(st) => st.to_canonical_object(skip_signature), + StateTransition::AddressFundingFromAssetLock(st) => { + st.to_canonical_object(skip_signature) + } + StateTransition::AddressCreditWithdrawal(st) => { + st.to_canonical_object(skip_signature) + } + } + } + + fn to_canonical_cleaned_object(&self, skip_signature: bool) -> Result { + match self { + StateTransition::DataContractCreate(st) => { + st.to_canonical_cleaned_object(skip_signature) + } + StateTransition::DataContractUpdate(st) => { + st.to_canonical_cleaned_object(skip_signature) + } + StateTransition::Batch(st) => st.to_canonical_cleaned_object(skip_signature), + StateTransition::IdentityCreate(st) => st.to_canonical_cleaned_object(skip_signature), + StateTransition::IdentityTopUp(st) => st.to_canonical_cleaned_object(skip_signature), + StateTransition::IdentityCreditWithdrawal(st) => { + st.to_canonical_cleaned_object(skip_signature) + } + StateTransition::IdentityUpdate(st) => st.to_canonical_cleaned_object(skip_signature), + StateTransition::IdentityCreditTransfer(st) => { + st.to_canonical_cleaned_object(skip_signature) + } + StateTransition::MasternodeVote(st) => st.to_canonical_cleaned_object(skip_signature), + StateTransition::IdentityCreditTransferToAddresses(st) => { + st.to_canonical_cleaned_object(skip_signature) + } + StateTransition::IdentityCreateFromAddresses(st) => { + st.to_canonical_cleaned_object(skip_signature) + } + StateTransition::IdentityTopUpFromAddresses(st) => { + st.to_canonical_cleaned_object(skip_signature) + } + StateTransition::AddressFundsTransfer(st) => { + st.to_canonical_cleaned_object(skip_signature) + } + StateTransition::AddressFundingFromAssetLock(st) => { + st.to_canonical_cleaned_object(skip_signature) + } + StateTransition::AddressCreditWithdrawal(st) => { + st.to_canonical_cleaned_object(skip_signature) + } + } + } + + fn to_cleaned_object(&self, skip_signature: bool) -> Result { + match self { + StateTransition::DataContractCreate(st) => st.to_cleaned_object(skip_signature), + StateTransition::DataContractUpdate(st) => st.to_cleaned_object(skip_signature), + StateTransition::Batch(st) => st.to_cleaned_object(skip_signature), + StateTransition::IdentityCreate(st) => st.to_cleaned_object(skip_signature), + StateTransition::IdentityTopUp(st) => st.to_cleaned_object(skip_signature), + StateTransition::IdentityCreditWithdrawal(st) => st.to_cleaned_object(skip_signature), + StateTransition::IdentityUpdate(st) => st.to_cleaned_object(skip_signature), + StateTransition::IdentityCreditTransfer(st) => st.to_cleaned_object(skip_signature), + StateTransition::MasternodeVote(st) => st.to_cleaned_object(skip_signature), + StateTransition::IdentityCreditTransferToAddresses(st) => { + st.to_cleaned_object(skip_signature) + } + StateTransition::IdentityCreateFromAddresses(st) => { + st.to_cleaned_object(skip_signature) + } + StateTransition::IdentityTopUpFromAddresses(st) => { + st.to_cleaned_object(skip_signature) + } + StateTransition::AddressFundsTransfer(st) => st.to_cleaned_object(skip_signature), + StateTransition::AddressFundingFromAssetLock(st) => { + st.to_cleaned_object(skip_signature) + } + StateTransition::AddressCreditWithdrawal(st) => st.to_cleaned_object(skip_signature), + } + } + + fn from_object( + raw_object: Value, + platform_version: &PlatformVersion, + ) -> Result + where + Self: Sized, + { + // Deserialize using existing platform_value deserialization + // This is already implemented via the derive macros + platform_value::from_value(raw_object).map_err(ProtocolError::ValueError) + } + + fn from_value_map( + raw_value_map: BTreeMap, + platform_version: &PlatformVersion, + ) -> Result + where + Self: Sized, + { + platform_value::from_value(Value::Map( + raw_value_map + .into_iter() + .map(|(k, v)| (k.into(), v)) + .collect(), + )) + .map_err(ProtocolError::ValueError) + } + + fn clean_value(value: &mut Value) -> Result<(), ProtocolError> { + // The clean_value logic is variant-specific and should be dispatched + // However, since we're working with a Value (not a StateTransition instance), + // we'd need type information to dispatch correctly. + // For now, this is a no-op as per the default trait implementation. + Ok(()) + } +} From c616d6e98a9a67077d41e78342918372ab5a843a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 12:04:32 +0000 Subject: [PATCH 03/12] Fix build errors: implement StateTransitionFieldTypes and fix warnings Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> --- packages/rs-dpp/src/state_transition/mod.rs | 20 +++++++++++++++++++ .../src/state_transition/value_conversion.rs | 6 +++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/rs-dpp/src/state_transition/mod.rs b/packages/rs-dpp/src/state_transition/mod.rs index d7e3d7b40bd..bf4a464996e 100644 --- a/packages/rs-dpp/src/state_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/mod.rs @@ -387,6 +387,26 @@ impl OptionallyAssetLockProved for StateTransition { } } +impl StateTransitionFieldTypes for StateTransition { + fn signature_property_paths() -> Vec<&'static str> { + // The top-level enum doesn't have fixed signature paths + // Each variant has its own specific paths + vec![] + } + + fn identifiers_property_paths() -> Vec<&'static str> { + // The top-level enum doesn't have fixed identifier paths + // Each variant has its own specific paths + vec![] + } + + fn binary_property_paths() -> Vec<&'static str> { + // The top-level enum doesn't have fixed binary paths + // Each variant has its own specific paths + vec![] + } +} + /// The state transition signing options #[derive(Debug, Clone, Copy, Default, Eq, PartialEq)] pub struct StateTransitionSigningOptions { diff --git a/packages/rs-dpp/src/state_transition/value_conversion.rs b/packages/rs-dpp/src/state_transition/value_conversion.rs index ca8d8c83ae7..7faa9960a2b 100644 --- a/packages/rs-dpp/src/state_transition/value_conversion.rs +++ b/packages/rs-dpp/src/state_transition/value_conversion.rs @@ -128,7 +128,7 @@ impl StateTransitionValueConvert<'_> for StateTransition { fn from_object( raw_object: Value, - platform_version: &PlatformVersion, + _platform_version: &PlatformVersion, ) -> Result where Self: Sized, @@ -140,7 +140,7 @@ impl StateTransitionValueConvert<'_> for StateTransition { fn from_value_map( raw_value_map: BTreeMap, - platform_version: &PlatformVersion, + _platform_version: &PlatformVersion, ) -> Result where Self: Sized, @@ -154,7 +154,7 @@ impl StateTransitionValueConvert<'_> for StateTransition { .map_err(ProtocolError::ValueError) } - fn clean_value(value: &mut Value) -> Result<(), ProtocolError> { + fn clean_value(_value: &mut Value) -> Result<(), ProtocolError> { // The clean_value logic is variant-specific and should be dispatched // However, since we're working with a Value (not a StateTransition instance), // we'd need type information to dispatch correctly. From 4116373d2aeded3f3cff7449298c40f2aa939d22 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 14:54:05 +0000 Subject: [PATCH 04/12] Run cargo fmt to format Rust code Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> --- packages/rs-dpp/src/state_transition/mod.rs | 4 ++-- .../rs-dpp/src/state_transition/value_conversion.rs | 12 +++--------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/packages/rs-dpp/src/state_transition/mod.rs b/packages/rs-dpp/src/state_transition/mod.rs index bf4a464996e..3c2672d4147 100644 --- a/packages/rs-dpp/src/state_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/mod.rs @@ -38,14 +38,14 @@ pub mod errors; use crate::util::hash::ripemd160_sha256; use crate::util::hash::{hash_double_to_vec, hash_single}; +#[cfg(feature = "state-transition-json-conversion")] +mod json_conversion; pub mod proof_result; mod serialization; pub mod state_transitions; mod traits; #[cfg(feature = "state-transition-value-conversion")] mod value_conversion; -#[cfg(feature = "state-transition-json-conversion")] -mod json_conversion; // pub mod state_transition_fee; diff --git a/packages/rs-dpp/src/state_transition/value_conversion.rs b/packages/rs-dpp/src/state_transition/value_conversion.rs index 7faa9960a2b..d4570407fb4 100644 --- a/packages/rs-dpp/src/state_transition/value_conversion.rs +++ b/packages/rs-dpp/src/state_transition/value_conversion.rs @@ -33,9 +33,7 @@ impl StateTransitionValueConvert<'_> for StateTransition { StateTransition::Batch(st) => st.to_canonical_object(skip_signature), StateTransition::IdentityCreate(st) => st.to_canonical_object(skip_signature), StateTransition::IdentityTopUp(st) => st.to_canonical_object(skip_signature), - StateTransition::IdentityCreditWithdrawal(st) => { - st.to_canonical_object(skip_signature) - } + StateTransition::IdentityCreditWithdrawal(st) => st.to_canonical_object(skip_signature), StateTransition::IdentityUpdate(st) => st.to_canonical_object(skip_signature), StateTransition::IdentityCreditTransfer(st) => st.to_canonical_object(skip_signature), StateTransition::MasternodeVote(st) => st.to_canonical_object(skip_signature), @@ -52,9 +50,7 @@ impl StateTransitionValueConvert<'_> for StateTransition { StateTransition::AddressFundingFromAssetLock(st) => { st.to_canonical_object(skip_signature) } - StateTransition::AddressCreditWithdrawal(st) => { - st.to_canonical_object(skip_signature) - } + StateTransition::AddressCreditWithdrawal(st) => st.to_canonical_object(skip_signature), } } @@ -115,9 +111,7 @@ impl StateTransitionValueConvert<'_> for StateTransition { StateTransition::IdentityCreateFromAddresses(st) => { st.to_cleaned_object(skip_signature) } - StateTransition::IdentityTopUpFromAddresses(st) => { - st.to_cleaned_object(skip_signature) - } + StateTransition::IdentityTopUpFromAddresses(st) => st.to_cleaned_object(skip_signature), StateTransition::AddressFundsTransfer(st) => st.to_cleaned_object(skip_signature), StateTransition::AddressFundingFromAssetLock(st) => { st.to_cleaned_object(skip_signature) From db07146d19df499bd3828ccbf511d5615a80145c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 15:47:16 +0000 Subject: [PATCH 05/12] Add test to verify serde vs to_json behavior Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> --- packages/rs-dpp/src/state_transition/mod.rs | 2 + .../test_json_serde_integration.rs | 103 ++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 packages/rs-dpp/src/state_transition/test_json_serde_integration.rs diff --git a/packages/rs-dpp/src/state_transition/mod.rs b/packages/rs-dpp/src/state_transition/mod.rs index 3c2672d4147..63143a0abd2 100644 --- a/packages/rs-dpp/src/state_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/mod.rs @@ -43,6 +43,8 @@ mod json_conversion; pub mod proof_result; mod serialization; pub mod state_transitions; +#[cfg(test)] +mod test_json_serde_integration; mod traits; #[cfg(feature = "state-transition-value-conversion")] mod value_conversion; diff --git a/packages/rs-dpp/src/state_transition/test_json_serde_integration.rs b/packages/rs-dpp/src/state_transition/test_json_serde_integration.rs new file mode 100644 index 00000000000..21c587f9811 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/test_json_serde_integration.rs @@ -0,0 +1,103 @@ +#[cfg(all( + test, + feature = "state-transition-serde-conversion", + feature = "state-transition-json-conversion" +))] +mod test_serde_json_serialization { + use crate::address_funds::PlatformAddress; + use crate::state_transition::address_funds_transfer_transition::v0::AddressFundsTransferTransitionV0; + use crate::state_transition::address_funds_transfer_transition::AddressFundsTransferTransition; + use crate::state_transition::{ + JsonStateTransitionSerializationOptions, StateTransition, StateTransitionJsonConvert, + }; + use std::collections::BTreeMap; + + #[test] + fn test_variant_to_json() { + // Test if the variant's to_json works (as claimed in the original issue) + let mut inputs = BTreeMap::new(); + let input_address = PlatformAddress::P2pkh([1u8; 20]); + inputs.insert(input_address, (1u32, 1000u64)); + + let mut outputs = BTreeMap::new(); + let output_address = PlatformAddress::P2pkh([2u8; 20]); + outputs.insert(output_address, 900u64); + + let transition_v0 = AddressFundsTransferTransitionV0 { + inputs, + outputs, + user_fee_increase: 0, + fee_strategy: Default::default(), + input_witnesses: vec![], + }; + + let transition = AddressFundsTransferTransition::V0(transition_v0); + + println!("\n=== Testing variant.to_json() ==="); + match transition.to_json(JsonStateTransitionSerializationOptions::default()) { + Ok(json_value) => { + println!("SUCCESS: variant to_json() worked!"); + println!( + "JSON:\n{}", + serde_json::to_string_pretty(&json_value).unwrap() + ); + } + Err(e) => { + println!("FAILED: variant to_json() error: {:?}", e); + panic!("Expected variant to_json to work but it failed: {:?}", e); + } + } + } + + #[test] + fn test_state_transition_enum_to_json() { + // Test if the top-level StateTransition enum's to_json works + let mut inputs = BTreeMap::new(); + let input_address = PlatformAddress::P2pkh([1u8; 20]); + inputs.insert(input_address, (1u32, 1000u64)); + + let mut outputs = BTreeMap::new(); + let output_address = PlatformAddress::P2pkh([2u8; 20]); + outputs.insert(output_address, 900u64); + + let transition_v0 = AddressFundsTransferTransitionV0 { + inputs, + outputs, + user_fee_increase: 0, + fee_strategy: Default::default(), + input_witnesses: vec![], + }; + + let transition = AddressFundsTransferTransition::V0(transition_v0); + let state_transition = StateTransition::AddressFundsTransfer(transition.clone()); + + // Test 1: Try serde_json::to_string_pretty (this should fail with "key must be a string") + println!("\n=== Testing serde_json::to_string_pretty ==="); + match serde_json::to_string_pretty(&state_transition) { + Ok(json_str) => { + println!("SUCCESS: serde serialization worked!"); + println!("JSON:\n{}", json_str); + } + Err(e) => { + println!("FAILED: serde serialization error: {}", e); + println!("This is expected - PlatformAddress as BTreeMap key doesn't work with serde"); + } + } + + // Test 2: Try our custom to_json() method on the enum + println!("\n=== Testing StateTransition enum to_json() method ==="); + match state_transition.to_json(JsonStateTransitionSerializationOptions::default()) { + Ok(json_value) => { + println!("SUCCESS: enum to_json() worked!"); + println!( + "JSON:\n{}", + serde_json::to_string_pretty(&json_value).unwrap() + ); + } + Err(e) => { + println!("FAILED: enum to_json() error: {:?}", e); + panic!("Expected enum to_json to work but it failed: {:?}", e); + } + } + } +} From b96d71f295a98e9095c15c1a4fea177ff0be7067 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 15:52:03 +0000 Subject: [PATCH 06/12] Fix serde serialization for BTreeMap fields Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> --- packages/rs-dpp/src/address_funds/mod.rs | 2 + .../platform_address_map_serde.rs | 63 +++++++++++++++++++ .../v0/mod.rs | 4 ++ .../v0/mod.rs | 8 +++ .../v0/mod.rs | 8 +++ .../v0/mod.rs | 8 +++ .../v0/mod.rs | 4 ++ .../v0/mod.rs | 4 ++ 8 files changed, 101 insertions(+) create mode 100644 packages/rs-dpp/src/address_funds/platform_address_map_serde.rs diff --git a/packages/rs-dpp/src/address_funds/mod.rs b/packages/rs-dpp/src/address_funds/mod.rs index 68508382934..aa8e8a67a16 100644 --- a/packages/rs-dpp/src/address_funds/mod.rs +++ b/packages/rs-dpp/src/address_funds/mod.rs @@ -1,5 +1,7 @@ pub mod fee_strategy; mod platform_address; +#[cfg(feature = "state-transition-serde-conversion")] +pub mod platform_address_map_serde; mod witness; mod witness_verification_operations; diff --git a/packages/rs-dpp/src/address_funds/platform_address_map_serde.rs b/packages/rs-dpp/src/address_funds/platform_address_map_serde.rs new file mode 100644 index 00000000000..da6525c6079 --- /dev/null +++ b/packages/rs-dpp/src/address_funds/platform_address_map_serde.rs @@ -0,0 +1,63 @@ +/// Custom serde serialization for BTreeMap +/// Converts PlatformAddress keys to strings using Display when serializing to JSON +use crate::address_funds::PlatformAddress; +use serde::de::{MapAccess, Visitor}; +use serde::ser::SerializeMap; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::collections::BTreeMap; +use std::fmt; +use std::marker::PhantomData; +use std::str::FromStr; + +pub fn serialize( + map: &BTreeMap, + serializer: S, +) -> Result +where + S: Serializer, + V: Serialize, +{ + let mut ser_map = serializer.serialize_map(Some(map.len()))?; + for (k, v) in map { + // Convert PlatformAddress to string using Display + ser_map.serialize_entry(&k.to_string(), v)?; + } + ser_map.end() +} + +pub fn deserialize<'de, D, V>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, + V: Deserialize<'de>, +{ + struct MapVisitor { + marker: PhantomData, + } + + impl<'de, V: Deserialize<'de>> Visitor<'de> for MapVisitor { + type Value = BTreeMap; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a map with PlatformAddress keys") + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let mut result = BTreeMap::new(); + while let Some((key_str, value)) = map.next_entry::()? { + let key = PlatformAddress::from_str(&key_str) + .map_err(|e| serde::de::Error::custom(format!("{}", e)))?; + result.insert(key, value); + } + Ok(result) + } + } + + deserializer.deserialize_map(MapVisitor { + marker: PhantomData, + }) +} + + diff --git a/packages/rs-dpp/src/state_transition/state_transitions/address_funds/address_credit_withdrawal_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/address_funds/address_credit_withdrawal_transition/v0/mod.rs index 70b22676451..02a179aeba1 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/address_funds/address_credit_withdrawal_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/address_funds/address_credit_withdrawal_transition/v0/mod.rs @@ -27,6 +27,10 @@ use crate::{identity::core_script::CoreScript, withdrawal::Pooling, ProtocolErro )] #[derive(Default)] pub struct AddressCreditWithdrawalTransitionV0 { + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(with = "crate::address_funds::platform_address_map_serde") + )] pub inputs: BTreeMap, /// Optional output for change pub output: Option<(PlatformAddress, Credits)>, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/address_funds/address_funding_from_asset_lock_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/address_funds/address_funding_from_asset_lock_transition/v0/mod.rs index 5d717964aa2..98e646bb796 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/address_funds/address_funding_from_asset_lock_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/address_funds/address_funding_from_asset_lock_transition/v0/mod.rs @@ -44,12 +44,20 @@ mod property_names { pub struct AddressFundingFromAssetLockTransitionV0 { pub asset_lock_proof: AssetLockProof, /// Inputs from existing platform addresses (optional, for combining funds) + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(with = "crate::address_funds::platform_address_map_serde") + )] pub inputs: BTreeMap, /// Outputs to fund platform addresses. /// - `Some(credits)` = explicit amount to send to this address /// - `None` = this address receives everything remaining after explicit outputs and fees /// Exactly one output must be `None` to receive the remainder /// (ensures full asset lock consumption). + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(with = "crate::address_funds::platform_address_map_serde") + )] pub outputs: BTreeMap>, pub fee_strategy: AddressFundsFeeStrategy, pub user_fee_increase: UserFeeIncrease, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/address_funds/address_funds_transfer_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/address_funds/address_funds_transfer_transition/v0/mod.rs index b18957694d8..caff9574ef2 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/address_funds/address_funds_transfer_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/address_funds/address_funds_transfer_transition/v0/mod.rs @@ -37,7 +37,15 @@ use serde::{Deserialize, Serialize}; #[platform_serialize(unversioned)] #[derive(Default)] pub struct AddressFundsTransferTransitionV0 { + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(with = "crate::address_funds::platform_address_map_serde") + )] pub inputs: BTreeMap, + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(with = "crate::address_funds::platform_address_map_serde") + )] pub outputs: BTreeMap, pub fee_strategy: AddressFundsFeeStrategy, pub user_fee_increase: UserFeeIncrease, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_create_from_addresses_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_create_from_addresses_transition/v0/mod.rs index 2bc07a55c18..57cd90ac0a4 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_create_from_addresses_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_create_from_addresses_transition/v0/mod.rs @@ -39,6 +39,10 @@ pub struct IdentityCreateFromAddressesTransitionV0 { // When signing, we don't sign the signatures for keys #[platform_signable(into = "Vec")] pub public_keys: Vec, + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(with = "crate::address_funds::platform_address_map_serde") + )] pub inputs: BTreeMap, /// Optional output to send remaining credits to an address pub output: Option<(PlatformAddress, Credits)>, @@ -56,6 +60,10 @@ pub struct IdentityCreateFromAddressesTransitionV0 { struct IdentityCreateFromAddressesTransitionV0Inner { // Own ST fields public_keys: Vec, + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(with = "crate::address_funds::platform_address_map_serde") + )] inputs: BTreeMap, output: Option<(PlatformAddress, Credits)>, fee_strategy: AddressFundsFeeStrategy, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_to_addresses_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_to_addresses_transition/v0/mod.rs index f0fa91ad74c..024ca28096a 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_to_addresses_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_to_addresses_transition/v0/mod.rs @@ -43,6 +43,10 @@ use serde::{Deserialize, Serialize}; pub struct IdentityCreditTransferToAddressesTransitionV0 { // Own ST fields pub identity_id: Identifier, + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(with = "crate::address_funds::platform_address_map_serde") + )] pub recipient_addresses: BTreeMap, pub nonce: IdentityNonce, pub user_fee_increase: UserFeeIncrease, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_topup_from_addresses_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_topup_from_addresses_transition/v0/mod.rs index 38ceb07ad01..928e51b26cb 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_topup_from_addresses_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_topup_from_addresses_transition/v0/mod.rs @@ -28,6 +28,10 @@ use crate::ProtocolError; )] #[derive(Default)] pub struct IdentityTopUpFromAddressesTransitionV0 { + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(with = "crate::address_funds::platform_address_map_serde") + )] pub inputs: BTreeMap, /// Optional output to send remaining credits to an address pub output: Option<(PlatformAddress, Credits)>, From f0edbfe3bfb5ca9a0e862faef0da9987ab9d3d25 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 15:54:10 +0000 Subject: [PATCH 07/12] Run cargo fmt on new code Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> --- .../rs-dpp/src/address_funds/platform_address_map_serde.rs | 7 +------ .../src/state_transition/test_json_serde_integration.rs | 4 +++- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/rs-dpp/src/address_funds/platform_address_map_serde.rs b/packages/rs-dpp/src/address_funds/platform_address_map_serde.rs index da6525c6079..a15294805eb 100644 --- a/packages/rs-dpp/src/address_funds/platform_address_map_serde.rs +++ b/packages/rs-dpp/src/address_funds/platform_address_map_serde.rs @@ -9,10 +9,7 @@ use std::fmt; use std::marker::PhantomData; use std::str::FromStr; -pub fn serialize( - map: &BTreeMap, - serializer: S, -) -> Result +pub fn serialize(map: &BTreeMap, serializer: S) -> Result where S: Serializer, V: Serialize, @@ -59,5 +56,3 @@ where marker: PhantomData, }) } - - diff --git a/packages/rs-dpp/src/state_transition/test_json_serde_integration.rs b/packages/rs-dpp/src/state_transition/test_json_serde_integration.rs index 21c587f9811..a2324ea2db5 100644 --- a/packages/rs-dpp/src/state_transition/test_json_serde_integration.rs +++ b/packages/rs-dpp/src/state_transition/test_json_serde_integration.rs @@ -80,7 +80,9 @@ mod test_serde_json_serialization { } Err(e) => { println!("FAILED: serde serialization error: {}", e); - println!("This is expected - PlatformAddress as BTreeMap key doesn't work with serde"); + println!( + "This is expected - PlatformAddress as BTreeMap key doesn't work with serde" + ); } } From 314a1c6d1feacdbefe493b838aa69ae6ae93618a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 14:37:33 +0000 Subject: [PATCH 08/12] Add state-transition-json-conversion feature to wasm-dpp2 Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com> --- packages/wasm-dpp2/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/wasm-dpp2/Cargo.toml b/packages/wasm-dpp2/Cargo.toml index 7297b062f17..6e3ee7b6a08 100644 --- a/packages/wasm-dpp2/Cargo.toml +++ b/packages/wasm-dpp2/Cargo.toml @@ -16,6 +16,7 @@ wasm-bindgen = { version = "=0.2.108", default-features = false, features = [ dpp = { path = "../rs-dpp", default-features = false, features = [ "state-transition-signing", "state-transition-value-conversion", + "state-transition-json-conversion", "document-json-conversion", "identity-serialization", "identity-value-conversion", From 5a43766eca2388c6ed4cd44e7f9c7df1d7326ae1 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Mon, 23 Feb 2026 13:45:53 +0100 Subject: [PATCH 09/12] test: improve state transition JSON conversion tests with given/when/then docs Replace verbose println-based tests with proper assertion-based tests that validate both to_json() and serde_json serialization paths produce correct string keys for BTreeMap fields. Co-Authored-By: Claude Opus 4.6 --- .../test_json_serde_integration.rs | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/packages/rs-dpp/src/state_transition/test_json_serde_integration.rs b/packages/rs-dpp/src/state_transition/test_json_serde_integration.rs index a2324ea2db5..7e6b910f865 100644 --- a/packages/rs-dpp/src/state_transition/test_json_serde_integration.rs +++ b/packages/rs-dpp/src/state_transition/test_json_serde_integration.rs @@ -12,6 +12,56 @@ mod test_serde_json_serialization { }; use std::collections::BTreeMap; + /// Recursively search a JSON value for a given key name. + fn find_key_recursive<'a>( + val: &'a serde_json::Value, + key: &str, + ) -> Option<&'a serde_json::Value> { + match val { + serde_json::Value::Object(map) => { + if let Some(v) = map.get(key) { + return Some(v); + } + for v in map.values() { + if let Some(found) = find_key_recursive(v, key) { + return Some(found); + } + } + None + } + serde_json::Value::Array(arr) => { + for v in arr { + if let Some(found) = find_key_recursive(v, key) { + return Some(found); + } + } + None + } + _ => None, + } + } + + /// Helper: build an AddressFundsTransfer StateTransition with known addresses. + fn make_address_funds_transfer() -> StateTransition { + let mut inputs = BTreeMap::new(); + let input_address = PlatformAddress::P2pkh([1u8; 20]); + inputs.insert(input_address, (1u32, 1000u64)); + + let mut outputs = BTreeMap::new(); + let output_address = PlatformAddress::P2pkh([2u8; 20]); + outputs.insert(output_address, 900u64); + + let v0 = AddressFundsTransferTransitionV0 { + inputs, + outputs, + user_fee_increase: 0, + fee_strategy: Default::default(), + input_witnesses: vec![], + }; + + StateTransition::AddressFundsTransfer(AddressFundsTransferTransition::V0(v0)) + } + #[test] fn test_variant_to_json() { // Test if the variant's to_json works (as claimed in the original issue) @@ -102,4 +152,65 @@ mod test_serde_json_serialization { } } } + + /// Given an AddressFundsTransfer variant with BTreeMap fields, + /// When calling to_json() on the inner variant directly, + /// Then serialization succeeds without "key must be a string" errors. + #[test] + fn variant_to_json_succeeds() { + let st = make_address_funds_transfer(); + if let StateTransition::AddressFundsTransfer(ref inner) = st { + inner + .to_json(JsonStateTransitionSerializationOptions::default()) + .expect("variant to_json should succeed"); + } + } + + /// Given an AddressFundsTransfer wrapped in the top-level StateTransition enum, + /// When calling to_json() on the enum and serde_json::to_string_pretty(), + /// Then both serialization paths succeed and PlatformAddress map keys are + /// rendered as human-readable strings (e.g. "P2PKH(hex...)"), not complex objects. + #[test] + fn enum_to_json_succeeds_and_serde_roundtrips() { + let st = make_address_funds_transfer(); + + // StateTransition::to_json() must succeed (the whole point of the fix). + let json = st + .to_json(JsonStateTransitionSerializationOptions::default()) + .expect("StateTransition::to_json should succeed"); + + // serde_json must also work now (custom map-key serializer). + let serde_json_str = serde_json::to_string_pretty(&st) + .expect("serde_json::to_string_pretty should succeed after custom serde fix"); + + // The to_json output must contain string keys for PlatformAddress maps. + let inputs = json.get("inputs").expect("JSON must have 'inputs' field"); + assert!( + inputs.is_object(), + "inputs must be a JSON object (string keys)" + ); + for key in inputs.as_object().unwrap().keys() { + assert!( + key.starts_with("P2PKH(") || key.starts_with("P2SH("), + "map key must be a PlatformAddress Display string, got: {key}" + ); + } + + // The serde output must also have string keys for PlatformAddress maps. + // The exact nesting depends on enum repr; find "inputs" anywhere in the tree. + let serde_val: serde_json::Value = + serde_json::from_str(&serde_json_str).expect("re-parse must succeed"); + let inputs_field = find_key_recursive(&serde_val, "inputs") + .expect("serde JSON must contain an 'inputs' field somewhere"); + assert!( + inputs_field.is_object(), + "serde inputs must be a JSON object with string keys" + ); + for key in inputs_field.as_object().unwrap().keys() { + assert!( + key.starts_with("P2PKH(") || key.starts_with("P2SH("), + "serde map key must be a PlatformAddress Display string, got: {key}" + ); + } + } } From 82abea6b3d1dc531716741ef70504409445357fd Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Mon, 23 Feb 2026 13:50:47 +0100 Subject: [PATCH 10/12] test: clean up duplicate tests in state transition JSON conversion Remove duplicated test functions, keep the consolidated versions with shared helper, proper assertions, and given/when/then docstrings. Co-Authored-By: Claude Opus 4.6 --- .../test_json_serde_integration.rs | 91 ------------------- 1 file changed, 91 deletions(-) diff --git a/packages/rs-dpp/src/state_transition/test_json_serde_integration.rs b/packages/rs-dpp/src/state_transition/test_json_serde_integration.rs index 7e6b910f865..9e7605df038 100644 --- a/packages/rs-dpp/src/state_transition/test_json_serde_integration.rs +++ b/packages/rs-dpp/src/state_transition/test_json_serde_integration.rs @@ -62,97 +62,6 @@ mod test_serde_json_serialization { StateTransition::AddressFundsTransfer(AddressFundsTransferTransition::V0(v0)) } - #[test] - fn test_variant_to_json() { - // Test if the variant's to_json works (as claimed in the original issue) - let mut inputs = BTreeMap::new(); - let input_address = PlatformAddress::P2pkh([1u8; 20]); - inputs.insert(input_address, (1u32, 1000u64)); - - let mut outputs = BTreeMap::new(); - let output_address = PlatformAddress::P2pkh([2u8; 20]); - outputs.insert(output_address, 900u64); - - let transition_v0 = AddressFundsTransferTransitionV0 { - inputs, - outputs, - user_fee_increase: 0, - fee_strategy: Default::default(), - input_witnesses: vec![], - }; - - let transition = AddressFundsTransferTransition::V0(transition_v0); - - println!("\n=== Testing variant.to_json() ==="); - match transition.to_json(JsonStateTransitionSerializationOptions::default()) { - Ok(json_value) => { - println!("SUCCESS: variant to_json() worked!"); - println!( - "JSON:\n{}", - serde_json::to_string_pretty(&json_value).unwrap() - ); - } - Err(e) => { - println!("FAILED: variant to_json() error: {:?}", e); - panic!("Expected variant to_json to work but it failed: {:?}", e); - } - } - } - - #[test] - fn test_state_transition_enum_to_json() { - // Test if the top-level StateTransition enum's to_json works - let mut inputs = BTreeMap::new(); - let input_address = PlatformAddress::P2pkh([1u8; 20]); - inputs.insert(input_address, (1u32, 1000u64)); - - let mut outputs = BTreeMap::new(); - let output_address = PlatformAddress::P2pkh([2u8; 20]); - outputs.insert(output_address, 900u64); - - let transition_v0 = AddressFundsTransferTransitionV0 { - inputs, - outputs, - user_fee_increase: 0, - fee_strategy: Default::default(), - input_witnesses: vec![], - }; - - let transition = AddressFundsTransferTransition::V0(transition_v0); - let state_transition = StateTransition::AddressFundsTransfer(transition.clone()); - - // Test 1: Try serde_json::to_string_pretty (this should fail with "key must be a string") - println!("\n=== Testing serde_json::to_string_pretty ==="); - match serde_json::to_string_pretty(&state_transition) { - Ok(json_str) => { - println!("SUCCESS: serde serialization worked!"); - println!("JSON:\n{}", json_str); - } - Err(e) => { - println!("FAILED: serde serialization error: {}", e); - println!( - "This is expected - PlatformAddress as BTreeMap key doesn't work with serde" - ); - } - } - - // Test 2: Try our custom to_json() method on the enum - println!("\n=== Testing StateTransition enum to_json() method ==="); - match state_transition.to_json(JsonStateTransitionSerializationOptions::default()) { - Ok(json_value) => { - println!("SUCCESS: enum to_json() worked!"); - println!( - "JSON:\n{}", - serde_json::to_string_pretty(&json_value).unwrap() - ); - } - Err(e) => { - println!("FAILED: enum to_json() error: {:?}", e); - panic!("Expected enum to_json to work but it failed: {:?}", e); - } - } - } - /// Given an AddressFundsTransfer variant with BTreeMap fields, /// When calling to_json() on the inner variant directly, /// Then serialization succeeds without "key must be a string" errors. From 2ec9acc03ed63dcce22e00cf64f5c01cfc6131a6 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Mon, 23 Feb 2026 13:52:26 +0100 Subject: [PATCH 11/12] test: add wasm-dpp2 test for StateTransition JSON conversion Verify that StateTransition::to_json() and serde_json serialization work correctly in the wasm-dpp2 context with its enabled features, including string keys for BTreeMap fields. Co-Authored-By: Claude Opus 4.6 --- .../base/state_transition.rs | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/packages/wasm-dpp2/src/state_transitions/base/state_transition.rs b/packages/wasm-dpp2/src/state_transitions/base/state_transition.rs index 2cd140ac40c..4e20d1b4aef 100644 --- a/packages/wasm-dpp2/src/state_transitions/base/state_transition.rs +++ b/packages/wasm-dpp2/src/state_transitions/base/state_transition.rs @@ -714,3 +714,59 @@ impl StateTransitionWasm { } impl_wasm_type_info!(StateTransitionWasm, StateTransition); + +#[cfg(test)] +mod tests { + use dpp::address_funds::PlatformAddress; + use dpp::state_transition::address_funds_transfer_transition::v0::AddressFundsTransferTransitionV0; + use dpp::state_transition::address_funds_transfer_transition::AddressFundsTransferTransition; + use dpp::state_transition::{ + JsonStateTransitionSerializationOptions, StateTransition, StateTransitionJsonConvert, + }; + use std::collections::BTreeMap; + + /// Given a StateTransition::AddressFundsTransfer with BTreeMap fields + /// built using features enabled by wasm-dpp2 (state-transition-json-conversion, + /// state-transition-serde-conversion), + /// When calling to_json() on the top-level StateTransition enum, + /// Then serialization succeeds and PlatformAddress map keys are human-readable strings. + #[test] + fn state_transition_to_json_works_with_wasm_dpp2_features() { + let mut inputs = BTreeMap::new(); + inputs.insert(PlatformAddress::P2pkh([0xAA; 20]), (1u32, 5000u64)); + + let mut outputs = BTreeMap::new(); + outputs.insert(PlatformAddress::P2pkh([0xBB; 20]), 4500u64); + + let st = StateTransition::AddressFundsTransfer(AddressFundsTransferTransition::V0( + AddressFundsTransferTransitionV0 { + inputs, + outputs, + user_fee_increase: 0, + fee_strategy: Default::default(), + input_witnesses: vec![], + }, + )); + + // to_json() via StateTransitionJsonConvert must work. + let json = st + .to_json(JsonStateTransitionSerializationOptions::default()) + .expect("StateTransition::to_json must succeed in wasm-dpp2 context"); + + let inputs_obj = json + .get("inputs") + .and_then(|v| v.as_object()) + .expect("JSON inputs must be an object with string keys"); + + for key in inputs_obj.keys() { + assert!( + key.starts_with("P2PKH(") || key.starts_with("P2SH("), + "expected PlatformAddress Display string key, got: {key}" + ); + } + + // serde_json direct serialization must also work. + serde_json::to_string(&st) + .expect("serde_json::to_string must succeed for StateTransition in wasm-dpp2"); + } +} From aa87b3f90b6e121aed33f49afaeec9a10a163deb Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Mon, 23 Feb 2026 14:01:54 +0100 Subject: [PATCH 12/12] chore: fmt --- .../wasm-dpp2/src/state_transitions/base/state_transition.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wasm-dpp2/src/state_transitions/base/state_transition.rs b/packages/wasm-dpp2/src/state_transitions/base/state_transition.rs index 4e20d1b4aef..46db2aa59ec 100644 --- a/packages/wasm-dpp2/src/state_transitions/base/state_transition.rs +++ b/packages/wasm-dpp2/src/state_transitions/base/state_transition.rs @@ -718,8 +718,8 @@ impl_wasm_type_info!(StateTransitionWasm, StateTransition); #[cfg(test)] mod tests { use dpp::address_funds::PlatformAddress; - use dpp::state_transition::address_funds_transfer_transition::v0::AddressFundsTransferTransitionV0; use dpp::state_transition::address_funds_transfer_transition::AddressFundsTransferTransition; + use dpp::state_transition::address_funds_transfer_transition::v0::AddressFundsTransferTransitionV0; use dpp::state_transition::{ JsonStateTransitionSerializationOptions, StateTransition, StateTransitionJsonConvert, };