From 73591df887f39cd9709f54ee51c9e1d2c3d4e915 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Mon, 23 Feb 2026 18:27:05 +0700 Subject: [PATCH 01/15] feat(wasm-dpp2): add platform address transition WASM bindings --- packages/wasm-dpp2/src/lib.rs | 5 + .../wasm-dpp2/src/platform_address/address.rs | 13 +- .../src/platform_address/fee_strategy.rs | 31 ++ .../src/platform_address/input_output.rs | 135 +++++++- .../wasm-dpp2/src/platform_address/mod.rs | 8 +- .../address_credit_withdrawal_transition.rs | 315 ++++++++++++++++++ ...ress_funding_from_asset_lock_transition.rs | 257 ++++++++++++++ .../address_funds_transfer_transition.rs | 232 +++++++++++++ ...entity_create_from_addresses_transition.rs | 281 ++++++++++++++++ ...credit_transfer_to_addresses_transition.rs | 274 +++++++++++++++ ...entity_top_up_from_addresses_transition.rs | 269 +++++++++++++++ .../src/platform_address/transitions/mod.rs | 13 + .../AddressCreditWithdrawalTransition.spec.ts | 208 ++++++++++++ ...ressFundingFromAssetLockTransition.spec.ts | 201 +++++++++++ .../tests/unit/AddressFundsTransfer.spec.ts | 6 +- .../AddressFundsTransferTransition.spec.ts | 171 ++++++++++ ...ntityCreateFromAddressesTransition.spec.ts | 187 +++++++++++ .../IdentityCreditTransferToAddresses.spec.ts | 198 +++++++++++ ...entityTopUpFromAddressesTransition.spec.ts | 180 ++++++++++ 19 files changed, 2976 insertions(+), 8 deletions(-) create mode 100644 packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs create mode 100644 packages/wasm-dpp2/src/platform_address/transitions/address_funding_from_asset_lock_transition.rs create mode 100644 packages/wasm-dpp2/src/platform_address/transitions/address_funds_transfer_transition.rs create mode 100644 packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs create mode 100644 packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs create mode 100644 packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs create mode 100644 packages/wasm-dpp2/src/platform_address/transitions/mod.rs create mode 100644 packages/wasm-dpp2/tests/unit/AddressCreditWithdrawalTransition.spec.ts create mode 100644 packages/wasm-dpp2/tests/unit/AddressFundingFromAssetLockTransition.spec.ts create mode 100644 packages/wasm-dpp2/tests/unit/AddressFundsTransferTransition.spec.ts create mode 100644 packages/wasm-dpp2/tests/unit/IdentityCreateFromAddressesTransition.spec.ts create mode 100644 packages/wasm-dpp2/tests/unit/IdentityCreditTransferToAddresses.spec.ts create mode 100644 packages/wasm-dpp2/tests/unit/IdentityTopUpFromAddressesTransition.spec.ts diff --git a/packages/wasm-dpp2/src/lib.rs b/packages/wasm-dpp2/src/lib.rs index 845706a0cf2..cc23e1df137 100644 --- a/packages/wasm-dpp2/src/lib.rs +++ b/packages/wasm-dpp2/src/lib.rs @@ -61,6 +61,11 @@ pub use platform_address::{ PlatformAddressWasm, default_fee_strategy, fee_strategy_from_steps, fee_strategy_from_steps_or_default, outputs_to_btree_map, outputs_to_optional_btree_map, }; +pub use platform_address::transitions::{ + AddressCreditWithdrawalTransitionWasm, AddressFundingFromAssetLockTransitionWasm, + AddressFundsTransferTransitionWasm, IdentityCreateFromAddressesTransitionWasm, + IdentityCreditTransferToAddressesTransitionWasm, IdentityTopUpFromAddressesTransitionWasm, +}; pub use state_transitions::base::{GroupStateTransitionInfoWasm, StateTransitionWasm}; pub use state_transitions::proof_result::{StateTransitionProofResultTypeJs, convert_proof_result}; pub use tokens::*; diff --git a/packages/wasm-dpp2/src/platform_address/address.rs b/packages/wasm-dpp2/src/platform_address/address.rs index 6fe96dcde06..546a12dc3dc 100644 --- a/packages/wasm-dpp2/src/platform_address/address.rs +++ b/packages/wasm-dpp2/src/platform_address/address.rs @@ -5,9 +5,10 @@ use crate::utils::IntoWasm; use dpp::address_funds::PlatformAddress; use dpp::dashcore::Network; use js_sys::Uint8Array; -use serde::de::{self, Error, Visitor}; +use serde::de::{self, Error, MapAccess, Visitor}; use serde::ser::Serializer; use serde::{Deserialize, Deserializer, Serialize}; +use serde_json::Value as JsonValue; use std::fmt; use wasm_bindgen::prelude::*; @@ -197,6 +198,16 @@ impl<'de> Visitor<'de> for PlatformAddressWasmVisitor { .map(PlatformAddressWasm) .map_err(|e| A::Error::custom(e.to_string())) } + + fn visit_map(self, map: M) -> Result + where + M: MapAccess<'de>, + { + let value = JsonValue::deserialize(de::value::MapAccessDeserializer::new(map)) + .map_err(M::Error::custom)?; + let js_value = serde_wasm_bindgen::to_value(&value).map_err(M::Error::custom)?; + PlatformAddressWasm::try_from(&js_value).map_err(|err| M::Error::custom(err.to_string())) + } } impl<'de> Deserialize<'de> for PlatformAddressWasm { diff --git a/packages/wasm-dpp2/src/platform_address/fee_strategy.rs b/packages/wasm-dpp2/src/platform_address/fee_strategy.rs index 8f815a0c5a8..39b2878d2a1 100644 --- a/packages/wasm-dpp2/src/platform_address/fee_strategy.rs +++ b/packages/wasm-dpp2/src/platform_address/fee_strategy.rs @@ -1,3 +1,6 @@ +use crate::error::{WasmDppError, WasmDppResult}; +use crate::impl_wasm_type_info; +use crate::utils::{IntoWasm, try_from_options_optional_with, try_to_array}; use dpp::address_funds::{AddressFundsFeeStrategy, AddressFundsFeeStrategyStep}; use serde::Deserialize; use serde::de::{self, Deserializer, MapAccess, Visitor}; @@ -56,6 +59,8 @@ impl FeeStrategyStepWasm { } } +impl_wasm_type_info!(FeeStrategyStepWasm, FeeStrategyStep); + impl From for AddressFundsFeeStrategyStep { fn from(step: FeeStrategyStepWasm) -> Self { step.0 @@ -87,6 +92,32 @@ pub fn fee_strategy_from_steps_or_default( .unwrap_or_else(default_fee_strategy) } +/// Extract an optional Vec from a JS options object property. +/// +/// Returns None if the property is undefined or null. +pub fn fee_strategy_from_js_options( + options: &JsValue, + field_name: &str, +) -> WasmDppResult>> { + try_from_options_optional_with(options, field_name, |v| { + let array = try_to_array(v, field_name)?; + array + .iter() + .enumerate() + .map(|(i, item)| { + item.to_wasm::("FeeStrategyStep") + .map(|r| (*r).clone()) + .map_err(|_| { + WasmDppError::invalid_argument(format!( + "{}[{}] is not a FeeStrategyStep", + field_name, i + )) + }) + }) + .collect() + }) +} + impl<'de> Deserialize<'de> for FeeStrategyStepWasm { fn deserialize(deserializer: D) -> Result where diff --git a/packages/wasm-dpp2/src/platform_address/input_output.rs b/packages/wasm-dpp2/src/platform_address/input_output.rs index dd130528a2c..0457a969652 100644 --- a/packages/wasm-dpp2/src/platform_address/input_output.rs +++ b/packages/wasm-dpp2/src/platform_address/input_output.rs @@ -1,6 +1,7 @@ use super::{PlatformAddressLikeJs, PlatformAddressWasm}; -use crate::error::WasmDppResult; -use crate::utils::try_to_u64; +use crate::error::{WasmDppError, WasmDppResult}; +use crate::impl_wasm_type_info; +use crate::utils::{try_to_u64, IntoWasm}; use dpp::address_funds::PlatformAddress; use dpp::fee::Credits; use dpp::prelude::AddressNonce; @@ -22,6 +23,8 @@ pub struct PlatformAddressInputWasm { amount: Credits, } +impl_wasm_type_info!(PlatformAddressInputWasm, PlatformAddressInput); + #[wasm_bindgen(js_class = PlatformAddressInput)] impl PlatformAddressInputWasm { /// Creates a new PlatformAddressInput. @@ -65,6 +68,14 @@ impl PlatformAddressInputWasm { } impl PlatformAddressInputWasm { + pub fn new(address: PlatformAddress, nonce: AddressNonce, amount: Credits) -> Self { + Self { + address: address.into(), + nonce, + amount, + } + } + /// Returns the inner values as a tuple suitable for BTreeMap insertion. pub fn into_inner(self) -> (PlatformAddress, (AddressNonce, Credits)) { (self.address.into(), (self.nonce, self.amount)) @@ -86,6 +97,8 @@ pub struct PlatformAddressOutputWasm { amount: Option, } +impl_wasm_type_info!(PlatformAddressOutputWasm, PlatformAddressOutput); + #[wasm_bindgen(js_class = PlatformAddressOutput)] impl PlatformAddressOutputWasm { /// Creates a new PlatformAddressOutput with a specific amount. @@ -122,6 +135,20 @@ impl PlatformAddressOutputWasm { } impl PlatformAddressOutputWasm { + pub fn new(address: PlatformAddress, amount: Credits) -> Self { + Self { + address: address.into(), + amount: Some(amount), + } + } + + pub fn new_optional(address: PlatformAddress, amount: Option) -> Self { + Self { + address: address.into(), + amount, + } + } + /// Returns the inner values as a tuple suitable for BTreeMap insertion. /// Panics if amount is None - use `into_inner_optional` for optional amounts. pub fn into_inner(self) -> (PlatformAddress, Credits) { @@ -156,3 +183,107 @@ pub fn outputs_to_optional_btree_map( .map(|o| o.into_inner_optional()) .collect() } + +/// Extract a Vec from a JS options object property. +/// +/// Reads the named property as a JS array, then extracts each element +/// as a PlatformAddressInput wasm-bindgen object via its __wbg_ptr. +pub fn inputs_from_js_options( + options: &JsValue, + field_name: &str, +) -> WasmDppResult> { + let value = js_sys::Reflect::get(options, &JsValue::from_str(field_name)).map_err(|_| { + WasmDppError::invalid_argument(format!("failed to read '{}' from options", field_name)) + })?; + if value.is_undefined() || value.is_null() { + return Err(WasmDppError::invalid_argument(format!( + "'{}' is required", + field_name + ))); + } + if !js_sys::Array::is_array(&value) { + return Err(WasmDppError::invalid_argument(format!( + "'{}' must be an array", + field_name + ))); + } + let array = js_sys::Array::from(&value); + array + .iter() + .enumerate() + .map(|(i, item)| { + item.to_wasm::("PlatformAddressInput") + .map(|r| (*r).clone()) + .map_err(|_| { + WasmDppError::invalid_argument(format!( + "{}[{}] is not a PlatformAddressInput", + field_name, i + )) + }) + }) + .collect() +} + +/// Extract a Vec from a JS options object property. +/// +/// Reads the named property as a JS array, then extracts each element +/// as a PlatformAddressOutput wasm-bindgen object via its __wbg_ptr. +pub fn outputs_from_js_options( + options: &JsValue, + field_name: &str, +) -> WasmDppResult> { + let value = js_sys::Reflect::get(options, &JsValue::from_str(field_name)).map_err(|_| { + WasmDppError::invalid_argument(format!("failed to read '{}' from options", field_name)) + })?; + if value.is_undefined() || value.is_null() { + return Err(WasmDppError::invalid_argument(format!( + "'{}' is required", + field_name + ))); + } + if !js_sys::Array::is_array(&value) { + return Err(WasmDppError::invalid_argument(format!( + "'{}' must be an array", + field_name + ))); + } + let array = js_sys::Array::from(&value); + array + .iter() + .enumerate() + .map(|(i, item)| { + item.to_wasm::("PlatformAddressOutput") + .map(|r| (*r).clone()) + .map_err(|_| { + WasmDppError::invalid_argument(format!( + "{}[{}] is not a PlatformAddressOutput", + field_name, i + )) + }) + }) + .collect() +} + +/// Extract an optional PlatformAddressOutputWasm from a JS options object property. +/// +/// Returns None if the property is undefined or null. +pub fn optional_output_from_js_options( + options: &JsValue, + field_name: &str, +) -> WasmDppResult> { + let value = js_sys::Reflect::get(options, &JsValue::from_str(field_name)).map_err(|_| { + WasmDppError::invalid_argument(format!("failed to read '{}' from options", field_name)) + })?; + if value.is_undefined() || value.is_null() { + return Ok(None); + } + value + .to_wasm::("PlatformAddressOutput") + .map(|r| Some((*r).clone())) + .map_err(|_| { + WasmDppError::invalid_argument(format!( + "'{}' is not a PlatformAddressOutput", + field_name + )) + }) +} diff --git a/packages/wasm-dpp2/src/platform_address/mod.rs b/packages/wasm-dpp2/src/platform_address/mod.rs index 21e528da0b9..0308f9a5cb0 100644 --- a/packages/wasm-dpp2/src/platform_address/mod.rs +++ b/packages/wasm-dpp2/src/platform_address/mod.rs @@ -2,14 +2,16 @@ mod address; mod fee_strategy; mod input_output; mod signer; +pub mod transitions; pub use address::{PlatformAddressLikeArrayJs, PlatformAddressLikeJs, PlatformAddressWasm}; pub use fee_strategy::{ - FeeStrategyStepWasm, default_fee_strategy, fee_strategy_from_steps, - fee_strategy_from_steps_or_default, + FeeStrategyStepWasm, default_fee_strategy, fee_strategy_from_js_options, + fee_strategy_from_steps, fee_strategy_from_steps_or_default, }; pub use input_output::{ - PlatformAddressInputWasm, PlatformAddressOutputWasm, outputs_to_btree_map, + PlatformAddressInputWasm, PlatformAddressOutputWasm, inputs_from_js_options, + optional_output_from_js_options, outputs_from_js_options, outputs_to_btree_map, outputs_to_optional_btree_map, }; pub use signer::PlatformAddressSignerWasm; diff --git a/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs new file mode 100644 index 00000000000..ecbf56ee662 --- /dev/null +++ b/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs @@ -0,0 +1,315 @@ +use crate::core::core_script::CoreScriptWasm; +use crate::error::{WasmDppError, WasmDppResult}; +use crate::identity::transitions::pooling::{PoolingLikeJs, PoolingWasm}; +use crate::impl_wasm_conversions; +use crate::impl_wasm_type_info; +use crate::platform_address::{ + PlatformAddressInputWasm, PlatformAddressOutputWasm, fee_strategy_from_js_options, + fee_strategy_from_steps_or_default, inputs_from_js_options, optional_output_from_js_options, +}; +use crate::state_transitions::StateTransitionWasm; +use crate::utils::{ + IntoWasm, try_from_options, try_from_options_optional_with, try_from_options_with, try_to_u16, + try_to_u32, +}; +use dpp::platform_value::string_encoding::Encoding::{Base64, Hex}; +use dpp::platform_value::string_encoding::{decode, encode}; +use dpp::prelude::UserFeeIncrease; +use dpp::serialization::{PlatformDeserializable, PlatformSerializable}; +use dpp::state_transition::StateTransition; +use dpp::state_transition::address_credit_withdrawal_transition::AddressCreditWithdrawalTransition; +use dpp::state_transition::address_credit_withdrawal_transition::v0::AddressCreditWithdrawalTransitionV0; +use wasm_bindgen::JsValue; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen(typescript_custom_section)] +const TS_TYPES: &str = r#" +export interface AddressCreditWithdrawalTransitionOptions { + inputs: PlatformAddressInput[]; + output?: PlatformAddressOutput; + outputScript: CoreScript; + pooling: CreditWithdrawalTransitionPoolingLike; + coreFeePerByte: number; + feeStrategy?: FeeStrategyStep[]; + userFeeIncrease?: number; +} + +export interface AddressCreditWithdrawalTransitionObject { + inputs: PlatformAddressInputObject[]; + output?: PlatformAddressOutputObject; + outputScript: Uint8Array; + pooling: number; + coreFeePerByte: number; + feeStrategy: FeeStrategyStepObject[]; + userFeeIncrease: number; +} + +export interface AddressCreditWithdrawalTransitionJSON { + inputs: object[]; + output?: object; + outputScript: string; + pooling: string; + coreFeePerByte: number; + feeStrategy: object[]; + userFeeIncrease: number; +} +"#; + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(typescript_type = "AddressCreditWithdrawalTransitionOptions")] + pub type AddressCreditWithdrawalTransitionOptionsJs; + + #[wasm_bindgen(typescript_type = "AddressCreditWithdrawalTransitionObject")] + pub type AddressCreditWithdrawalTransitionObjectJs; + + #[wasm_bindgen(typescript_type = "AddressCreditWithdrawalTransitionJSON")] + pub type AddressCreditWithdrawalTransitionJSONJs; +} + +#[wasm_bindgen(js_name = "AddressCreditWithdrawalTransition")] +#[derive(Clone, serde::Serialize, serde::Deserialize)] +#[serde(transparent)] +pub struct AddressCreditWithdrawalTransitionWasm(AddressCreditWithdrawalTransition); + +#[wasm_bindgen(js_class = AddressCreditWithdrawalTransition)] +impl AddressCreditWithdrawalTransitionWasm { + #[wasm_bindgen(constructor)] + pub fn constructor( + options: AddressCreditWithdrawalTransitionOptionsJs, + ) -> WasmDppResult { + let js_opts: &JsValue = options.as_ref(); + + // Extract complex types manually (wasm-bindgen objects can't go through serde) + let output_script: CoreScriptWasm = try_from_options(&options, "outputScript")?; + let pooling: PoolingWasm = PoolingWasm::try_from_options(&options, "pooling")?; + let inputs = inputs_from_js_options(js_opts, "inputs")?; + let output = optional_output_from_js_options(js_opts, "output")?; + + // Extract simple fields + let fee_strategy = fee_strategy_from_js_options(js_opts, "feeStrategy")?; + let core_fee_per_byte: u32 = try_from_options_with(js_opts, "coreFeePerByte", |v| { + try_to_u32(v, "coreFeePerByte") + })?; + let user_fee_increase: UserFeeIncrease = + try_from_options_optional_with(js_opts, "userFeeIncrease", |v| { + try_to_u16(v, "userFeeIncrease") + })? + .unwrap_or(0); + + let inputs_map = inputs.into_iter().map(|i| i.into_inner()).collect(); + let output = output.map(|o| o.into_inner()); + let fee_strategy = fee_strategy_from_steps_or_default(fee_strategy); + + Ok(AddressCreditWithdrawalTransitionWasm( + AddressCreditWithdrawalTransition::V0(AddressCreditWithdrawalTransitionV0 { + inputs: inputs_map, + output, + fee_strategy, + core_fee_per_byte, + pooling: pooling.into(), + output_script: output_script.into(), + user_fee_increase, + input_witnesses: Vec::new(), + }), + )) + } + + #[wasm_bindgen(js_name = "toBytes")] + pub fn to_bytes(&self) -> WasmDppResult> { + Ok(self.0.serialize_to_bytes()?) + } + + #[wasm_bindgen(js_name = "toHex")] + pub fn to_hex(&self) -> WasmDppResult { + let bytes = self.0.serialize_to_bytes()?; + Ok(encode(bytes.as_slice(), Hex)) + } + + #[wasm_bindgen(js_name = "toBase64")] + pub fn to_base64(&self) -> WasmDppResult { + let bytes = self.0.serialize_to_bytes()?; + Ok(encode(bytes.as_slice(), Base64)) + } + + #[wasm_bindgen(js_name = "fromBytes")] + pub fn from_bytes(bytes: Vec) -> WasmDppResult { + let rs_transition = + AddressCreditWithdrawalTransition::deserialize_from_bytes(bytes.as_slice())?; + Ok(AddressCreditWithdrawalTransitionWasm(rs_transition)) + } + + #[wasm_bindgen(js_name = "fromHex")] + pub fn from_hex(hex: String) -> WasmDppResult { + let bytes = + decode(hex.as_str(), Hex).map_err(|e| WasmDppError::serialization(e.to_string()))?; + Self::from_bytes(bytes) + } + + #[wasm_bindgen(js_name = "fromBase64")] + pub fn from_base64(base64: String) -> WasmDppResult { + let bytes = decode(base64.as_str(), Base64) + .map_err(|e| WasmDppError::serialization(e.to_string()))?; + Self::from_bytes(bytes) + } + + #[wasm_bindgen(getter = "inputs")] + pub fn inputs(&self) -> Vec { + let inputs_map = match &self.0 { + AddressCreditWithdrawalTransition::V0(v0) => &v0.inputs, + }; + inputs_map + .iter() + .map(|(address, (nonce, amount))| { + PlatformAddressInputWasm::new(*address, *nonce, *amount) + }) + .collect() + } + + #[wasm_bindgen(setter = "inputs")] + pub fn set_inputs(&mut self, inputs: Vec) { + let inputs_map = inputs.into_iter().map(|i| i.into_inner()).collect(); + match &mut self.0 { + AddressCreditWithdrawalTransition::V0(v0) => { + v0.inputs = inputs_map; + } + } + } + + #[wasm_bindgen(getter = "output")] + pub fn output(&self) -> Option { + let output = match &self.0 { + AddressCreditWithdrawalTransition::V0(v0) => &v0.output, + }; + output.map(|(address, credits)| PlatformAddressOutputWasm::new(address, credits)) + } + + #[wasm_bindgen(setter = "output")] + pub fn set_output(&mut self, output: JsValue) -> WasmDppResult<()> { + let new_output = if output.is_undefined() || output.is_null() { + None + } else { + let output_wasm = output + .to_wasm::("PlatformAddressOutput") + .map(|r| (*r).clone()) + .map_err(|_| { + WasmDppError::invalid_argument("'output' is not a PlatformAddressOutput") + })?; + Some(output_wasm.into_inner()) + }; + match &mut self.0 { + AddressCreditWithdrawalTransition::V0(v0) => { + v0.output = new_output; + } + } + Ok(()) + } + + #[wasm_bindgen(getter = "outputScript")] + pub fn output_script(&self) -> CoreScriptWasm { + match &self.0 { + AddressCreditWithdrawalTransition::V0(v0) => v0.output_script.clone().into(), + } + } + + #[wasm_bindgen(setter = "outputScript")] + pub fn set_output_script(&mut self, script: &JsValue) -> WasmDppResult<()> { + let script = CoreScriptWasm::try_from(script)?; + match &mut self.0 { + AddressCreditWithdrawalTransition::V0(v0) => { + v0.output_script = script.into(); + } + } + Ok(()) + } + + #[wasm_bindgen(getter = "pooling")] + pub fn pooling(&self) -> String { + match &self.0 { + AddressCreditWithdrawalTransition::V0(v0) => PoolingWasm::from(v0.pooling).into(), + } + } + + #[wasm_bindgen(setter = "pooling")] + pub fn set_pooling(&mut self, pooling: PoolingLikeJs) -> WasmDppResult<()> { + let pooling: dpp::withdrawal::Pooling = pooling.try_into()?; + match &mut self.0 { + AddressCreditWithdrawalTransition::V0(v0) => { + v0.pooling = pooling; + } + } + Ok(()) + } + + #[wasm_bindgen(getter = "coreFeePerByte")] + pub fn core_fee_per_byte(&self) -> u32 { + match &self.0 { + AddressCreditWithdrawalTransition::V0(v0) => v0.core_fee_per_byte, + } + } + + #[wasm_bindgen(setter = "coreFeePerByte")] + pub fn set_core_fee_per_byte( + &mut self, + #[wasm_bindgen(js_name = "coreFeePerByte")] core_fee_per_byte: &js_sys::Number, + ) -> WasmDppResult<()> { + match &mut self.0 { + AddressCreditWithdrawalTransition::V0(v0) => { + v0.core_fee_per_byte = try_to_u32(core_fee_per_byte, "coreFeePerByte")?; + } + } + Ok(()) + } + + #[wasm_bindgen(getter = "userFeeIncrease")] + pub fn user_fee_increase(&self) -> u16 { + match &self.0 { + AddressCreditWithdrawalTransition::V0(v0) => v0.user_fee_increase, + } + } + + #[wasm_bindgen(setter = "userFeeIncrease")] + pub fn set_user_fee_increase( + &mut self, + #[wasm_bindgen(js_name = "userFeeIncrease")] amount: &js_sys::Number, + ) -> WasmDppResult<()> { + match &mut self.0 { + AddressCreditWithdrawalTransition::V0(v0) => { + v0.user_fee_increase = try_to_u16(amount, "userFeeIncrease")?; + } + } + Ok(()) + } + + #[wasm_bindgen(js_name = "toStateTransition")] + pub fn to_state_transition(&self) -> StateTransitionWasm { + StateTransitionWasm::from(StateTransition::AddressCreditWithdrawal(self.0.clone())) + } + + #[wasm_bindgen(js_name = "fromStateTransition")] + pub fn from_state_transition( + st: &StateTransitionWasm, + ) -> WasmDppResult { + let rs_st: StateTransition = st.clone().into(); + match rs_st { + StateTransition::AddressCreditWithdrawal(st) => { + Ok(AddressCreditWithdrawalTransitionWasm(st)) + } + _ => Err(WasmDppError::invalid_argument( + "Invalid state transition type", + )), + } + } +} + +impl_wasm_conversions!( + AddressCreditWithdrawalTransitionWasm, + AddressCreditWithdrawalTransition, + AddressCreditWithdrawalTransitionObjectJs, + AddressCreditWithdrawalTransitionJSONJs +); + +impl_wasm_type_info!( + AddressCreditWithdrawalTransitionWasm, + AddressCreditWithdrawalTransition +); diff --git a/packages/wasm-dpp2/src/platform_address/transitions/address_funding_from_asset_lock_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/address_funding_from_asset_lock_transition.rs new file mode 100644 index 00000000000..d35350b9f9b --- /dev/null +++ b/packages/wasm-dpp2/src/platform_address/transitions/address_funding_from_asset_lock_transition.rs @@ -0,0 +1,257 @@ +use crate::asset_lock_proof::AssetLockProofWasm; +use crate::error::{WasmDppError, WasmDppResult}; +use crate::impl_wasm_conversions; +use crate::impl_wasm_type_info; +use crate::platform_address::{ + PlatformAddressInputWasm, PlatformAddressOutputWasm, fee_strategy_from_js_options, + fee_strategy_from_steps_or_default, inputs_from_js_options, outputs_from_js_options, +}; +use crate::state_transitions::StateTransitionWasm; +use crate::utils::{try_from_options, try_from_options_optional_with, try_to_u16}; +use dpp::platform_value::string_encoding::Encoding::{Base64, Hex}; +use dpp::platform_value::string_encoding::{decode, encode}; +use dpp::prelude::UserFeeIncrease; +use dpp::serialization::{PlatformDeserializable, PlatformSerializable}; +use dpp::state_transition::address_funding_from_asset_lock_transition::accessors::AddressFundingFromAssetLockTransitionAccessorsV0; +use dpp::state_transition::address_funding_from_asset_lock_transition::v0::AddressFundingFromAssetLockTransitionV0; +use dpp::state_transition::address_funding_from_asset_lock_transition::AddressFundingFromAssetLockTransition; +use dpp::state_transition::StateTransition; +use wasm_bindgen::prelude::wasm_bindgen; +use wasm_bindgen::JsValue; + +#[wasm_bindgen(typescript_custom_section)] +const TS_TYPES: &str = r#" +export interface AddressFundingFromAssetLockTransitionOptions { + assetLockProof: AssetLockProof; + inputs: PlatformAddressInput[]; + outputs: PlatformAddressOutput[]; + feeStrategy?: FeeStrategyStep[]; + userFeeIncrease?: number; +} + +export interface AddressFundingFromAssetLockTransitionObject { + assetLockProof: AssetLockProofObject; + inputs: PlatformAddressInputObject[]; + outputs: PlatformAddressOutputObject[]; + feeStrategy: FeeStrategyStepObject[]; + userFeeIncrease: number; +} + +export interface AddressFundingFromAssetLockTransitionJSON { + assetLockProof: AssetLockProofJSON; + inputs: object[]; + outputs: object[]; + feeStrategy: object[]; + userFeeIncrease: number; +} +"#; + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(typescript_type = "AddressFundingFromAssetLockTransitionOptions")] + pub type AddressFundingFromAssetLockTransitionOptionsJs; + + #[wasm_bindgen(typescript_type = "AddressFundingFromAssetLockTransitionObject")] + pub type AddressFundingFromAssetLockTransitionObjectJs; + + #[wasm_bindgen(typescript_type = "AddressFundingFromAssetLockTransitionJSON")] + pub type AddressFundingFromAssetLockTransitionJSONJs; +} + +#[wasm_bindgen(js_name = "AddressFundingFromAssetLockTransition")] +#[derive(Clone, serde::Serialize, serde::Deserialize)] +#[serde(transparent)] +pub struct AddressFundingFromAssetLockTransitionWasm(AddressFundingFromAssetLockTransition); + +#[wasm_bindgen(js_class = AddressFundingFromAssetLockTransition)] +impl AddressFundingFromAssetLockTransitionWasm { + #[wasm_bindgen(constructor)] + pub fn constructor( + options: AddressFundingFromAssetLockTransitionOptionsJs, + ) -> WasmDppResult { + let js_opts: &JsValue = options.as_ref(); + + // Extract complex wasm-bindgen types manually + let asset_lock: AssetLockProofWasm = try_from_options(&options, "assetLockProof")?; + let inputs = inputs_from_js_options(js_opts, "inputs")?; + let outputs = outputs_from_js_options(js_opts, "outputs")?; + + // Extract simple fields + let fee_strategy = fee_strategy_from_js_options(js_opts, "feeStrategy")?; + let user_fee_increase: UserFeeIncrease = + try_from_options_optional_with(js_opts, "userFeeIncrease", |v| { + try_to_u16(v, "userFeeIncrease") + })? + .unwrap_or(0); + + let inputs_map = inputs.into_iter().map(|i| i.into_inner()).collect(); + let outputs = outputs + .into_iter() + .map(|o| o.into_inner_optional()) + .collect(); + let fee_strategy = fee_strategy_from_steps_or_default(fee_strategy); + + Ok(AddressFundingFromAssetLockTransitionWasm( + AddressFundingFromAssetLockTransition::V0( + AddressFundingFromAssetLockTransitionV0 { + asset_lock_proof: asset_lock.into(), + inputs: inputs_map, + outputs, + fee_strategy, + user_fee_increase, + signature: Default::default(), + input_witnesses: Default::default(), + }, + ), + )) + } + + #[wasm_bindgen(js_name = "toBytes")] + pub fn to_bytes(&self) -> WasmDppResult> { + Ok(self.0.serialize_to_bytes()?) + } + + #[wasm_bindgen(js_name = "toHex")] + pub fn to_hex(&self) -> WasmDppResult { + let bytes = self.0.serialize_to_bytes()?; + Ok(encode(bytes.as_slice(), Hex)) + } + + #[wasm_bindgen(js_name = "toBase64")] + pub fn to_base64(&self) -> WasmDppResult { + let bytes = self.0.serialize_to_bytes()?; + Ok(encode(bytes.as_slice(), Base64)) + } + + #[wasm_bindgen(js_name = "fromBytes")] + pub fn from_bytes( + bytes: Vec, + ) -> WasmDppResult { + let rs_transition = + AddressFundingFromAssetLockTransition::deserialize_from_bytes(bytes.as_slice())?; + Ok(AddressFundingFromAssetLockTransitionWasm(rs_transition)) + } + + #[wasm_bindgen(js_name = "fromHex")] + pub fn from_hex( + hex: String, + ) -> WasmDppResult { + let bytes = + decode(hex.as_str(), Hex).map_err(|e| WasmDppError::serialization(e.to_string()))?; + Self::from_bytes(bytes) + } + + #[wasm_bindgen(js_name = "fromBase64")] + pub fn from_base64( + base64: String, + ) -> WasmDppResult { + let bytes = decode(base64.as_str(), Base64) + .map_err(|e| WasmDppError::serialization(e.to_string()))?; + Self::from_bytes(bytes) + } + + #[wasm_bindgen(getter = "assetLockProof")] + pub fn asset_lock_proof(&self) -> AssetLockProofWasm { + AssetLockProofWasm::from(self.0.asset_lock_proof().clone()) + } + + #[wasm_bindgen(setter = "assetLockProof")] + pub fn set_asset_lock_proof(&mut self, proof: AssetLockProofWasm) { + self.0.set_asset_lock_proof(proof.into()); + } + + #[wasm_bindgen(getter = "inputs")] + pub fn inputs(&self) -> Vec { + let inputs_map = match &self.0 { + AddressFundingFromAssetLockTransition::V0(v0) => &v0.inputs, + }; + inputs_map + .iter() + .map(|(address, (nonce, amount))| { + PlatformAddressInputWasm::new(*address, *nonce, *amount) + }) + .collect() + } + + #[wasm_bindgen(setter = "inputs")] + pub fn set_inputs(&mut self, inputs: Vec) { + let inputs_map = inputs.into_iter().map(|i| i.into_inner()).collect(); + match &mut self.0 { + AddressFundingFromAssetLockTransition::V0(v0) => { + v0.inputs = inputs_map; + } + } + } + + #[wasm_bindgen(getter = "outputs")] + pub fn outputs(&self) -> Vec { + self.0 + .outputs() + .iter() + .map(|(address, amount)| { + PlatformAddressOutputWasm::new_optional(*address, *amount) + }) + .collect() + } + + #[wasm_bindgen(setter = "outputs")] + pub fn set_outputs(&mut self, outputs: Vec) { + let outputs_map = outputs + .into_iter() + .map(|o| o.into_inner_optional()) + .collect(); + self.0.set_outputs(outputs_map); + } + + #[wasm_bindgen(getter = "userFeeIncrease")] + pub fn user_fee_increase(&self) -> u16 { + match &self.0 { + AddressFundingFromAssetLockTransition::V0(v0) => v0.user_fee_increase, + } + } + + #[wasm_bindgen(setter = "userFeeIncrease")] + pub fn set_user_fee_increase( + &mut self, + #[wasm_bindgen(js_name = "userFeeIncrease")] amount: &js_sys::Number, + ) -> WasmDppResult<()> { + match &mut self.0 { + AddressFundingFromAssetLockTransition::V0(v0) => { + v0.user_fee_increase = try_to_u16(amount, "userFeeIncrease")?; + } + } + Ok(()) + } + + #[wasm_bindgen(js_name = "toStateTransition")] + pub fn to_state_transition(&self) -> StateTransitionWasm { + StateTransitionWasm::from(StateTransition::AddressFundingFromAssetLock(self.0.clone())) + } + + #[wasm_bindgen(js_name = "fromStateTransition")] + pub fn from_state_transition( + st: &StateTransitionWasm, + ) -> WasmDppResult { + let rs_st: StateTransition = st.clone().into(); + match rs_st { + StateTransition::AddressFundingFromAssetLock(st) => { + Ok(AddressFundingFromAssetLockTransitionWasm(st)) + } + _ => Err(WasmDppError::invalid_argument( + "Invalid state transition type", + )), + } + } +} + +impl_wasm_conversions!( + AddressFundingFromAssetLockTransitionWasm, + AddressFundingFromAssetLockTransition, + AddressFundingFromAssetLockTransitionObjectJs, + AddressFundingFromAssetLockTransitionJSONJs +); + +impl_wasm_type_info!( + AddressFundingFromAssetLockTransitionWasm, + AddressFundingFromAssetLockTransition +); diff --git a/packages/wasm-dpp2/src/platform_address/transitions/address_funds_transfer_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/address_funds_transfer_transition.rs new file mode 100644 index 00000000000..4482c61f2ee --- /dev/null +++ b/packages/wasm-dpp2/src/platform_address/transitions/address_funds_transfer_transition.rs @@ -0,0 +1,232 @@ +use crate::error::{WasmDppError, WasmDppResult}; +use crate::impl_wasm_conversions; +use crate::impl_wasm_type_info; +use crate::platform_address::{ + PlatformAddressInputWasm, PlatformAddressOutputWasm, fee_strategy_from_js_options, + fee_strategy_from_steps_or_default, inputs_from_js_options, outputs_from_js_options, + outputs_to_btree_map, +}; +use crate::state_transitions::StateTransitionWasm; +use crate::utils::{try_from_options_optional_with, try_to_u16}; +use dpp::platform_value::string_encoding::Encoding::{Base64, Hex}; +use dpp::platform_value::string_encoding::{decode, encode}; +use dpp::prelude::UserFeeIncrease; +use dpp::serialization::{PlatformDeserializable, PlatformSerializable}; +use dpp::state_transition::address_funds_transfer_transition::v0::AddressFundsTransferTransitionV0; +use dpp::state_transition::address_funds_transfer_transition::AddressFundsTransferTransition; +use dpp::state_transition::StateTransition; +use wasm_bindgen::prelude::wasm_bindgen; +use wasm_bindgen::JsValue; + +#[wasm_bindgen(typescript_custom_section)] +const TS_TYPES: &str = r#" +export interface AddressFundsTransferTransitionOptions { + inputs: PlatformAddressInput[]; + outputs: PlatformAddressOutput[]; + feeStrategy?: FeeStrategyStep[]; + userFeeIncrease?: number; +} + +export interface AddressFundsTransferTransitionObject { + inputs: PlatformAddressInputObject[]; + outputs: PlatformAddressOutputObject[]; + feeStrategy: FeeStrategyStepObject[]; + userFeeIncrease: number; +} + +export interface AddressFundsTransferTransitionJSON { + inputs: object[]; + outputs: object[]; + feeStrategy: object[]; + userFeeIncrease: number; +} +"#; + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(typescript_type = "AddressFundsTransferTransitionOptions")] + pub type AddressFundsTransferTransitionOptionsJs; + + #[wasm_bindgen(typescript_type = "AddressFundsTransferTransitionObject")] + pub type AddressFundsTransferTransitionObjectJs; + + #[wasm_bindgen(typescript_type = "AddressFundsTransferTransitionJSON")] + pub type AddressFundsTransferTransitionJSONJs; +} + +#[wasm_bindgen(js_name = "AddressFundsTransferTransition")] +#[derive(Clone, serde::Serialize, serde::Deserialize)] +#[serde(transparent)] +pub struct AddressFundsTransferTransitionWasm(AddressFundsTransferTransition); + +#[wasm_bindgen(js_class = AddressFundsTransferTransition)] +impl AddressFundsTransferTransitionWasm { + #[wasm_bindgen(constructor)] + pub fn constructor( + options: AddressFundsTransferTransitionOptionsJs, + ) -> WasmDppResult { + let js_opts: &JsValue = options.as_ref(); + + // Extract wasm-bindgen objects manually (can't go through serde) + let inputs = inputs_from_js_options(js_opts, "inputs")?; + let outputs = outputs_from_js_options(js_opts, "outputs")?; + + // Extract simple fields via serde for the remaining options + let fee_strategy = fee_strategy_from_js_options(js_opts, "feeStrategy")?; + let user_fee_increase: UserFeeIncrease = + try_from_options_optional_with(js_opts, "userFeeIncrease", |v| { + try_to_u16(v, "userFeeIncrease") + })? + .unwrap_or(0); + + let inputs_map = inputs.into_iter().map(|i| i.into_inner()).collect(); + let outputs_map = outputs_to_btree_map(outputs); + let fee_strategy = fee_strategy_from_steps_or_default(fee_strategy); + + Ok(AddressFundsTransferTransitionWasm( + AddressFundsTransferTransition::V0(AddressFundsTransferTransitionV0 { + inputs: inputs_map, + outputs: outputs_map, + fee_strategy, + user_fee_increase, + input_witnesses: Vec::new(), + }), + )) + } + + #[wasm_bindgen(js_name = "toBytes")] + pub fn to_bytes(&self) -> WasmDppResult> { + Ok(self.0.serialize_to_bytes()?) + } + + #[wasm_bindgen(js_name = "toHex")] + pub fn to_hex(&self) -> WasmDppResult { + let bytes = self.0.serialize_to_bytes()?; + Ok(encode(bytes.as_slice(), Hex)) + } + + #[wasm_bindgen(js_name = "toBase64")] + pub fn to_base64(&self) -> WasmDppResult { + let bytes = self.0.serialize_to_bytes()?; + Ok(encode(bytes.as_slice(), Base64)) + } + + #[wasm_bindgen(js_name = "fromBytes")] + pub fn from_bytes( + bytes: Vec, + ) -> WasmDppResult { + let rs_transition = + AddressFundsTransferTransition::deserialize_from_bytes(bytes.as_slice())?; + Ok(AddressFundsTransferTransitionWasm(rs_transition)) + } + + #[wasm_bindgen(js_name = "fromHex")] + pub fn from_hex(hex: String) -> WasmDppResult { + let bytes = + decode(hex.as_str(), Hex).map_err(|e| WasmDppError::serialization(e.to_string()))?; + Self::from_bytes(bytes) + } + + #[wasm_bindgen(js_name = "fromBase64")] + pub fn from_base64(base64: String) -> WasmDppResult { + let bytes = decode(base64.as_str(), Base64) + .map_err(|e| WasmDppError::serialization(e.to_string()))?; + Self::from_bytes(bytes) + } + + #[wasm_bindgen(getter = "inputs")] + pub fn inputs(&self) -> Vec { + let inputs_map = match &self.0 { + AddressFundsTransferTransition::V0(v0) => &v0.inputs, + }; + inputs_map + .iter() + .map(|(address, (nonce, amount))| { + PlatformAddressInputWasm::new(*address, *nonce, *amount) + }) + .collect() + } + + #[wasm_bindgen(setter = "inputs")] + pub fn set_inputs(&mut self, inputs: Vec) { + let inputs_map = inputs.into_iter().map(|i| i.into_inner()).collect(); + match &mut self.0 { + AddressFundsTransferTransition::V0(v0) => { + v0.inputs = inputs_map; + } + } + } + + #[wasm_bindgen(getter = "outputs")] + pub fn outputs(&self) -> Vec { + let outputs_map = match &self.0 { + AddressFundsTransferTransition::V0(v0) => &v0.outputs, + }; + outputs_map + .iter() + .map(|(address, amount)| PlatformAddressOutputWasm::new(*address, *amount)) + .collect() + } + + #[wasm_bindgen(setter = "outputs")] + pub fn set_outputs(&mut self, outputs: Vec) { + let outputs_map = outputs_to_btree_map(outputs); + match &mut self.0 { + AddressFundsTransferTransition::V0(v0) => { + v0.outputs = outputs_map; + } + } + } + + #[wasm_bindgen(getter = "userFeeIncrease")] + pub fn user_fee_increase(&self) -> u16 { + match &self.0 { + AddressFundsTransferTransition::V0(v0) => v0.user_fee_increase, + } + } + + #[wasm_bindgen(setter = "userFeeIncrease")] + pub fn set_user_fee_increase( + &mut self, + #[wasm_bindgen(js_name = "userFeeIncrease")] amount: &js_sys::Number, + ) -> WasmDppResult<()> { + match &mut self.0 { + AddressFundsTransferTransition::V0(v0) => { + v0.user_fee_increase = try_to_u16(amount, "userFeeIncrease")?; + } + } + Ok(()) + } + + #[wasm_bindgen(js_name = "toStateTransition")] + pub fn to_state_transition(&self) -> StateTransitionWasm { + StateTransitionWasm::from(StateTransition::from(self.0.clone())) + } + + #[wasm_bindgen(js_name = "fromStateTransition")] + pub fn from_state_transition( + st: &StateTransitionWasm, + ) -> WasmDppResult { + let rs_st: StateTransition = st.clone().into(); + match rs_st { + StateTransition::AddressFundsTransfer(st) => { + Ok(AddressFundsTransferTransitionWasm(st)) + } + _ => Err(WasmDppError::invalid_argument( + "Invalid state transition type", + )), + } + } +} + +impl_wasm_conversions!( + AddressFundsTransferTransitionWasm, + AddressFundsTransferTransition, + AddressFundsTransferTransitionObjectJs, + AddressFundsTransferTransitionJSONJs +); + +impl_wasm_type_info!( + AddressFundsTransferTransitionWasm, + AddressFundsTransferTransition +); diff --git a/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs new file mode 100644 index 00000000000..0d099d2be98 --- /dev/null +++ b/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs @@ -0,0 +1,281 @@ +use crate::error::{WasmDppError, WasmDppResult}; +use crate::identity::transitions::public_key_in_creation::IdentityPublicKeyInCreationWasm; +use crate::impl_wasm_conversions; +use crate::impl_wasm_type_info; +use crate::platform_address::{ + PlatformAddressInputWasm, PlatformAddressOutputWasm, fee_strategy_from_js_options, + fee_strategy_from_steps_or_default, inputs_from_js_options, optional_output_from_js_options, +}; +use crate::state_transitions::StateTransitionWasm; +use crate::utils::{try_from_options_optional_with, try_from_options_with, try_to_array, try_to_u16}; +use dpp::platform_value::string_encoding::Encoding::{Base64, Hex}; +use dpp::platform_value::string_encoding::{decode, encode}; +use dpp::prelude::UserFeeIncrease; +use dpp::serialization::{PlatformDeserializable, PlatformSerializable}; +use dpp::state_transition::identity_create_from_addresses_transition::v0::IdentityCreateFromAddressesTransitionV0; +use dpp::state_transition::identity_create_from_addresses_transition::IdentityCreateFromAddressesTransition; +use dpp::state_transition::public_key_in_creation::IdentityPublicKeyInCreation; +use dpp::state_transition::StateTransition; +use wasm_bindgen::prelude::wasm_bindgen; +use wasm_bindgen::JsValue; + +#[wasm_bindgen(typescript_custom_section)] +const TS_TYPES: &str = r#" +export interface IdentityCreateFromAddressesTransitionOptions { + publicKeys: IdentityPublicKeyInCreation[]; + inputs: PlatformAddressInput[]; + output?: PlatformAddressOutput; + feeStrategy?: FeeStrategyStep[]; + userFeeIncrease?: number; +} + +export interface IdentityCreateFromAddressesTransitionObject { + publicKeys: IdentityPublicKeyInCreationObject[]; + inputs: PlatformAddressInputObject[]; + output?: PlatformAddressOutputObject; + feeStrategy: FeeStrategyStepObject[]; + userFeeIncrease: number; +} + +export interface IdentityCreateFromAddressesTransitionJSON { + publicKeys: object[]; + inputs: object[]; + output?: object; + feeStrategy: object[]; + userFeeIncrease: number; +} +"#; + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(typescript_type = "IdentityCreateFromAddressesTransitionOptions")] + pub type IdentityCreateFromAddressesTransitionOptionsJs; + + #[wasm_bindgen(typescript_type = "IdentityCreateFromAddressesTransitionObject")] + pub type IdentityCreateFromAddressesTransitionObjectJs; + + #[wasm_bindgen(typescript_type = "IdentityCreateFromAddressesTransitionJSON")] + pub type IdentityCreateFromAddressesTransitionJSONJs; +} + +#[wasm_bindgen(js_name = "IdentityCreateFromAddressesTransition")] +#[derive(Clone, serde::Serialize, serde::Deserialize)] +#[serde(transparent)] +pub struct IdentityCreateFromAddressesTransitionWasm(IdentityCreateFromAddressesTransition); + +#[wasm_bindgen(js_class = IdentityCreateFromAddressesTransition)] +impl IdentityCreateFromAddressesTransitionWasm { + #[wasm_bindgen(constructor)] + pub fn constructor( + options: IdentityCreateFromAddressesTransitionOptionsJs, + ) -> WasmDppResult { + let js_opts: &JsValue = options.as_ref(); + + // Extract complex wasm-bindgen types manually + let js_public_keys_array = + try_from_options_with(&options, "publicKeys", |v| try_to_array(v, "publicKeys"))?; + let public_keys: Vec = + IdentityPublicKeyInCreationWasm::vec_from_array(&js_public_keys_array)?; + let inputs = inputs_from_js_options(js_opts, "inputs")?; + let output = optional_output_from_js_options(js_opts, "output")?; + + // Extract simple fields + let fee_strategy = fee_strategy_from_js_options(js_opts, "feeStrategy")?; + let user_fee_increase: UserFeeIncrease = + try_from_options_optional_with(js_opts, "userFeeIncrease", |v| { + try_to_u16(v, "userFeeIncrease") + })? + .unwrap_or(0); + + let inputs_map = inputs.into_iter().map(|i| i.into_inner()).collect(); + let output = output.map(|o| o.into_inner()); + let fee_strategy = fee_strategy_from_steps_or_default(fee_strategy); + + Ok(IdentityCreateFromAddressesTransitionWasm( + IdentityCreateFromAddressesTransition::V0( + IdentityCreateFromAddressesTransitionV0 { + public_keys: public_keys.iter().map(|k| k.clone().into()).collect(), + inputs: inputs_map, + output, + fee_strategy, + user_fee_increase, + input_witnesses: Vec::new(), + }, + ), + )) + } + + #[wasm_bindgen(js_name = "toBytes")] + pub fn to_bytes(&self) -> WasmDppResult> { + Ok(self.0.serialize_to_bytes()?) + } + + #[wasm_bindgen(js_name = "toHex")] + pub fn to_hex(&self) -> WasmDppResult { + let bytes = self.0.serialize_to_bytes()?; + Ok(encode(bytes.as_slice(), Hex)) + } + + #[wasm_bindgen(js_name = "toBase64")] + pub fn to_base64(&self) -> WasmDppResult { + let bytes = self.0.serialize_to_bytes()?; + Ok(encode(bytes.as_slice(), Base64)) + } + + #[wasm_bindgen(js_name = "fromBytes")] + pub fn from_bytes( + bytes: Vec, + ) -> WasmDppResult { + let rs_transition = + IdentityCreateFromAddressesTransition::deserialize_from_bytes(bytes.as_slice())?; + Ok(IdentityCreateFromAddressesTransitionWasm(rs_transition)) + } + + #[wasm_bindgen(js_name = "fromHex")] + pub fn from_hex( + hex: String, + ) -> WasmDppResult { + let bytes = + decode(hex.as_str(), Hex).map_err(|e| WasmDppError::serialization(e.to_string()))?; + Self::from_bytes(bytes) + } + + #[wasm_bindgen(js_name = "fromBase64")] + pub fn from_base64( + base64: String, + ) -> WasmDppResult { + let bytes = decode(base64.as_str(), Base64) + .map_err(|e| WasmDppError::serialization(e.to_string()))?; + Self::from_bytes(bytes) + } + + #[wasm_bindgen(getter = "publicKeys")] + pub fn public_keys(&self) -> Vec { + match &self.0 { + IdentityCreateFromAddressesTransition::V0(v0) => v0 + .public_keys + .iter() + .map(|key| IdentityPublicKeyInCreationWasm::from(key.clone())) + .collect(), + } + } + + #[wasm_bindgen(setter = "publicKeys")] + pub fn set_public_keys( + &mut self, + #[wasm_bindgen(js_name = "publicKeys")] public_keys: &js_sys::Array, + ) -> WasmDppResult<()> { + let keys: Vec = + IdentityPublicKeyInCreationWasm::vec_from_array(public_keys)?; + match &mut self.0 { + IdentityCreateFromAddressesTransition::V0(v0) => { + v0.public_keys = keys + .iter() + .map(|k| IdentityPublicKeyInCreation::from(k.clone())) + .collect(); + } + } + Ok(()) + } + + #[wasm_bindgen(getter = "inputs")] + pub fn inputs(&self) -> Vec { + let inputs_map = match &self.0 { + IdentityCreateFromAddressesTransition::V0(v0) => &v0.inputs, + }; + inputs_map + .iter() + .map(|(address, (nonce, amount))| { + PlatformAddressInputWasm::new(*address, *nonce, *amount) + }) + .collect() + } + + #[wasm_bindgen(setter = "inputs")] + pub fn set_inputs(&mut self, inputs: Vec) { + let inputs_map = inputs.into_iter().map(|i| i.into_inner()).collect(); + match &mut self.0 { + IdentityCreateFromAddressesTransition::V0(v0) => { + v0.inputs = inputs_map; + } + } + } + + #[wasm_bindgen(getter = "output")] + pub fn output(&self) -> Option { + let output = match &self.0 { + IdentityCreateFromAddressesTransition::V0(v0) => &v0.output, + }; + output.map(|(address, credits)| PlatformAddressOutputWasm::new(address, credits)) + } + + #[wasm_bindgen(setter = "output")] + pub fn set_output(&mut self, output: JsValue) -> WasmDppResult<()> { + let new_output = if output.is_undefined() || output.is_null() { + None + } else { + let output_wasm: PlatformAddressOutputWasm = + serde_wasm_bindgen::from_value(output) + .map_err(|e| WasmDppError::invalid_argument(e.to_string()))?; + Some(output_wasm.into_inner()) + }; + match &mut self.0 { + IdentityCreateFromAddressesTransition::V0(v0) => { + v0.output = new_output; + } + } + Ok(()) + } + + #[wasm_bindgen(getter = "userFeeIncrease")] + pub fn user_fee_increase(&self) -> u16 { + match &self.0 { + IdentityCreateFromAddressesTransition::V0(v0) => v0.user_fee_increase, + } + } + + #[wasm_bindgen(setter = "userFeeIncrease")] + pub fn set_user_fee_increase( + &mut self, + #[wasm_bindgen(js_name = "userFeeIncrease")] amount: &js_sys::Number, + ) -> WasmDppResult<()> { + match &mut self.0 { + IdentityCreateFromAddressesTransition::V0(v0) => { + v0.user_fee_increase = try_to_u16(amount, "userFeeIncrease")?; + } + } + Ok(()) + } + + #[wasm_bindgen(js_name = "toStateTransition")] + pub fn to_state_transition(&self) -> StateTransitionWasm { + StateTransitionWasm::from(StateTransition::IdentityCreateFromAddresses(self.0.clone())) + } + + #[wasm_bindgen(js_name = "fromStateTransition")] + pub fn from_state_transition( + st: &StateTransitionWasm, + ) -> WasmDppResult { + let rs_st: StateTransition = st.clone().into(); + match rs_st { + StateTransition::IdentityCreateFromAddresses(st) => { + Ok(IdentityCreateFromAddressesTransitionWasm(st)) + } + _ => Err(WasmDppError::invalid_argument( + "Invalid state transition type", + )), + } + } +} + +impl_wasm_conversions!( + IdentityCreateFromAddressesTransitionWasm, + IdentityCreateFromAddressesTransition, + IdentityCreateFromAddressesTransitionObjectJs, + IdentityCreateFromAddressesTransitionJSONJs +); + +impl_wasm_type_info!( + IdentityCreateFromAddressesTransitionWasm, + IdentityCreateFromAddressesTransition +); diff --git a/packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs new file mode 100644 index 00000000000..b5c947967e5 --- /dev/null +++ b/packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs @@ -0,0 +1,274 @@ +use crate::error::{WasmDppError, WasmDppResult}; +use crate::identifier::{IdentifierLikeJs, IdentifierWasm}; +use crate::impl_wasm_conversions; +use crate::impl_wasm_type_info; +use crate::platform_address::{outputs_from_js_options, outputs_to_btree_map, PlatformAddressOutputWasm}; +use crate::state_transitions::StateTransitionWasm; +use crate::utils::{try_to_u16, try_to_u32, try_to_u64}; +use dpp::platform_value::BinaryData; +use dpp::platform_value::string_encoding::Encoding::{Base64, Hex}; +use dpp::platform_value::string_encoding::{decode, encode}; +use dpp::prelude::UserFeeIncrease; +use dpp::serialization::{PlatformDeserializable, PlatformSerializable}; +use dpp::state_transition::identity_credit_transfer_to_addresses_transition::IdentityCreditTransferToAddressesTransition; +use dpp::state_transition::identity_credit_transfer_to_addresses_transition::accessors::IdentityCreditTransferToAddressesTransitionAccessorsV0; +use dpp::state_transition::identity_credit_transfer_to_addresses_transition::v0::IdentityCreditTransferToAddressesTransitionV0; +use dpp::state_transition::{ + StateTransition, StateTransitionIdentitySigned, StateTransitionLike, + StateTransitionSingleSigned, +}; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen(typescript_custom_section)] +const CREDIT_TRANSFER_TO_ADDRESSES_OPTIONS_TS: &str = r#" +export interface IdentityCreditTransferToAddressesOptions { + recipientAddresses: PlatformAddressOutput[]; + senderId: IdentifierLike; + nonce: bigint; + userFeeIncrease?: number; +} + +/** + * IdentityCreditTransferToAddresses serialized as a plain object. + */ +export interface IdentityCreditTransferToAddressesObject { + recipientAddresses: Array<{ address: Uint8Array; amount: bigint }>; + senderId: Uint8Array; + nonce: bigint; + userFeeIncrease: number; + signature?: Uint8Array; + signaturePublicKeyId?: number; +} + +/** + * IdentityCreditTransferToAddresses serialized as JSON. + */ +export interface IdentityCreditTransferToAddressesJSON { + recipientAddresses: Array<{ address: string; amount: string }>; + senderId: string; + nonce: string; + userFeeIncrease: number; + signature?: string; + signaturePublicKeyId?: number; +} +"#; + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(typescript_type = "IdentityCreditTransferToAddressesOptions")] + pub type IdentityCreditTransferToAddressesOptionsJs; + + #[wasm_bindgen(typescript_type = "IdentityCreditTransferToAddressesObject")] + pub type IdentityCreditTransferToAddressesObjectJs; + + #[wasm_bindgen(typescript_type = "IdentityCreditTransferToAddressesJSON")] + pub type IdentityCreditTransferToAddressesJSONJs; +} + +#[wasm_bindgen(js_name = "IdentityCreditTransferToAddresses")] +#[derive(Clone, serde::Serialize, serde::Deserialize)] +#[serde(transparent)] +pub struct IdentityCreditTransferToAddressesTransitionWasm( + IdentityCreditTransferToAddressesTransition, +); + +#[wasm_bindgen(js_class = IdentityCreditTransferToAddresses)] +impl IdentityCreditTransferToAddressesTransitionWasm { + #[wasm_bindgen(constructor)] + pub fn constructor( + options: IdentityCreditTransferToAddressesOptionsJs, + ) -> WasmDppResult { + let js_opts: &wasm_bindgen::JsValue = options.as_ref(); + + // Extract complex wasm-bindgen types manually + let sender_id: IdentifierWasm = crate::utils::try_from_options(&options, "senderId")?; + let recipient_outputs = outputs_from_js_options(js_opts, "recipientAddresses")?; + + // Extract simple fields + let nonce: u64 = + crate::utils::try_from_options_with(js_opts, "nonce", |v| try_to_u64(v, "nonce"))?; + let user_fee_increase: UserFeeIncrease = + crate::utils::try_from_options_optional_with(js_opts, "userFeeIncrease", |v| { + crate::utils::try_to_u16(v, "userFeeIncrease") + })? + .unwrap_or(0); + + let recipient_addresses = outputs_to_btree_map(recipient_outputs); + + Ok(IdentityCreditTransferToAddressesTransitionWasm( + IdentityCreditTransferToAddressesTransition::V0( + IdentityCreditTransferToAddressesTransitionV0 { + identity_id: sender_id.into(), + recipient_addresses, + nonce, + user_fee_increase, + signature_public_key_id: 0, + signature: Default::default(), + }, + ), + )) + } + + #[wasm_bindgen(js_name = "toBytes")] + pub fn to_bytes(&self) -> WasmDppResult> { + Ok(self.0.serialize_to_bytes()?) + } + + #[wasm_bindgen(js_name = "toHex")] + pub fn to_hex(&self) -> WasmDppResult { + let bytes = self.0.serialize_to_bytes()?; + Ok(encode(bytes.as_slice(), Hex)) + } + + #[wasm_bindgen(js_name = "toBase64")] + pub fn to_base64(&self) -> WasmDppResult { + let bytes = self.0.serialize_to_bytes()?; + Ok(encode(bytes.as_slice(), Base64)) + } + + #[wasm_bindgen(js_name = "fromBytes")] + pub fn from_bytes( + bytes: Vec, + ) -> WasmDppResult { + let rs_transition = + IdentityCreditTransferToAddressesTransition::deserialize_from_bytes(bytes.as_slice())?; + + Ok(IdentityCreditTransferToAddressesTransitionWasm( + rs_transition, + )) + } + + #[wasm_bindgen(js_name = "fromHex")] + pub fn from_hex( + hex: String, + ) -> WasmDppResult { + let bytes = + decode(hex.as_str(), Hex).map_err(|e| WasmDppError::serialization(e.to_string()))?; + IdentityCreditTransferToAddressesTransitionWasm::from_bytes(bytes) + } + + #[wasm_bindgen(js_name = "fromBase64")] + pub fn from_base64( + base64: String, + ) -> WasmDppResult { + let bytes = + decode(base64.as_str(), Base64).map_err(|e| WasmDppError::serialization(e.to_string()))?; + IdentityCreditTransferToAddressesTransitionWasm::from_bytes(bytes) + } + + #[wasm_bindgen(getter = "recipientAddresses")] + pub fn recipient_addresses(&self) -> Vec { + self.0 + .recipient_addresses() + .iter() + .map(|(address, amount)| PlatformAddressOutputWasm::new(*address, *amount)) + .collect() + } + + #[wasm_bindgen(setter = "recipientAddresses")] + pub fn set_recipient_addresses( + &mut self, + outputs: Vec, + ) { + self.0 + .set_recipient_addresses(outputs_to_btree_map(outputs)); + } + + #[wasm_bindgen(setter = "senderId")] + pub fn set_sender_id(&mut self, sender: IdentifierLikeJs) -> WasmDppResult<()> { + self.0.set_identity_id(sender.try_into()?); + Ok(()) + } + + #[wasm_bindgen(setter = "nonce")] + pub fn set_nonce(&mut self, nonce: &js_sys::BigInt) -> WasmDppResult<()> { + self.0.set_nonce(try_to_u64(nonce, "nonce")?); + Ok(()) + } + + #[wasm_bindgen(setter = "signature")] + pub fn set_signature(&mut self, signature: Vec) { + self.0.set_signature_bytes(signature) + } + + #[wasm_bindgen(setter = "signaturePublicKeyId")] + pub fn set_signature_public_key_id( + &mut self, + #[wasm_bindgen(js_name = "publicKeyId")] public_key_id: &js_sys::Number, + ) -> WasmDppResult<()> { + self.0 + .set_signature_public_key_id(try_to_u32(public_key_id, "signaturePublicKeyId")?); + Ok(()) + } + + #[wasm_bindgen(setter = "userFeeIncrease")] + pub fn set_user_fee_increase(&mut self, amount: &js_sys::Number) -> WasmDppResult<()> { + self.0 + .set_user_fee_increase(try_to_u16(amount, "userFeeIncrease")?); + Ok(()) + } + + #[wasm_bindgen(getter = "signature")] + pub fn signature(&self) -> Vec { + self.0.signature().to_vec() + } + + #[wasm_bindgen(getter = "signaturePublicKeyId")] + pub fn signature_public_key_id(&self) -> u32 { + self.0.signature_public_key_id() + } + + #[wasm_bindgen(getter = "userFeeIncrease")] + pub fn user_fee_increase(&self) -> u16 { + self.0.user_fee_increase() + } + + #[wasm_bindgen(getter = "senderId")] + pub fn sender_id(&self) -> IdentifierWasm { + self.0.identity_id().into() + } + + #[wasm_bindgen(getter = "nonce")] + pub fn nonce(&self) -> u64 { + self.0.nonce() + } + + #[wasm_bindgen(js_name = "toStateTransition")] + pub fn to_state_transition(&self) -> StateTransitionWasm { + StateTransitionWasm::from(StateTransition::from(self.0.clone())) + } + + #[wasm_bindgen(js_name = "fromStateTransition")] + pub fn from_state_transition( + st: &StateTransitionWasm, + ) -> WasmDppResult { + let rs_st: StateTransition = st.clone().into(); + + match rs_st { + StateTransition::IdentityCreditTransferToAddresses(st) => { + Ok(IdentityCreditTransferToAddressesTransitionWasm(st)) + } + _ => Err(WasmDppError::invalid_argument( + "Invalid state transition type", + )), + } + } +} + +impl IdentityCreditTransferToAddressesTransitionWasm { + pub fn set_signature_binary_data(&mut self, data: BinaryData) { + self.0.set_signature(data) + } +} + +impl_wasm_conversions!( + IdentityCreditTransferToAddressesTransitionWasm, + IdentityCreditTransferToAddresses, + IdentityCreditTransferToAddressesObjectJs, + IdentityCreditTransferToAddressesJSONJs +); + +impl_wasm_type_info!( + IdentityCreditTransferToAddressesTransitionWasm, + IdentityCreditTransferToAddresses +); diff --git a/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs new file mode 100644 index 00000000000..6019899d9b6 --- /dev/null +++ b/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs @@ -0,0 +1,269 @@ +use crate::error::{WasmDppError, WasmDppResult}; +use crate::identifier::{IdentifierLikeJs, IdentifierWasm}; +use crate::impl_wasm_conversions; +use crate::impl_wasm_type_info; +use crate::platform_address::{ + PlatformAddressInputWasm, PlatformAddressOutputWasm, fee_strategy_from_js_options, + fee_strategy_from_steps_or_default, inputs_from_js_options, optional_output_from_js_options, +}; +use crate::state_transitions::StateTransitionWasm; +use crate::utils::{try_from_options_optional_with, try_to_u16}; +use dpp::platform_value::string_encoding::Encoding::{Base64, Hex}; +use dpp::platform_value::string_encoding::{decode, encode}; +use dpp::prelude::UserFeeIncrease; +use dpp::serialization::{PlatformDeserializable, PlatformSerializable}; +use dpp::state_transition::identity_topup_from_addresses_transition::v0::IdentityTopUpFromAddressesTransitionV0; +use dpp::state_transition::identity_topup_from_addresses_transition::IdentityTopUpFromAddressesTransition; +use dpp::state_transition::StateTransition; +use wasm_bindgen::prelude::wasm_bindgen; +use wasm_bindgen::JsValue; + +#[wasm_bindgen(typescript_custom_section)] +const TS_TYPES: &str = r#" +export interface IdentityTopUpFromAddressesTransitionOptions { + identityId: IdentifierLike; + inputs: PlatformAddressInput[]; + output?: PlatformAddressOutput; + feeStrategy?: FeeStrategyStep[]; + userFeeIncrease?: number; +} + +export interface IdentityTopUpFromAddressesTransitionObject { + identityId: Uint8Array; + inputs: PlatformAddressInputObject[]; + output?: PlatformAddressOutputObject; + feeStrategy: FeeStrategyStepObject[]; + userFeeIncrease: number; +} + +export interface IdentityTopUpFromAddressesTransitionJSON { + identityId: string; + inputs: object[]; + output?: object; + feeStrategy: object[]; + userFeeIncrease: number; +} +"#; + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(typescript_type = "IdentityTopUpFromAddressesTransitionOptions")] + pub type IdentityTopUpFromAddressesTransitionOptionsJs; + + #[wasm_bindgen(typescript_type = "IdentityTopUpFromAddressesTransitionObject")] + pub type IdentityTopUpFromAddressesTransitionObjectJs; + + #[wasm_bindgen(typescript_type = "IdentityTopUpFromAddressesTransitionJSON")] + pub type IdentityTopUpFromAddressesTransitionJSONJs; +} + +#[wasm_bindgen(js_name = "IdentityTopUpFromAddressesTransition")] +#[derive(Clone, serde::Serialize, serde::Deserialize)] +#[serde(transparent)] +pub struct IdentityTopUpFromAddressesTransitionWasm(IdentityTopUpFromAddressesTransition); + +#[wasm_bindgen(js_class = IdentityTopUpFromAddressesTransition)] +impl IdentityTopUpFromAddressesTransitionWasm { + #[wasm_bindgen(constructor)] + pub fn constructor( + options: IdentityTopUpFromAddressesTransitionOptionsJs, + ) -> WasmDppResult { + let js_opts: &JsValue = options.as_ref(); + + // Extract complex wasm-bindgen types manually + let identity_id: IdentifierWasm = crate::utils::try_from_options(&options, "identityId")?; + let inputs = inputs_from_js_options(js_opts, "inputs")?; + let output = optional_output_from_js_options(js_opts, "output")?; + + // Extract simple fields + let fee_strategy = fee_strategy_from_js_options(js_opts, "feeStrategy")?; + let user_fee_increase: UserFeeIncrease = + try_from_options_optional_with(js_opts, "userFeeIncrease", |v| { + try_to_u16(v, "userFeeIncrease") + })? + .unwrap_or(0); + + let inputs_map = inputs.into_iter().map(|i| i.into_inner()).collect(); + let output = output.map(|o| o.into_inner()); + let fee_strategy = fee_strategy_from_steps_or_default(fee_strategy); + + Ok(IdentityTopUpFromAddressesTransitionWasm( + IdentityTopUpFromAddressesTransition::V0( + IdentityTopUpFromAddressesTransitionV0 { + identity_id: identity_id.into(), + inputs: inputs_map, + output, + fee_strategy, + user_fee_increase, + input_witnesses: Vec::new(), + }, + ), + )) + } + + #[wasm_bindgen(js_name = "toBytes")] + pub fn to_bytes(&self) -> WasmDppResult> { + Ok(self.0.serialize_to_bytes()?) + } + + #[wasm_bindgen(js_name = "toHex")] + pub fn to_hex(&self) -> WasmDppResult { + let bytes = self.0.serialize_to_bytes()?; + Ok(encode(bytes.as_slice(), Hex)) + } + + #[wasm_bindgen(js_name = "toBase64")] + pub fn to_base64(&self) -> WasmDppResult { + let bytes = self.0.serialize_to_bytes()?; + Ok(encode(bytes.as_slice(), Base64)) + } + + #[wasm_bindgen(js_name = "fromBytes")] + pub fn from_bytes( + bytes: Vec, + ) -> WasmDppResult { + let rs_transition = + IdentityTopUpFromAddressesTransition::deserialize_from_bytes(bytes.as_slice())?; + Ok(IdentityTopUpFromAddressesTransitionWasm(rs_transition)) + } + + #[wasm_bindgen(js_name = "fromHex")] + pub fn from_hex( + hex: String, + ) -> WasmDppResult { + let bytes = + decode(hex.as_str(), Hex).map_err(|e| WasmDppError::serialization(e.to_string()))?; + Self::from_bytes(bytes) + } + + #[wasm_bindgen(js_name = "fromBase64")] + pub fn from_base64( + base64: String, + ) -> WasmDppResult { + let bytes = decode(base64.as_str(), Base64) + .map_err(|e| WasmDppError::serialization(e.to_string()))?; + Self::from_bytes(bytes) + } + + #[wasm_bindgen(getter = "identityId")] + pub fn identity_id(&self) -> IdentifierWasm { + match &self.0 { + IdentityTopUpFromAddressesTransition::V0(v0) => v0.identity_id.into(), + } + } + + #[wasm_bindgen(setter = "identityId")] + pub fn set_identity_id( + &mut self, + #[wasm_bindgen(js_name = "identityId")] identity_id: IdentifierLikeJs, + ) -> WasmDppResult<()> { + let id: IdentifierWasm = identity_id.try_into()?; + match &mut self.0 { + IdentityTopUpFromAddressesTransition::V0(v0) => { + v0.identity_id = id.into(); + } + } + Ok(()) + } + + #[wasm_bindgen(getter = "inputs")] + pub fn inputs(&self) -> Vec { + let inputs_map = match &self.0 { + IdentityTopUpFromAddressesTransition::V0(v0) => &v0.inputs, + }; + inputs_map + .iter() + .map(|(address, (nonce, amount))| { + PlatformAddressInputWasm::new(*address, *nonce, *amount) + }) + .collect() + } + + #[wasm_bindgen(setter = "inputs")] + pub fn set_inputs(&mut self, inputs: Vec) { + let inputs_map = inputs.into_iter().map(|i| i.into_inner()).collect(); + match &mut self.0 { + IdentityTopUpFromAddressesTransition::V0(v0) => { + v0.inputs = inputs_map; + } + } + } + + #[wasm_bindgen(getter = "output")] + pub fn output(&self) -> Option { + let output = match &self.0 { + IdentityTopUpFromAddressesTransition::V0(v0) => &v0.output, + }; + output.map(|(address, credits)| PlatformAddressOutputWasm::new(address, credits)) + } + + #[wasm_bindgen(setter = "output")] + pub fn set_output(&mut self, output: JsValue) -> WasmDppResult<()> { + let new_output = if output.is_undefined() || output.is_null() { + None + } else { + let output_wasm: PlatformAddressOutputWasm = + serde_wasm_bindgen::from_value(output) + .map_err(|e| WasmDppError::invalid_argument(e.to_string()))?; + Some(output_wasm.into_inner()) + }; + match &mut self.0 { + IdentityTopUpFromAddressesTransition::V0(v0) => { + v0.output = new_output; + } + } + Ok(()) + } + + #[wasm_bindgen(getter = "userFeeIncrease")] + pub fn user_fee_increase(&self) -> u16 { + match &self.0 { + IdentityTopUpFromAddressesTransition::V0(v0) => v0.user_fee_increase, + } + } + + #[wasm_bindgen(setter = "userFeeIncrease")] + pub fn set_user_fee_increase( + &mut self, + #[wasm_bindgen(js_name = "userFeeIncrease")] amount: &js_sys::Number, + ) -> WasmDppResult<()> { + match &mut self.0 { + IdentityTopUpFromAddressesTransition::V0(v0) => { + v0.user_fee_increase = try_to_u16(amount, "userFeeIncrease")?; + } + } + Ok(()) + } + + #[wasm_bindgen(js_name = "toStateTransition")] + pub fn to_state_transition(&self) -> StateTransitionWasm { + StateTransitionWasm::from(StateTransition::IdentityTopUpFromAddresses(self.0.clone())) + } + + #[wasm_bindgen(js_name = "fromStateTransition")] + pub fn from_state_transition( + st: &StateTransitionWasm, + ) -> WasmDppResult { + let rs_st: StateTransition = st.clone().into(); + match rs_st { + StateTransition::IdentityTopUpFromAddresses(st) => { + Ok(IdentityTopUpFromAddressesTransitionWasm(st)) + } + _ => Err(WasmDppError::invalid_argument( + "Invalid state transition type", + )), + } + } +} + +impl_wasm_conversions!( + IdentityTopUpFromAddressesTransitionWasm, + IdentityTopUpFromAddressesTransition, + IdentityTopUpFromAddressesTransitionObjectJs, + IdentityTopUpFromAddressesTransitionJSONJs +); + +impl_wasm_type_info!( + IdentityTopUpFromAddressesTransitionWasm, + IdentityTopUpFromAddressesTransition +); diff --git a/packages/wasm-dpp2/src/platform_address/transitions/mod.rs b/packages/wasm-dpp2/src/platform_address/transitions/mod.rs new file mode 100644 index 00000000000..3232116c968 --- /dev/null +++ b/packages/wasm-dpp2/src/platform_address/transitions/mod.rs @@ -0,0 +1,13 @@ +pub mod address_credit_withdrawal_transition; +pub mod address_funding_from_asset_lock_transition; +pub mod address_funds_transfer_transition; +pub mod identity_create_from_addresses_transition; +pub mod identity_credit_transfer_to_addresses_transition; +pub mod identity_top_up_from_addresses_transition; + +pub use address_credit_withdrawal_transition::AddressCreditWithdrawalTransitionWasm; +pub use address_funding_from_asset_lock_transition::AddressFundingFromAssetLockTransitionWasm; +pub use address_funds_transfer_transsition::AddressFundsTransferTransitionWasm; +pub use identity_create_from_addresses_transition::IdentityCreateFromAddressesTransitionWasm; +pub use identity_credit_transfer_to_addresses_transition::IdentityCreditTransferToAddressesTransitionWasm; +pub use identity_top_up_from_addresses_transition::IdentityTopUpFromAddressesTransitionWasm; diff --git a/packages/wasm-dpp2/tests/unit/AddressCreditWithdrawalTransition.spec.ts b/packages/wasm-dpp2/tests/unit/AddressCreditWithdrawalTransition.spec.ts new file mode 100644 index 00000000000..abdf99d1c06 --- /dev/null +++ b/packages/wasm-dpp2/tests/unit/AddressCreditWithdrawalTransition.spec.ts @@ -0,0 +1,208 @@ +import { expect } from './helpers/chai.ts'; +import { initWasm, wasm } from '../../dist/dpp.compressed.js'; + +before(async () => { + await initWasm(); +}); + +describe('AddressCreditWithdrawalTransition', () => { + const addr1Bytes = new Uint8Array([ + 0x00, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + ]); + const addr2Bytes = new Uint8Array([ + 0x00, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, + ]); + + function createTransition() { + const inputAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const outputAddr = wasm.PlatformAddress.fromBytes(addr2Bytes); + const script = wasm.CoreScript.fromP2PKH([ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + ]); + + const input = new wasm.PlatformAddressInput(inputAddr, 0, BigInt(100000)); + const output = new wasm.PlatformAddressOutput(outputAddr, BigInt(90000)); + + return new wasm.AddressCreditWithdrawalTransition({ + inputs: [input], + output: output, + outputScript: script, + pooling: 'never', + coreFeePerByte: 1, + }); + } + + describe('constructor()', () => { + it('should create transition', () => { + const transition = createTransition(); + expect(transition).to.exist(); + expect(transition).to.be.an.instanceof(wasm.AddressCreditWithdrawalTransition); + }); + + it('should create transition without output', () => { + const inputAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const script = wasm.CoreScript.fromP2PKH([ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + ]); + const input = new wasm.PlatformAddressInput(inputAddr, 0, BigInt(100000)); + + const transition = new wasm.AddressCreditWithdrawalTransition({ + inputs: [input], + outputScript: script, + pooling: 'never', + coreFeePerByte: 1, + }); + + expect(transition).to.exist(); + }); + + it('should create transition with user fee increase', () => { + const inputAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const script = wasm.CoreScript.fromP2PKH([ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + ]); + const input = new wasm.PlatformAddressInput(inputAddr, 0, BigInt(100000)); + + const transition = new wasm.AddressCreditWithdrawalTransition({ + inputs: [input], + outputScript: script, + pooling: 'never', + coreFeePerByte: 1, + userFeeIncrease: 100, + }); + + expect(transition.userFeeIncrease).to.equal(100); + }); + }); + + describe('toBytes() / fromBytes()', () => { + it('should round-trip via bytes', () => { + const transition = createTransition(); + const bytes = transition.toBytes(); + const restored = wasm.AddressCreditWithdrawalTransition.fromBytes(bytes); + expect(Buffer.from(restored.toBytes())).to.deep.equal(Buffer.from(bytes)); + }); + }); + + describe('toBase64() / fromBase64()', () => { + it('should round-trip via base64', () => { + const transition = createTransition(); + const base64 = transition.toBase64(); + const bytes = transition.toBytes(); + expect(Buffer.from(base64, 'base64')).to.deep.equal(Buffer.from(bytes)); + + const restored = wasm.AddressCreditWithdrawalTransition.fromBase64(base64); + expect(Buffer.from(restored.toBytes())).to.deep.equal(Buffer.from(bytes)); + }); + }); + + describe('inputs', () => { + it('should return inputs array', () => { + const transition = createTransition(); + const inputs = transition.inputs; + expect(inputs).to.be.an('array'); + expect(inputs).to.have.lengthOf(1); + expect(inputs[0].nonce).to.equal(0); + expect(inputs[0].amount).to.equal(BigInt(100000)); + }); + + it('should set inputs', () => { + const transition = createTransition(); + const newAddr = wasm.PlatformAddress.fromBytes(addr2Bytes); + const newInput = new wasm.PlatformAddressInput(newAddr, 5, BigInt(50000)); + + transition.inputs = [newInput]; + const inputs = transition.inputs; + expect(inputs).to.have.lengthOf(1); + expect(inputs[0].nonce).to.equal(5); + }); + }); + + describe('output', () => { + it('should return output', () => { + const transition = createTransition(); + const output = transition.output; + expect(output).to.exist(); + expect(output.amount).to.equal(BigInt(90000)); + }); + + it('should set output to undefined', () => { + const transition = createTransition(); + transition.output = undefined; + expect(transition.output).to.be.undefined(); + }); + }); + + describe('outputScript', () => { + it('should return outputScript', () => { + const transition = createTransition(); + expect(transition.outputScript).to.exist(); + expect(transition.outputScript).to.be.an.instanceof(wasm.CoreScript); + }); + + it('should set outputScript', () => { + const transition = createTransition(); + const script2 = wasm.CoreScript.fromP2PKH([ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + ]); + + const origScript = transition.outputScript.toString(); + transition.outputScript = script2; + expect(transition.outputScript.toString()).to.not.equal(origScript); + expect(transition.outputScript.toString()).to.equal(script2.toString()); + }); + }); + + describe('pooling', () => { + it('should return pooling', () => { + const transition = createTransition(); + expect(transition.pooling).to.equal('Never'); + }); + + it('should set pooling', () => { + const transition = createTransition(); + transition.pooling = 'Standard'; + expect(transition.pooling).to.equal('Standard'); + }); + }); + + describe('coreFeePerByte', () => { + it('should return coreFeePerByte', () => { + const transition = createTransition(); + expect(transition.coreFeePerByte).to.equal(1); + }); + + it('should set coreFeePerByte', () => { + const transition = createTransition(); + transition.coreFeePerByte = 10; + expect(transition.coreFeePerByte).to.equal(10); + }); + }); + + describe('userFeeIncrease', () => { + it('should return default userFeeIncrease', () => { + const transition = createTransition(); + expect(transition.userFeeIncrease).to.equal(0); + }); + + it('should set userFeeIncrease', () => { + const transition = createTransition(); + transition.userFeeIncrease = 42; + expect(transition.userFeeIncrease).to.equal(42); + }); + }); + + describe('toStateTransition() / fromStateTransition()', () => { + it('should convert to and from StateTransition', () => { + const transition = createTransition(); + const st = transition.toStateTransition(); + expect(st).to.exist(); + + const restored = + wasm.AddressCreditWithdrawalTransition.fromStateTransition(st); + expect(Buffer.from(restored.toBytes())).to.deep.equal( + Buffer.from(transition.toBytes()), + ); + }); + }); +}); diff --git a/packages/wasm-dpp2/tests/unit/AddressFundingFromAssetLockTransition.spec.ts b/packages/wasm-dpp2/tests/unit/AddressFundingFromAssetLockTransition.spec.ts new file mode 100644 index 00000000000..a2d8288ddf2 --- /dev/null +++ b/packages/wasm-dpp2/tests/unit/AddressFundingFromAssetLockTransition.spec.ts @@ -0,0 +1,201 @@ +import { expect } from './helpers/chai.ts'; +import { initWasm, wasm } from '../../dist/dpp.compressed.js'; +import { instantLockBytes, transactionBytes } from './mocks/Locks/index.js'; + +before(async () => { + await initWasm(); +}); + +describe('AddressFundingFromAssetLockTransition', () => { + const addr1Bytes = new Uint8Array([ + 0x00, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + ]); + const addr2Bytes = new Uint8Array([ + 0x00, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, + ]); + + function createAssetLockProof() { + return wasm.AssetLockProof.createInstantAssetLockProof( + instantLockBytes, + transactionBytes, + 0, + ); + } + + function createTransition() { + const inputAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const outputAddr = wasm.PlatformAddress.fromBytes(addr2Bytes); + + const input = new wasm.PlatformAddressInput(inputAddr, 0, BigInt(100000)); + // For asset lock funding, output amount can be optional (undefined = remainder) + const output = new wasm.PlatformAddressOutput(outputAddr); + + return new wasm.AddressFundingFromAssetLockTransition({ + assetLockProof: createAssetLockProof(), + inputs: [input], + outputs: [output], + }); + } + + describe('constructor()', () => { + it('should create transition with asset lock proof', () => { + const transition = createTransition(); + expect(transition).to.exist(); + expect(transition).to.be.an.instanceof(wasm.AddressFundingFromAssetLockTransition); + }); + + it('should create transition with explicit output amounts', () => { + const inputAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const outputAddr = wasm.PlatformAddress.fromBytes(addr2Bytes); + + const input = new wasm.PlatformAddressInput(inputAddr, 0, BigInt(50000)); + const output = new wasm.PlatformAddressOutput(outputAddr, BigInt(40000)); + + const transition = new wasm.AddressFundingFromAssetLockTransition({ + assetLockProof: createAssetLockProof(), + inputs: [input], + outputs: [output], + }); + + expect(transition).to.exist(); + }); + + it('should create transition with user fee increase', () => { + const inputAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const outputAddr = wasm.PlatformAddress.fromBytes(addr2Bytes); + + const input = new wasm.PlatformAddressInput(inputAddr, 0, BigInt(100000)); + const output = new wasm.PlatformAddressOutput(outputAddr); + + const transition = new wasm.AddressFundingFromAssetLockTransition({ + assetLockProof: createAssetLockProof(), + inputs: [input], + outputs: [output], + userFeeIncrease: 100, + }); + + expect(transition.userFeeIncrease).to.equal(100); + }); + }); + + describe('toBytes() / fromBytes()', () => { + it('should round-trip via bytes', () => { + const transition = createTransition(); + const bytes = transition.toBytes(); + const restored = wasm.AddressFundingFromAssetLockTransition.fromBytes(bytes); + expect(Buffer.from(restored.toBytes())).to.deep.equal(Buffer.from(bytes)); + }); + }); + + describe('toBase64() / fromBase64()', () => { + it('should round-trip via base64', () => { + const transition = createTransition(); + const base64 = transition.toBase64(); + const bytes = transition.toBytes(); + expect(Buffer.from(base64, 'base64')).to.deep.equal(Buffer.from(bytes)); + + const restored = wasm.AddressFundingFromAssetLockTransition.fromBase64(base64); + expect(Buffer.from(restored.toBytes())).to.deep.equal(Buffer.from(bytes)); + }); + }); + + describe('toHex() / fromHex()', () => { + it('should round-trip via hex', () => { + const transition = createTransition(); + const hex = transition.toHex(); + const bytes = transition.toBytes(); + + const restored = wasm.AddressFundingFromAssetLockTransition.fromHex(hex); + expect(Buffer.from(restored.toBytes())).to.deep.equal(Buffer.from(bytes)); + }); + }); + + describe('assetLockProof', () => { + it('should return asset lock proof', () => { + const transition = createTransition(); + const proof = transition.assetLockProof; + expect(proof).to.exist(); + expect(proof.lockTypeName).to.equal('Instant'); + }); + + it('should set asset lock proof', () => { + const transition = createTransition(); + const outpoint = new wasm.OutPoint( + 'e8b43025641eea4fd21190f01bd870ef90f1a8b199d8fc3376c5b62c0b1a179d', + 1, + ); + const chainProof = wasm.AssetLockProof.createChainAssetLockProof(11, outpoint); + + transition.assetLockProof = chainProof; + expect(transition.assetLockProof.lockTypeName).to.equal('Chain'); + }); + }); + + describe('inputs', () => { + it('should return inputs array', () => { + const transition = createTransition(); + const inputs = transition.inputs; + expect(inputs).to.be.an('array'); + expect(inputs).to.have.lengthOf(1); + expect(inputs[0].nonce).to.equal(0); + expect(inputs[0].amount).to.equal(BigInt(100000)); + }); + + it('should set inputs', () => { + const transition = createTransition(); + const newAddr = wasm.PlatformAddress.fromBytes(addr2Bytes); + const newInput = new wasm.PlatformAddressInput(newAddr, 3, BigInt(50000)); + + transition.inputs = [newInput]; + const inputs = transition.inputs; + expect(inputs).to.have.lengthOf(1); + expect(inputs[0].nonce).to.equal(3); + }); + }); + + describe('outputs', () => { + it('should return outputs array', () => { + const transition = createTransition(); + const outputs = transition.outputs; + expect(outputs).to.be.an('array'); + expect(outputs).to.have.lengthOf(1); + }); + + it('should set outputs', () => { + const transition = createTransition(); + const newAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const newOutput = new wasm.PlatformAddressOutput(newAddr, BigInt(50000)); + + transition.outputs = [newOutput]; + const outputs = transition.outputs; + expect(outputs).to.have.lengthOf(1); + }); + }); + + describe('userFeeIncrease', () => { + it('should return default userFeeIncrease', () => { + const transition = createTransition(); + expect(transition.userFeeIncrease).to.equal(0); + }); + + it('should set userFeeIncrease', () => { + const transition = createTransition(); + transition.userFeeIncrease = 42; + expect(transition.userFeeIncrease).to.equal(42); + }); + }); + + describe('toStateTransition() / fromStateTransition()', () => { + it('should convert to and from StateTransition', () => { + const transition = createTransition(); + const st = transition.toStateTransition(); + expect(st).to.exist(); + + const restored = + wasm.AddressFundingFromAssetLockTransition.fromStateTransition(st); + expect(Buffer.from(restored.toBytes())).to.deep.equal( + Buffer.from(transition.toBytes()), + ); + }); + }); +}); diff --git a/packages/wasm-dpp2/tests/unit/AddressFundsTransfer.spec.ts b/packages/wasm-dpp2/tests/unit/AddressFundsTransfer.spec.ts index e510d44623c..376071fd274 100644 --- a/packages/wasm-dpp2/tests/unit/AddressFundsTransfer.spec.ts +++ b/packages/wasm-dpp2/tests/unit/AddressFundsTransfer.spec.ts @@ -39,8 +39,10 @@ describe('FeeStrategyStep', () => { }); }); -// TODO: Implement AddressFundsTransferTransition in wasm-dpp2 -describe.skip('AddressFundsTransferTransition', () => { +// NOTE: AddressFundsTransferTransition constructor-based tests are in +// AddressFundsTransferTransition.spec.ts. The .build() API below requires +// signing which is a higher-level feature not yet available. +describe.skip('AddressFundsTransferTransition (.build API)', () => { // Valid test private key const testPrivateKeyHex = 'c9d9d0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfd'; const testPrivateKeyHex2 = 'a9d9d0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfd'; diff --git a/packages/wasm-dpp2/tests/unit/AddressFundsTransferTransition.spec.ts b/packages/wasm-dpp2/tests/unit/AddressFundsTransferTransition.spec.ts new file mode 100644 index 00000000000..747a378a1d4 --- /dev/null +++ b/packages/wasm-dpp2/tests/unit/AddressFundsTransferTransition.spec.ts @@ -0,0 +1,171 @@ +import { expect } from './helpers/chai.ts'; +import { initWasm, wasm } from '../../dist/dpp.compressed.js'; + +before(async () => { + await initWasm(); +}); + +describe('AddressFundsTransferTransition', () => { + const addr1Bytes = new Uint8Array([ + 0x00, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + ]); + const addr2Bytes = new Uint8Array([ + 0x00, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, + ]); + + function createTransition() { + const inputAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const outputAddr = wasm.PlatformAddress.fromBytes(addr2Bytes); + + const input = new wasm.PlatformAddressInput(inputAddr, 0, BigInt(100000)); + const output = new wasm.PlatformAddressOutput(outputAddr, BigInt(90000)); + + return new wasm.AddressFundsTransferTransition({ + inputs: [input], + outputs: [output], + }); + } + + describe('constructor()', () => { + it('should create transition with single input and output', () => { + const transition = createTransition(); + expect(transition).to.exist(); + expect(transition).to.be.an.instanceof(wasm.AddressFundsTransferTransition); + }); + + it('should create transition with custom fee strategy', () => { + const inputAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const outputAddr = wasm.PlatformAddress.fromBytes(addr2Bytes); + + const input = new wasm.PlatformAddressInput(inputAddr, 0, BigInt(100000)); + const output = new wasm.PlatformAddressOutput(outputAddr, BigInt(100000)); + + const transition = new wasm.AddressFundsTransferTransition({ + inputs: [input], + outputs: [output], + feeStrategy: [wasm.FeeStrategyStep.reduceOutput(0)], + }); + + expect(transition).to.exist(); + }); + + it('should create transition with user fee increase', () => { + const inputAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const outputAddr = wasm.PlatformAddress.fromBytes(addr2Bytes); + + const input = new wasm.PlatformAddressInput(inputAddr, 0, BigInt(100000)); + const output = new wasm.PlatformAddressOutput(outputAddr, BigInt(90000)); + + const transition = new wasm.AddressFundsTransferTransition({ + inputs: [input], + outputs: [output], + userFeeIncrease: 100, + }); + + expect(transition).to.exist(); + expect(transition.userFeeIncrease).to.equal(100); + }); + }); + + describe('toBytes() / fromBytes()', () => { + it('should round-trip via bytes', () => { + const transition = createTransition(); + const bytes = transition.toBytes(); + const restored = wasm.AddressFundsTransferTransition.fromBytes(bytes); + expect(Buffer.from(restored.toBytes())).to.deep.equal(Buffer.from(bytes)); + }); + }); + + describe('toBase64() / fromBase64()', () => { + it('should round-trip via base64', () => { + const transition = createTransition(); + const base64 = transition.toBase64(); + const bytes = transition.toBytes(); + expect(Buffer.from(base64, 'base64')).to.deep.equal(Buffer.from(bytes)); + + const restored = wasm.AddressFundsTransferTransition.fromBase64(base64); + expect(Buffer.from(restored.toBytes())).to.deep.equal(Buffer.from(bytes)); + }); + }); + + describe('toHex() / fromHex()', () => { + it('should round-trip via hex', () => { + const transition = createTransition(); + const hex = transition.toHex(); + const bytes = transition.toBytes(); + + const restored = wasm.AddressFundsTransferTransition.fromHex(hex); + expect(Buffer.from(restored.toBytes())).to.deep.equal(Buffer.from(bytes)); + }); + }); + + describe('inputs', () => { + it('should return inputs array', () => { + const transition = createTransition(); + const inputs = transition.inputs; + expect(inputs).to.be.an('array'); + expect(inputs).to.have.lengthOf(1); + expect(inputs[0].nonce).to.equal(0); + expect(inputs[0].amount).to.equal(BigInt(100000)); + }); + + it('should set inputs', () => { + const transition = createTransition(); + const newAddr = wasm.PlatformAddress.fromBytes(addr2Bytes); + const newInput = new wasm.PlatformAddressInput(newAddr, 5, BigInt(50000)); + + transition.inputs = [newInput]; + const inputs = transition.inputs; + expect(inputs).to.have.lengthOf(1); + expect(inputs[0].nonce).to.equal(5); + expect(inputs[0].amount).to.equal(BigInt(50000)); + }); + }); + + describe('outputs', () => { + it('should return outputs array', () => { + const transition = createTransition(); + const outputs = transition.outputs; + expect(outputs).to.be.an('array'); + expect(outputs).to.have.lengthOf(1); + expect(outputs[0].amount).to.equal(BigInt(90000)); + }); + + it('should set outputs', () => { + const transition = createTransition(); + const newAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const newOutput = new wasm.PlatformAddressOutput(newAddr, BigInt(80000)); + + transition.outputs = [newOutput]; + const outputs = transition.outputs; + expect(outputs).to.have.lengthOf(1); + expect(outputs[0].amount).to.equal(BigInt(80000)); + }); + }); + + describe('userFeeIncrease', () => { + it('should return default userFeeIncrease', () => { + const transition = createTransition(); + expect(transition.userFeeIncrease).to.equal(0); + }); + + it('should set userFeeIncrease', () => { + const transition = createTransition(); + transition.userFeeIncrease = 42; + expect(transition.userFeeIncrease).to.equal(42); + }); + }); + + describe('toStateTransition() / fromStateTransition()', () => { + it('should convert to and from StateTransition', () => { + const transition = createTransition(); + const st = transition.toStateTransition(); + expect(st).to.exist(); + + const restored = wasm.AddressFundsTransferTransition.fromStateTransition(st); + expect(Buffer.from(restored.toBytes())).to.deep.equal( + Buffer.from(transition.toBytes()), + ); + }); + }); +}); diff --git a/packages/wasm-dpp2/tests/unit/IdentityCreateFromAddressesTransition.spec.ts b/packages/wasm-dpp2/tests/unit/IdentityCreateFromAddressesTransition.spec.ts new file mode 100644 index 00000000000..676dfde11d9 --- /dev/null +++ b/packages/wasm-dpp2/tests/unit/IdentityCreateFromAddressesTransition.spec.ts @@ -0,0 +1,187 @@ +import { expect } from './helpers/chai.ts'; +import { initWasm, wasm } from '../../dist/dpp.compressed.js'; + +before(async () => { + await initWasm(); +}); + +describe('IdentityCreateFromAddressesTransition', () => { + const addr1Bytes = new Uint8Array([ + 0x00, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + ]); + const addr2Bytes = new Uint8Array([ + 0x00, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, + ]); + + function createPublicKey() { + return new wasm.IdentityPublicKeyInCreation({ + keyId: 0, + purpose: 'AUTHENTICATION', + securityLevel: 'master', + keyType: 'ECDSA_SECP256K1', + isReadOnly: false, + data: Buffer.from( + '0333d5cf3674001d2f64c55617b7b11a2e8fc62aab09708b49355e30c7205bdb2e', + 'hex', + ), + signature: [], + }); + } + + function createTransition() { + const inputAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const outputAddr = wasm.PlatformAddress.fromBytes(addr2Bytes); + + const input = new wasm.PlatformAddressInput(inputAddr, 0, BigInt(100000)); + const output = new wasm.PlatformAddressOutput(outputAddr, BigInt(90000)); + const pk = createPublicKey(); + + return new wasm.IdentityCreateFromAddressesTransition({ + publicKeys: [pk], + inputs: [input], + output: output, + }); + } + + describe('constructor()', () => { + it('should create transition with public keys', () => { + const transition = createTransition(); + expect(transition).to.exist(); + expect(transition).to.be.an.instanceof(wasm.IdentityCreateFromAddressesTransition); + }); + + it('should create transition without output', () => { + const inputAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const input = new wasm.PlatformAddressInput(inputAddr, 0, BigInt(100000)); + const pk = createPublicKey(); + + const transition = new wasm.IdentityCreateFromAddressesTransition({ + publicKeys: [pk], + inputs: [input], + }); + + expect(transition).to.exist(); + }); + + it('should create transition with user fee increase', () => { + const inputAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const input = new wasm.PlatformAddressInput(inputAddr, 0, BigInt(100000)); + const pk = createPublicKey(); + + const transition = new wasm.IdentityCreateFromAddressesTransition({ + publicKeys: [pk], + inputs: [input], + userFeeIncrease: 100, + }); + + expect(transition.userFeeIncrease).to.equal(100); + }); + }); + + describe('toBytes() / fromBytes()', () => { + it('should round-trip via bytes', () => { + const transition = createTransition(); + const bytes = transition.toBytes(); + const restored = wasm.IdentityCreateFromAddressesTransition.fromBytes(bytes); + expect(Buffer.from(restored.toBytes())).to.deep.equal(Buffer.from(bytes)); + }); + }); + + describe('toBase64() / fromBase64()', () => { + it('should round-trip via base64', () => { + const transition = createTransition(); + const base64 = transition.toBase64(); + const bytes = transition.toBytes(); + expect(Buffer.from(base64, 'base64')).to.deep.equal(Buffer.from(bytes)); + + const restored = wasm.IdentityCreateFromAddressesTransition.fromBase64(base64); + expect(Buffer.from(restored.toBytes())).to.deep.equal(Buffer.from(bytes)); + }); + }); + + describe('publicKeys', () => { + it('should return public keys', () => { + const transition = createTransition(); + const keys = transition.publicKeys; + expect(keys).to.be.an('array'); + expect(keys).to.have.lengthOf(1); + expect(keys[0].keyId).to.equal(0); + expect(keys[0].purpose).to.equal('AUTHENTICATION'); + }); + + it('should set public keys', () => { + const transition = createTransition(); + const pk = createPublicKey(); + pk.keyId = 5; + + transition.publicKeys = [pk]; + const keys = transition.publicKeys; + expect(keys).to.have.lengthOf(1); + expect(keys[0].keyId).to.equal(5); + }); + }); + + describe('inputs', () => { + it('should return inputs array', () => { + const transition = createTransition(); + const inputs = transition.inputs; + expect(inputs).to.be.an('array'); + expect(inputs).to.have.lengthOf(1); + expect(inputs[0].nonce).to.equal(0); + expect(inputs[0].amount).to.equal(BigInt(100000)); + }); + + it('should set inputs', () => { + const transition = createTransition(); + const newAddr = wasm.PlatformAddress.fromBytes(addr2Bytes); + const newInput = new wasm.PlatformAddressInput(newAddr, 3, BigInt(50000)); + + transition.inputs = [newInput]; + const inputs = transition.inputs; + expect(inputs).to.have.lengthOf(1); + expect(inputs[0].nonce).to.equal(3); + }); + }); + + describe('output', () => { + it('should return output', () => { + const transition = createTransition(); + const output = transition.output; + expect(output).to.exist(); + expect(output.amount).to.equal(BigInt(90000)); + }); + + it('should set output to undefined', () => { + const transition = createTransition(); + transition.output = undefined; + expect(transition.output).to.be.undefined(); + }); + }); + + describe('userFeeIncrease', () => { + it('should return default userFeeIncrease', () => { + const transition = createTransition(); + expect(transition.userFeeIncrease).to.equal(0); + }); + + it('should set userFeeIncrease', () => { + const transition = createTransition(); + transition.userFeeIncrease = 42; + expect(transition.userFeeIncrease).to.equal(42); + }); + }); + + describe('toStateTransition() / fromStateTransition()', () => { + it('should convert to and from StateTransition', () => { + const transition = createTransition(); + const st = transition.toStateTransition(); + expect(st).to.exist(); + + const restored = + wasm.IdentityCreateFromAddressesTransition.fromStateTransition(st); + expect(Buffer.from(restored.toBytes())).to.deep.equal( + Buffer.from(transition.toBytes()), + ); + }); + }); +}); diff --git a/packages/wasm-dpp2/tests/unit/IdentityCreditTransferToAddresses.spec.ts b/packages/wasm-dpp2/tests/unit/IdentityCreditTransferToAddresses.spec.ts new file mode 100644 index 00000000000..fad144990f2 --- /dev/null +++ b/packages/wasm-dpp2/tests/unit/IdentityCreditTransferToAddresses.spec.ts @@ -0,0 +1,198 @@ +import { expect } from './helpers/chai.ts'; +import { initWasm, wasm } from '../../dist/dpp.compressed.js'; + +before(async () => { + await initWasm(); +}); + +describe('IdentityCreditTransferToAddresses', () => { + const addr1Bytes = new Uint8Array([ + 0x00, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, + ]); + + function createTransition() { + const outputAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const output = new wasm.PlatformAddressOutput(outputAddr, BigInt(90000)); + + return new wasm.IdentityCreditTransferToAddresses({ + recipientAddresses: [output], + senderId: '11111111111111111111111111111111', + nonce: BigInt(1), + }); + } + + describe('constructor()', () => { + it('should create transition with string senderId', () => { + const transition = createTransition(); + expect(transition).to.exist(); + expect(transition).to.be.an.instanceof(wasm.IdentityCreditTransferToAddresses); + }); + + it('should create transition with Identifier senderId', () => { + const sender = new wasm.Identifier('11111111111111111111111111111111'); + const outputAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const output = new wasm.PlatformAddressOutput(outputAddr, BigInt(90000)); + + const transition = new wasm.IdentityCreditTransferToAddresses({ + recipientAddresses: [output], + senderId: sender, + nonce: BigInt(1), + }); + + expect(transition).to.exist(); + }); + + it('should create transition with user fee increase', () => { + const outputAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const output = new wasm.PlatformAddressOutput(outputAddr, BigInt(90000)); + + const transition = new wasm.IdentityCreditTransferToAddresses({ + recipientAddresses: [output], + senderId: '11111111111111111111111111111111', + nonce: BigInt(1), + userFeeIncrease: 50, + }); + + expect(transition.userFeeIncrease).to.equal(50); + }); + }); + + describe('toBytes() / fromBytes()', () => { + it('should round-trip via bytes', () => { + const transition = createTransition(); + const bytes = transition.toBytes(); + const restored = wasm.IdentityCreditTransferToAddresses.fromBytes(bytes); + expect(Buffer.from(restored.toBytes())).to.deep.equal(Buffer.from(bytes)); + }); + }); + + describe('toBase64() / fromBase64()', () => { + it('should round-trip via base64', () => { + const transition = createTransition(); + const base64 = transition.toBase64(); + const bytes = transition.toBytes(); + expect(Buffer.from(base64, 'base64')).to.deep.equal(Buffer.from(bytes)); + + const restored = wasm.IdentityCreditTransferToAddresses.fromBase64(base64); + expect(Buffer.from(restored.toBytes())).to.deep.equal(Buffer.from(bytes)); + }); + }); + + describe('toHex() / fromHex()', () => { + it('should round-trip via hex', () => { + const transition = createTransition(); + const hex = transition.toHex(); + const bytes = transition.toBytes(); + + const restored = wasm.IdentityCreditTransferToAddresses.fromHex(hex); + expect(Buffer.from(restored.toBytes())).to.deep.equal(Buffer.from(bytes)); + }); + }); + + describe('recipientAddresses', () => { + it('should return recipient addresses', () => { + const transition = createTransition(); + const recipients = transition.recipientAddresses; + expect(recipients).to.be.an('array'); + expect(recipients).to.have.lengthOf(1); + expect(recipients[0].amount).to.equal(BigInt(90000)); + }); + + it('should set recipient addresses', () => { + const transition = createTransition(); + const newAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const newOutput = new wasm.PlatformAddressOutput(newAddr, BigInt(50000)); + + transition.recipientAddresses = [newOutput]; + const recipients = transition.recipientAddresses; + expect(recipients).to.have.lengthOf(1); + expect(recipients[0].amount).to.equal(BigInt(50000)); + }); + }); + + describe('senderId', () => { + it('should return senderId', () => { + const transition = createTransition(); + expect(transition.senderId.toBase58()).to.equal('11111111111111111111111111111111'); + }); + + it('should set senderId with Identifier', () => { + const transition = createTransition(); + const newSender = new wasm.Identifier('GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec'); + + transition.senderId = newSender; + expect(transition.senderId.toBase58()).to.equal('GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec'); + }); + + it('should set senderId with string', () => { + const transition = createTransition(); + transition.senderId = 'GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec'; + expect(transition.senderId.toBase58()).to.equal('GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec'); + }); + }); + + describe('nonce', () => { + it('should return nonce', () => { + const transition = createTransition(); + expect(transition.nonce).to.equal(BigInt(1)); + }); + + it('should set nonce', () => { + const transition = createTransition(); + transition.nonce = BigInt(999); + expect(transition.nonce).to.equal(BigInt(999)); + }); + }); + + describe('signature', () => { + it('should return empty signature by default', () => { + const transition = createTransition(); + expect(transition.signature).to.deep.equal(Uint8Array.from([])); + }); + + it('should set signature', () => { + const transition = createTransition(); + transition.signature = [1, 2, 3]; + expect(transition.signature).to.deep.equal(Uint8Array.from([1, 2, 3])); + }); + }); + + describe('signaturePublicKeyId', () => { + it('should return default signaturePublicKeyId', () => { + const transition = createTransition(); + expect(transition.signaturePublicKeyId).to.equal(0); + }); + + it('should set signaturePublicKeyId', () => { + const transition = createTransition(); + transition.signaturePublicKeyId = 5; + expect(transition.signaturePublicKeyId).to.equal(5); + }); + }); + + describe('userFeeIncrease', () => { + it('should return default userFeeIncrease', () => { + const transition = createTransition(); + expect(transition.userFeeIncrease).to.equal(0); + }); + + it('should set userFeeIncrease', () => { + const transition = createTransition(); + transition.userFeeIncrease = 42; + expect(transition.userFeeIncrease).to.equal(42); + }); + }); + + describe('toStateTransition() / fromStateTransition()', () => { + it('should convert to and from StateTransition', () => { + const transition = createTransition(); + const st = transition.toStateTransition(); + expect(st).to.exist(); + + const restored = wasm.IdentityCreditTransferToAddresses.fromStateTransition(st); + expect(Buffer.from(restored.toBytes())).to.deep.equal( + Buffer.from(transition.toBytes()), + ); + }); + }); +}); diff --git a/packages/wasm-dpp2/tests/unit/IdentityTopUpFromAddressesTransition.spec.ts b/packages/wasm-dpp2/tests/unit/IdentityTopUpFromAddressesTransition.spec.ts new file mode 100644 index 00000000000..be51d704ce1 --- /dev/null +++ b/packages/wasm-dpp2/tests/unit/IdentityTopUpFromAddressesTransition.spec.ts @@ -0,0 +1,180 @@ +import { expect } from './helpers/chai.ts'; +import { initWasm, wasm } from '../../dist/dpp.compressed.js'; + +before(async () => { + await initWasm(); +}); + +describe('IdentityTopUpFromAddressesTransition', () => { + const addr1Bytes = new Uint8Array([ + 0x00, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + ]); + const addr2Bytes = new Uint8Array([ + 0x00, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, + ]); + + function createTransition() { + const inputAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const outputAddr = wasm.PlatformAddress.fromBytes(addr2Bytes); + + const input = new wasm.PlatformAddressInput(inputAddr, 0, BigInt(100000)); + const output = new wasm.PlatformAddressOutput(outputAddr, BigInt(90000)); + + return new wasm.IdentityTopUpFromAddressesTransition({ + identityId: '11111111111111111111111111111111', + inputs: [input], + output: output, + }); + } + + describe('constructor()', () => { + it('should create transition with string identityId', () => { + const transition = createTransition(); + expect(transition).to.exist(); + expect(transition).to.be.an.instanceof(wasm.IdentityTopUpFromAddressesTransition); + }); + + it('should create transition with Identifier identityId', () => { + const inputAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const input = new wasm.PlatformAddressInput(inputAddr, 0, BigInt(100000)); + const identityId = new wasm.Identifier('GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec'); + + const transition = new wasm.IdentityTopUpFromAddressesTransition({ + identityId, + inputs: [input], + }); + + expect(transition).to.exist(); + }); + + it('should create transition without output', () => { + const inputAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const input = new wasm.PlatformAddressInput(inputAddr, 0, BigInt(100000)); + + const transition = new wasm.IdentityTopUpFromAddressesTransition({ + identityId: '11111111111111111111111111111111', + inputs: [input], + }); + + expect(transition).to.exist(); + }); + + it('should create transition with user fee increase', () => { + const inputAddr = wasm.PlatformAddress.fromBytes(addr1Bytes); + const input = new wasm.PlatformAddressInput(inputAddr, 0, BigInt(100000)); + + const transition = new wasm.IdentityTopUpFromAddressesTransition({ + identityId: '11111111111111111111111111111111', + inputs: [input], + userFeeIncrease: 50, + }); + + expect(transition.userFeeIncrease).to.equal(50); + }); + }); + + describe('toBytes() / fromBytes()', () => { + it('should round-trip via bytes', () => { + const transition = createTransition(); + const bytes = transition.toBytes(); + const restored = wasm.IdentityTopUpFromAddressesTransition.fromBytes(bytes); + expect(Buffer.from(restored.toBytes())).to.deep.equal(Buffer.from(bytes)); + }); + }); + + describe('toBase64() / fromBase64()', () => { + it('should round-trip via base64', () => { + const transition = createTransition(); + const base64 = transition.toBase64(); + const bytes = transition.toBytes(); + expect(Buffer.from(base64, 'base64')).to.deep.equal(Buffer.from(bytes)); + + const restored = wasm.IdentityTopUpFromAddressesTransition.fromBase64(base64); + expect(Buffer.from(restored.toBytes())).to.deep.equal(Buffer.from(bytes)); + }); + }); + + describe('identityId', () => { + it('should return identityId', () => { + const transition = createTransition(); + expect(transition.identityId.toBase58()).to.equal('11111111111111111111111111111111'); + }); + + it('should set identityId with Identifier', () => { + const transition = createTransition(); + const newId = new wasm.Identifier('GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec'); + transition.identityId = newId; + expect(transition.identityId.toBase58()).to.equal('GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec'); + }); + + it('should set identityId with string', () => { + const transition = createTransition(); + transition.identityId = 'GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec'; + expect(transition.identityId.toBase58()).to.equal('GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec'); + }); + }); + + describe('inputs', () => { + it('should return inputs array', () => { + const transition = createTransition(); + const inputs = transition.inputs; + expect(inputs).to.be.an('array'); + expect(inputs).to.have.lengthOf(1); + expect(inputs[0].nonce).to.equal(0); + expect(inputs[0].amount).to.equal(BigInt(100000)); + }); + + it('should set inputs', () => { + const transition = createTransition(); + const newAddr = wasm.PlatformAddress.fromBytes(addr2Bytes); + const newInput = new wasm.PlatformAddressInput(newAddr, 7, BigInt(200000)); + + transition.inputs = [newInput]; + const inputs = transition.inputs; + expect(inputs).to.have.lengthOf(1); + expect(inputs[0].nonce).to.equal(7); + }); + }); + + describe('output', () => { + it('should return output', () => { + const transition = createTransition(); + const output = transition.output; + expect(output).to.exist(); + expect(output.amount).to.equal(BigInt(90000)); + }); + + it('should set output to undefined', () => { + const transition = createTransition(); + transition.output = undefined; + expect(transition.output).to.be.undefined(); + }); + }); + + describe('userFeeIncrease', () => { + it('should return default userFeeIncrease', () => { + const transition = createTransition(); + expect(transition.userFeeIncrease).to.equal(0); + }); + + it('should set userFeeIncrease', () => { + const transition = createTransition(); + transition.userFeeIncrease = 42; + expect(transition.userFeeIncrease).to.equal(42); + }); + }); + + describe('toStateTransition() / fromStateTransition()', () => { + it('should convert to and from StateTransition', () => { + const transition = createTransition(); + const st = transition.toStateTransition(); + expect(st).to.exist(); + + const restored = + wasm.IdentityTopUpFromAddressesTransition.fromStateTransition(st); + expect(Buffer.from(restored.toBytes())).to.deep.equal( + Buffer.from(transition.toBytes()), + ); + }); + }); +}); From 87d6c7962367e53e6bd0ad98c9d03634186b60c8 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Wed, 4 Mar 2026 22:03:47 +0700 Subject: [PATCH 02/15] fix(wasm-dpp2): fix formatting and typo in platform address transitions Fix module name typo (transsition -> transition) and apply cargo fmt. Co-Authored-By: Claude Opus 4.6 --- packages/wasm-dpp2/src/lib.rs | 10 ++--- .../src/platform_address/input_output.rs | 2 +- ...ress_funding_from_asset_lock_transition.rs | 42 +++++++---------- .../address_funds_transfer_transition.rs | 14 +++--- ...entity_create_from_addresses_transition.rs | 45 ++++++++----------- ...credit_transfer_to_addresses_transition.rs | 17 +++---- ...entity_top_up_from_addresses_transition.rs | 41 +++++++---------- .../src/platform_address/transitions/mod.rs | 2 +- 8 files changed, 70 insertions(+), 103 deletions(-) diff --git a/packages/wasm-dpp2/src/lib.rs b/packages/wasm-dpp2/src/lib.rs index cc23e1df137..8ff7050bff0 100644 --- a/packages/wasm-dpp2/src/lib.rs +++ b/packages/wasm-dpp2/src/lib.rs @@ -55,17 +55,17 @@ pub use identity::{ IdentityUpdateTransitionWasm, IdentityWasm, MasternodeVoteTransitionWasm, PartialIdentityWasm, PublicKeyHashLikeJs, public_key_hash_from_js, }; +pub use platform_address::transitions::{ + AddressCreditWithdrawalTransitionWasm, AddressFundingFromAssetLockTransitionWasm, + AddressFundsTransferTransitionWasm, IdentityCreateFromAddressesTransitionWasm, + IdentityCreditTransferToAddressesTransitionWasm, IdentityTopUpFromAddressesTransitionWasm, +}; pub use platform_address::{ FeeStrategyStepWasm, PlatformAddressInputWasm, PlatformAddressLikeArrayJs, PlatformAddressLikeJs, PlatformAddressOutputWasm, PlatformAddressSignerWasm, PlatformAddressWasm, default_fee_strategy, fee_strategy_from_steps, fee_strategy_from_steps_or_default, outputs_to_btree_map, outputs_to_optional_btree_map, }; -pub use platform_address::transitions::{ - AddressCreditWithdrawalTransitionWasm, AddressFundingFromAssetLockTransitionWasm, - AddressFundsTransferTransitionWasm, IdentityCreateFromAddressesTransitionWasm, - IdentityCreditTransferToAddressesTransitionWasm, IdentityTopUpFromAddressesTransitionWasm, -}; pub use state_transitions::base::{GroupStateTransitionInfoWasm, StateTransitionWasm}; pub use state_transitions::proof_result::{StateTransitionProofResultTypeJs, convert_proof_result}; pub use tokens::*; diff --git a/packages/wasm-dpp2/src/platform_address/input_output.rs b/packages/wasm-dpp2/src/platform_address/input_output.rs index 0457a969652..ea55c003d17 100644 --- a/packages/wasm-dpp2/src/platform_address/input_output.rs +++ b/packages/wasm-dpp2/src/platform_address/input_output.rs @@ -1,7 +1,7 @@ use super::{PlatformAddressLikeJs, PlatformAddressWasm}; use crate::error::{WasmDppError, WasmDppResult}; use crate::impl_wasm_type_info; -use crate::utils::{try_to_u64, IntoWasm}; +use crate::utils::{IntoWasm, try_to_u64}; use dpp::address_funds::PlatformAddress; use dpp::fee::Credits; use dpp::prelude::AddressNonce; diff --git a/packages/wasm-dpp2/src/platform_address/transitions/address_funding_from_asset_lock_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/address_funding_from_asset_lock_transition.rs index d35350b9f9b..2d7db57b191 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/address_funding_from_asset_lock_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/address_funding_from_asset_lock_transition.rs @@ -12,12 +12,12 @@ use dpp::platform_value::string_encoding::Encoding::{Base64, Hex}; use dpp::platform_value::string_encoding::{decode, encode}; use dpp::prelude::UserFeeIncrease; use dpp::serialization::{PlatformDeserializable, PlatformSerializable}; +use dpp::state_transition::StateTransition; +use dpp::state_transition::address_funding_from_asset_lock_transition::AddressFundingFromAssetLockTransition; use dpp::state_transition::address_funding_from_asset_lock_transition::accessors::AddressFundingFromAssetLockTransitionAccessorsV0; use dpp::state_transition::address_funding_from_asset_lock_transition::v0::AddressFundingFromAssetLockTransitionV0; -use dpp::state_transition::address_funding_from_asset_lock_transition::AddressFundingFromAssetLockTransition; -use dpp::state_transition::StateTransition; -use wasm_bindgen::prelude::wasm_bindgen; use wasm_bindgen::JsValue; +use wasm_bindgen::prelude::wasm_bindgen; #[wasm_bindgen(typescript_custom_section)] const TS_TYPES: &str = r#" @@ -92,17 +92,15 @@ impl AddressFundingFromAssetLockTransitionWasm { let fee_strategy = fee_strategy_from_steps_or_default(fee_strategy); Ok(AddressFundingFromAssetLockTransitionWasm( - AddressFundingFromAssetLockTransition::V0( - AddressFundingFromAssetLockTransitionV0 { - asset_lock_proof: asset_lock.into(), - inputs: inputs_map, - outputs, - fee_strategy, - user_fee_increase, - signature: Default::default(), - input_witnesses: Default::default(), - }, - ), + AddressFundingFromAssetLockTransition::V0(AddressFundingFromAssetLockTransitionV0 { + asset_lock_proof: asset_lock.into(), + inputs: inputs_map, + outputs, + fee_strategy, + user_fee_increase, + signature: Default::default(), + input_witnesses: Default::default(), + }), )) } @@ -124,27 +122,21 @@ impl AddressFundingFromAssetLockTransitionWasm { } #[wasm_bindgen(js_name = "fromBytes")] - pub fn from_bytes( - bytes: Vec, - ) -> WasmDppResult { + pub fn from_bytes(bytes: Vec) -> WasmDppResult { let rs_transition = AddressFundingFromAssetLockTransition::deserialize_from_bytes(bytes.as_slice())?; Ok(AddressFundingFromAssetLockTransitionWasm(rs_transition)) } #[wasm_bindgen(js_name = "fromHex")] - pub fn from_hex( - hex: String, - ) -> WasmDppResult { + pub fn from_hex(hex: String) -> WasmDppResult { let bytes = decode(hex.as_str(), Hex).map_err(|e| WasmDppError::serialization(e.to_string()))?; Self::from_bytes(bytes) } #[wasm_bindgen(js_name = "fromBase64")] - pub fn from_base64( - base64: String, - ) -> WasmDppResult { + pub fn from_base64(base64: String) -> WasmDppResult { let bytes = decode(base64.as_str(), Base64) .map_err(|e| WasmDppError::serialization(e.to_string()))?; Self::from_bytes(bytes) @@ -188,9 +180,7 @@ impl AddressFundingFromAssetLockTransitionWasm { self.0 .outputs() .iter() - .map(|(address, amount)| { - PlatformAddressOutputWasm::new_optional(*address, *amount) - }) + .map(|(address, amount)| PlatformAddressOutputWasm::new_optional(*address, *amount)) .collect() } diff --git a/packages/wasm-dpp2/src/platform_address/transitions/address_funds_transfer_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/address_funds_transfer_transition.rs index 4482c61f2ee..a7e59ff0e94 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/address_funds_transfer_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/address_funds_transfer_transition.rs @@ -12,11 +12,11 @@ use dpp::platform_value::string_encoding::Encoding::{Base64, Hex}; use dpp::platform_value::string_encoding::{decode, encode}; use dpp::prelude::UserFeeIncrease; use dpp::serialization::{PlatformDeserializable, PlatformSerializable}; -use dpp::state_transition::address_funds_transfer_transition::v0::AddressFundsTransferTransitionV0; -use dpp::state_transition::address_funds_transfer_transition::AddressFundsTransferTransition; use dpp::state_transition::StateTransition; -use wasm_bindgen::prelude::wasm_bindgen; +use dpp::state_transition::address_funds_transfer_transition::AddressFundsTransferTransition; +use dpp::state_transition::address_funds_transfer_transition::v0::AddressFundsTransferTransitionV0; use wasm_bindgen::JsValue; +use wasm_bindgen::prelude::wasm_bindgen; #[wasm_bindgen(typescript_custom_section)] const TS_TYPES: &str = r#" @@ -112,9 +112,7 @@ impl AddressFundsTransferTransitionWasm { } #[wasm_bindgen(js_name = "fromBytes")] - pub fn from_bytes( - bytes: Vec, - ) -> WasmDppResult { + pub fn from_bytes(bytes: Vec) -> WasmDppResult { let rs_transition = AddressFundsTransferTransition::deserialize_from_bytes(bytes.as_slice())?; Ok(AddressFundsTransferTransitionWasm(rs_transition)) @@ -209,9 +207,7 @@ impl AddressFundsTransferTransitionWasm { ) -> WasmDppResult { let rs_st: StateTransition = st.clone().into(); match rs_st { - StateTransition::AddressFundsTransfer(st) => { - Ok(AddressFundsTransferTransitionWasm(st)) - } + StateTransition::AddressFundsTransfer(st) => Ok(AddressFundsTransferTransitionWasm(st)), _ => Err(WasmDppError::invalid_argument( "Invalid state transition type", )), diff --git a/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs index 0d099d2be98..1e03989f16a 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs @@ -7,17 +7,19 @@ use crate::platform_address::{ fee_strategy_from_steps_or_default, inputs_from_js_options, optional_output_from_js_options, }; use crate::state_transitions::StateTransitionWasm; -use crate::utils::{try_from_options_optional_with, try_from_options_with, try_to_array, try_to_u16}; +use crate::utils::{ + try_from_options_optional_with, try_from_options_with, try_to_array, try_to_u16, +}; use dpp::platform_value::string_encoding::Encoding::{Base64, Hex}; use dpp::platform_value::string_encoding::{decode, encode}; use dpp::prelude::UserFeeIncrease; use dpp::serialization::{PlatformDeserializable, PlatformSerializable}; -use dpp::state_transition::identity_create_from_addresses_transition::v0::IdentityCreateFromAddressesTransitionV0; +use dpp::state_transition::StateTransition; use dpp::state_transition::identity_create_from_addresses_transition::IdentityCreateFromAddressesTransition; +use dpp::state_transition::identity_create_from_addresses_transition::v0::IdentityCreateFromAddressesTransitionV0; use dpp::state_transition::public_key_in_creation::IdentityPublicKeyInCreation; -use dpp::state_transition::StateTransition; -use wasm_bindgen::prelude::wasm_bindgen; use wasm_bindgen::JsValue; +use wasm_bindgen::prelude::wasm_bindgen; #[wasm_bindgen(typescript_custom_section)] const TS_TYPES: &str = r#" @@ -92,16 +94,14 @@ impl IdentityCreateFromAddressesTransitionWasm { let fee_strategy = fee_strategy_from_steps_or_default(fee_strategy); Ok(IdentityCreateFromAddressesTransitionWasm( - IdentityCreateFromAddressesTransition::V0( - IdentityCreateFromAddressesTransitionV0 { - public_keys: public_keys.iter().map(|k| k.clone().into()).collect(), - inputs: inputs_map, - output, - fee_strategy, - user_fee_increase, - input_witnesses: Vec::new(), - }, - ), + IdentityCreateFromAddressesTransition::V0(IdentityCreateFromAddressesTransitionV0 { + public_keys: public_keys.iter().map(|k| k.clone().into()).collect(), + inputs: inputs_map, + output, + fee_strategy, + user_fee_increase, + input_witnesses: Vec::new(), + }), )) } @@ -123,27 +123,21 @@ impl IdentityCreateFromAddressesTransitionWasm { } #[wasm_bindgen(js_name = "fromBytes")] - pub fn from_bytes( - bytes: Vec, - ) -> WasmDppResult { + pub fn from_bytes(bytes: Vec) -> WasmDppResult { let rs_transition = IdentityCreateFromAddressesTransition::deserialize_from_bytes(bytes.as_slice())?; Ok(IdentityCreateFromAddressesTransitionWasm(rs_transition)) } #[wasm_bindgen(js_name = "fromHex")] - pub fn from_hex( - hex: String, - ) -> WasmDppResult { + pub fn from_hex(hex: String) -> WasmDppResult { let bytes = decode(hex.as_str(), Hex).map_err(|e| WasmDppError::serialization(e.to_string()))?; Self::from_bytes(bytes) } #[wasm_bindgen(js_name = "fromBase64")] - pub fn from_base64( - base64: String, - ) -> WasmDppResult { + pub fn from_base64(base64: String) -> WasmDppResult { let bytes = decode(base64.as_str(), Base64) .map_err(|e| WasmDppError::serialization(e.to_string()))?; Self::from_bytes(bytes) @@ -214,9 +208,8 @@ impl IdentityCreateFromAddressesTransitionWasm { let new_output = if output.is_undefined() || output.is_null() { None } else { - let output_wasm: PlatformAddressOutputWasm = - serde_wasm_bindgen::from_value(output) - .map_err(|e| WasmDppError::invalid_argument(e.to_string()))?; + let output_wasm: PlatformAddressOutputWasm = serde_wasm_bindgen::from_value(output) + .map_err(|e| WasmDppError::invalid_argument(e.to_string()))?; Some(output_wasm.into_inner()) }; match &mut self.0 { diff --git a/packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs index b5c947967e5..48e7988caf5 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs @@ -2,7 +2,9 @@ use crate::error::{WasmDppError, WasmDppResult}; use crate::identifier::{IdentifierLikeJs, IdentifierWasm}; use crate::impl_wasm_conversions; use crate::impl_wasm_type_info; -use crate::platform_address::{outputs_from_js_options, outputs_to_btree_map, PlatformAddressOutputWasm}; +use crate::platform_address::{ + PlatformAddressOutputWasm, outputs_from_js_options, outputs_to_btree_map, +}; use crate::state_transitions::StateTransitionWasm; use crate::utils::{try_to_u16, try_to_u32, try_to_u64}; use dpp::platform_value::BinaryData; @@ -139,9 +141,7 @@ impl IdentityCreditTransferToAddressesTransitionWasm { } #[wasm_bindgen(js_name = "fromHex")] - pub fn from_hex( - hex: String, - ) -> WasmDppResult { + pub fn from_hex(hex: String) -> WasmDppResult { let bytes = decode(hex.as_str(), Hex).map_err(|e| WasmDppError::serialization(e.to_string()))?; IdentityCreditTransferToAddressesTransitionWasm::from_bytes(bytes) @@ -151,8 +151,8 @@ impl IdentityCreditTransferToAddressesTransitionWasm { pub fn from_base64( base64: String, ) -> WasmDppResult { - let bytes = - decode(base64.as_str(), Base64).map_err(|e| WasmDppError::serialization(e.to_string()))?; + let bytes = decode(base64.as_str(), Base64) + .map_err(|e| WasmDppError::serialization(e.to_string()))?; IdentityCreditTransferToAddressesTransitionWasm::from_bytes(bytes) } @@ -166,10 +166,7 @@ impl IdentityCreditTransferToAddressesTransitionWasm { } #[wasm_bindgen(setter = "recipientAddresses")] - pub fn set_recipient_addresses( - &mut self, - outputs: Vec, - ) { + pub fn set_recipient_addresses(&mut self, outputs: Vec) { self.0 .set_recipient_addresses(outputs_to_btree_map(outputs)); } diff --git a/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs index 6019899d9b6..81ef3e7e8b5 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs @@ -12,11 +12,11 @@ use dpp::platform_value::string_encoding::Encoding::{Base64, Hex}; use dpp::platform_value::string_encoding::{decode, encode}; use dpp::prelude::UserFeeIncrease; use dpp::serialization::{PlatformDeserializable, PlatformSerializable}; -use dpp::state_transition::identity_topup_from_addresses_transition::v0::IdentityTopUpFromAddressesTransitionV0; -use dpp::state_transition::identity_topup_from_addresses_transition::IdentityTopUpFromAddressesTransition; use dpp::state_transition::StateTransition; -use wasm_bindgen::prelude::wasm_bindgen; +use dpp::state_transition::identity_topup_from_addresses_transition::IdentityTopUpFromAddressesTransition; +use dpp::state_transition::identity_topup_from_addresses_transition::v0::IdentityTopUpFromAddressesTransitionV0; use wasm_bindgen::JsValue; +use wasm_bindgen::prelude::wasm_bindgen; #[wasm_bindgen(typescript_custom_section)] const TS_TYPES: &str = r#" @@ -88,16 +88,14 @@ impl IdentityTopUpFromAddressesTransitionWasm { let fee_strategy = fee_strategy_from_steps_or_default(fee_strategy); Ok(IdentityTopUpFromAddressesTransitionWasm( - IdentityTopUpFromAddressesTransition::V0( - IdentityTopUpFromAddressesTransitionV0 { - identity_id: identity_id.into(), - inputs: inputs_map, - output, - fee_strategy, - user_fee_increase, - input_witnesses: Vec::new(), - }, - ), + IdentityTopUpFromAddressesTransition::V0(IdentityTopUpFromAddressesTransitionV0 { + identity_id: identity_id.into(), + inputs: inputs_map, + output, + fee_strategy, + user_fee_increase, + input_witnesses: Vec::new(), + }), )) } @@ -119,27 +117,21 @@ impl IdentityTopUpFromAddressesTransitionWasm { } #[wasm_bindgen(js_name = "fromBytes")] - pub fn from_bytes( - bytes: Vec, - ) -> WasmDppResult { + pub fn from_bytes(bytes: Vec) -> WasmDppResult { let rs_transition = IdentityTopUpFromAddressesTransition::deserialize_from_bytes(bytes.as_slice())?; Ok(IdentityTopUpFromAddressesTransitionWasm(rs_transition)) } #[wasm_bindgen(js_name = "fromHex")] - pub fn from_hex( - hex: String, - ) -> WasmDppResult { + pub fn from_hex(hex: String) -> WasmDppResult { let bytes = decode(hex.as_str(), Hex).map_err(|e| WasmDppError::serialization(e.to_string()))?; Self::from_bytes(bytes) } #[wasm_bindgen(js_name = "fromBase64")] - pub fn from_base64( - base64: String, - ) -> WasmDppResult { + pub fn from_base64(base64: String) -> WasmDppResult { let bytes = decode(base64.as_str(), Base64) .map_err(|e| WasmDppError::serialization(e.to_string()))?; Self::from_bytes(bytes) @@ -202,9 +194,8 @@ impl IdentityTopUpFromAddressesTransitionWasm { let new_output = if output.is_undefined() || output.is_null() { None } else { - let output_wasm: PlatformAddressOutputWasm = - serde_wasm_bindgen::from_value(output) - .map_err(|e| WasmDppError::invalid_argument(e.to_string()))?; + let output_wasm: PlatformAddressOutputWasm = serde_wasm_bindgen::from_value(output) + .map_err(|e| WasmDppError::invalid_argument(e.to_string()))?; Some(output_wasm.into_inner()) }; match &mut self.0 { diff --git a/packages/wasm-dpp2/src/platform_address/transitions/mod.rs b/packages/wasm-dpp2/src/platform_address/transitions/mod.rs index 3232116c968..cc6a60232fd 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/mod.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/mod.rs @@ -7,7 +7,7 @@ pub mod identity_top_up_from_addresses_transition; pub use address_credit_withdrawal_transition::AddressCreditWithdrawalTransitionWasm; pub use address_funding_from_asset_lock_transition::AddressFundingFromAssetLockTransitionWasm; -pub use address_funds_transfer_transsition::AddressFundsTransferTransitionWasm; +pub use address_funds_transfer_transition::AddressFundsTransferTransitionWasm; pub use identity_create_from_addresses_transition::IdentityCreateFromAddressesTransitionWasm; pub use identity_credit_transfer_to_addresses_transition::IdentityCreditTransferToAddressesTransitionWasm; pub use identity_top_up_from_addresses_transition::IdentityTopUpFromAddressesTransitionWasm; From bf0120c17f7a19af7775df633df0844ebc35d25d Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Wed, 4 Mar 2026 22:40:31 +0700 Subject: [PATCH 03/15] fix(wasm-dpp2): use typed params instead of JsValue in platform address setters Replace JsValue with Option for set_output and CoreScriptWasm for set_output_script to generate proper TypeScript types. Co-Authored-By: Claude Opus 4.6 --- .../address_credit_withdrawal_transition.rs | 24 ++++--------------- ...entity_create_from_addresses_transition.rs | 11 ++------- ...entity_top_up_from_addresses_transition.rs | 11 ++------- 3 files changed, 9 insertions(+), 37 deletions(-) diff --git a/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs index ecbf56ee662..981599e001b 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs @@ -9,8 +9,7 @@ use crate::platform_address::{ }; use crate::state_transitions::StateTransitionWasm; use crate::utils::{ - IntoWasm, try_from_options, try_from_options_optional_with, try_from_options_with, try_to_u16, - try_to_u32, + try_from_options, try_from_options_optional_with, try_from_options_with, try_to_u16, try_to_u32, }; use dpp::platform_value::string_encoding::Encoding::{Base64, Hex}; use dpp::platform_value::string_encoding::{decode, encode}; @@ -185,24 +184,13 @@ impl AddressCreditWithdrawalTransitionWasm { } #[wasm_bindgen(setter = "output")] - pub fn set_output(&mut self, output: JsValue) -> WasmDppResult<()> { - let new_output = if output.is_undefined() || output.is_null() { - None - } else { - let output_wasm = output - .to_wasm::("PlatformAddressOutput") - .map(|r| (*r).clone()) - .map_err(|_| { - WasmDppError::invalid_argument("'output' is not a PlatformAddressOutput") - })?; - Some(output_wasm.into_inner()) - }; + pub fn set_output(&mut self, output: Option) { + let new_output = output.map(|o| o.into_inner()); match &mut self.0 { AddressCreditWithdrawalTransition::V0(v0) => { v0.output = new_output; } } - Ok(()) } #[wasm_bindgen(getter = "outputScript")] @@ -213,14 +201,12 @@ impl AddressCreditWithdrawalTransitionWasm { } #[wasm_bindgen(setter = "outputScript")] - pub fn set_output_script(&mut self, script: &JsValue) -> WasmDppResult<()> { - let script = CoreScriptWasm::try_from(script)?; + pub fn set_output_script(&mut self, script: &CoreScriptWasm) { match &mut self.0 { AddressCreditWithdrawalTransition::V0(v0) => { - v0.output_script = script.into(); + v0.output_script = script.clone().into(); } } - Ok(()) } #[wasm_bindgen(getter = "pooling")] diff --git a/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs index 1e03989f16a..61770e8091f 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs @@ -204,20 +204,13 @@ impl IdentityCreateFromAddressesTransitionWasm { } #[wasm_bindgen(setter = "output")] - pub fn set_output(&mut self, output: JsValue) -> WasmDppResult<()> { - let new_output = if output.is_undefined() || output.is_null() { - None - } else { - let output_wasm: PlatformAddressOutputWasm = serde_wasm_bindgen::from_value(output) - .map_err(|e| WasmDppError::invalid_argument(e.to_string()))?; - Some(output_wasm.into_inner()) - }; + pub fn set_output(&mut self, output: Option) { + let new_output = output.map(|o| o.into_inner()); match &mut self.0 { IdentityCreateFromAddressesTransition::V0(v0) => { v0.output = new_output; } } - Ok(()) } #[wasm_bindgen(getter = "userFeeIncrease")] diff --git a/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs index 81ef3e7e8b5..8aae7f760cd 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs @@ -190,20 +190,13 @@ impl IdentityTopUpFromAddressesTransitionWasm { } #[wasm_bindgen(setter = "output")] - pub fn set_output(&mut self, output: JsValue) -> WasmDppResult<()> { - let new_output = if output.is_undefined() || output.is_null() { - None - } else { - let output_wasm: PlatformAddressOutputWasm = serde_wasm_bindgen::from_value(output) - .map_err(|e| WasmDppError::invalid_argument(e.to_string()))?; - Some(output_wasm.into_inner()) - }; + pub fn set_output(&mut self, output: Option) { + let new_output = output.map(|o| o.into_inner()); match &mut self.0 { IdentityTopUpFromAddressesTransition::V0(v0) => { v0.output = new_output; } } - Ok(()) } #[wasm_bindgen(getter = "userFeeIncrease")] From e39645d084276b26322ac606168dc63be7ddfabe Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Wed, 4 Mar 2026 22:49:32 +0700 Subject: [PATCH 04/15] refactor(wasm-dpp2): replace JsValue with typed params in setters across wasm-dpp2 Use js_sys::BigInt for u64 setters (balance, revision, nonce, amount, price, supply) and js_sys::Number for u32/u16 setters (version, userFeeIncrease, tokenContractPosition) to generate proper TypeScript types (bigint/number) instead of any. Co-Authored-By: Claude Opus 4.6 --- packages/wasm-dpp2/src/data_contract/model.rs | 4 ++-- packages/wasm-dpp2/src/identity/model.rs | 9 ++++----- .../src/identity/transitions/create_transition.rs | 5 ++--- .../identity/transitions/masternode_vote_transition.rs | 8 ++++---- .../src/identity/transitions/update_transition.rs | 9 ++++----- .../src/state_transitions/base/state_transition.rs | 8 ++++---- .../src/state_transitions/batch/batch_transition.rs | 4 ++-- .../state_transitions/batch/document_base_transition.rs | 5 ++--- .../src/state_transitions/batch/document_transition.rs | 9 ++++----- .../batch/document_transitions/purchase.rs | 9 ++++----- .../batch/document_transitions/replace.rs | 4 ++-- .../batch/document_transitions/update_price.rs | 5 ++--- .../src/state_transitions/batch/token_base_transition.rs | 4 ++-- .../src/state_transitions/batch/token_transition.rs | 4 ++-- .../batch/token_transitions/token_burn.rs | 5 ++--- .../batch/token_transitions/token_mint.rs | 5 ++--- .../batch/token_transitions/token_transfer.rs | 4 ++-- .../src/tokens/configuration/token_configuration.rs | 4 ++-- 18 files changed, 48 insertions(+), 57 deletions(-) diff --git a/packages/wasm-dpp2/src/data_contract/model.rs b/packages/wasm-dpp2/src/data_contract/model.rs index 18fe46bc52f..bc2196a994f 100644 --- a/packages/wasm-dpp2/src/data_contract/model.rs +++ b/packages/wasm-dpp2/src/data_contract/model.rs @@ -460,8 +460,8 @@ impl DataContractWasm { } #[wasm_bindgen(setter = "version")] - pub fn set_version(&mut self, version: JsValue) -> WasmDppResult<()> { - self.0.set_version(try_to_u32(&version, "version")?); + pub fn set_version(&mut self, version: &js_sys::Number) -> WasmDppResult<()> { + self.0.set_version(try_to_u32(version, "version")?); Ok(()) } diff --git a/packages/wasm-dpp2/src/identity/model.rs b/packages/wasm-dpp2/src/identity/model.rs index 6cbba343a36..d3492073bd9 100644 --- a/packages/wasm-dpp2/src/identity/model.rs +++ b/packages/wasm-dpp2/src/identity/model.rs @@ -13,7 +13,6 @@ use dpp::platform_value::string_encoding::{decode, encode}; use dpp::prelude::Identifier; use dpp::serialization::{PlatformDeserializable, PlatformSerializable, ValueConvertible}; use dpp::version::{PlatformVersion, TryFromPlatformVersioned}; -use wasm_bindgen::JsValue; use wasm_bindgen::prelude::wasm_bindgen; #[wasm_bindgen(typescript_custom_section)] @@ -83,14 +82,14 @@ impl IdentityWasm { } #[wasm_bindgen(setter = "balance")] - pub fn set_balance(&mut self, balance: JsValue) -> WasmDppResult<()> { - self.0.set_balance(try_to_u64(&balance, "balance")?); + pub fn set_balance(&mut self, balance: &js_sys::BigInt) -> WasmDppResult<()> { + self.0.set_balance(try_to_u64(balance, "balance")?); Ok(()) } #[wasm_bindgen(setter = "revision")] - pub fn set_revision(&mut self, revision: JsValue) -> WasmDppResult<()> { - self.0.set_revision(try_to_u64(&revision, "revision")?); + pub fn set_revision(&mut self, revision: &js_sys::BigInt) -> WasmDppResult<()> { + self.0.set_revision(try_to_u64(revision, "revision")?); Ok(()) } diff --git a/packages/wasm-dpp2/src/identity/transitions/create_transition.rs b/packages/wasm-dpp2/src/identity/transitions/create_transition.rs index 65f053f5588..e6fea109b8b 100644 --- a/packages/wasm-dpp2/src/identity/transitions/create_transition.rs +++ b/packages/wasm-dpp2/src/identity/transitions/create_transition.rs @@ -19,7 +19,6 @@ use dpp::state_transition::identity_create_transition::v0::IdentityCreateTransit use dpp::state_transition::public_key_in_creation::IdentityPublicKeyInCreation; use dpp::state_transition::{StateTransition, StateTransitionLike, StateTransitionSingleSigned}; use serde::Deserialize; -use wasm_bindgen::JsValue; use wasm_bindgen::prelude::wasm_bindgen; #[derive(Deserialize)] @@ -207,9 +206,9 @@ impl IdentityCreateTransitionWasm { } #[wasm_bindgen(setter = "userFeeIncrease")] - pub fn set_user_fee_increase(&mut self, amount: JsValue) -> WasmDppResult<()> { + pub fn set_user_fee_increase(&mut self, amount: &js_sys::Number) -> WasmDppResult<()> { self.0 - .set_user_fee_increase(try_to_u16(&amount, "userFeeIncrease")?); + .set_user_fee_increase(try_to_u16(amount, "userFeeIncrease")?); Ok(()) } diff --git a/packages/wasm-dpp2/src/identity/transitions/masternode_vote_transition.rs b/packages/wasm-dpp2/src/identity/transitions/masternode_vote_transition.rs index 1eb21075249..6631f736608 100644 --- a/packages/wasm-dpp2/src/identity/transitions/masternode_vote_transition.rs +++ b/packages/wasm-dpp2/src/identity/transitions/masternode_vote_transition.rs @@ -183,8 +183,8 @@ impl MasternodeVoteTransitionWasm { } #[wasm_bindgen(setter = nonce)] - pub fn set_nonce(&mut self, nonce: JsValue) -> WasmDppResult<()> { - let nonce = try_to_u64(&nonce, "nonce")?; + pub fn set_nonce(&mut self, nonce: &js_sys::BigInt) -> WasmDppResult<()> { + let nonce = try_to_u64(nonce, "nonce")?; self.0 = match self.0.clone() { MasternodeVoteTransition::V0(mut vote) => { vote.nonce = nonce; @@ -253,9 +253,9 @@ impl MasternodeVoteTransitionWasm { } #[wasm_bindgen(setter = "userFeeIncrease")] - pub fn set_user_fee_increase(&mut self, amount: JsValue) -> WasmDppResult<()> { + pub fn set_user_fee_increase(&mut self, amount: &js_sys::Number) -> WasmDppResult<()> { self.0 - .set_user_fee_increase(try_to_u16(&amount, "userFeeIncrease")?); + .set_user_fee_increase(try_to_u16(amount, "userFeeIncrease")?); Ok(()) } diff --git a/packages/wasm-dpp2/src/identity/transitions/update_transition.rs b/packages/wasm-dpp2/src/identity/transitions/update_transition.rs index a5ad053b7dd..e32fbf6da6e 100644 --- a/packages/wasm-dpp2/src/identity/transitions/update_transition.rs +++ b/packages/wasm-dpp2/src/identity/transitions/update_transition.rs @@ -22,7 +22,6 @@ use dpp::state_transition::{ StateTransitionSingleSigned, }; use serde::Deserialize; -use wasm_bindgen::JsValue; use wasm_bindgen::prelude::wasm_bindgen; #[wasm_bindgen(typescript_custom_section)] @@ -200,14 +199,14 @@ impl IdentityUpdateTransitionWasm { } #[wasm_bindgen(setter = "revision")] - pub fn set_revision(&mut self, revision: JsValue) -> WasmDppResult<()> { - self.0.set_revision(try_to_u64(&revision, "revision")?); + pub fn set_revision(&mut self, revision: &js_sys::BigInt) -> WasmDppResult<()> { + self.0.set_revision(try_to_u64(revision, "revision")?); Ok(()) } #[wasm_bindgen(setter = "nonce")] - pub fn set_nonce(&mut self, nonce: JsValue) -> WasmDppResult<()> { - self.0.set_nonce(try_to_u64(&nonce, "nonce")?); + pub fn set_nonce(&mut self, nonce: &js_sys::BigInt) -> WasmDppResult<()> { + self.0.set_nonce(try_to_u64(nonce, "nonce")?); Ok(()) } 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..4a396b0dbc1 100644 --- a/packages/wasm-dpp2/src/state_transitions/base/state_transition.rs +++ b/packages/wasm-dpp2/src/state_transitions/base/state_transition.rs @@ -557,9 +557,9 @@ impl StateTransitionWasm { } #[wasm_bindgen(js_name = "setIdentityContractNonce")] - pub fn set_identity_contract_nonce(&mut self, nonce: JsValue) -> WasmDppResult<()> { + pub fn set_identity_contract_nonce(&mut self, nonce: &js_sys::BigInt) -> WasmDppResult<()> { use crate::utils::try_to_u64; - let nonce: IdentityNonce = try_to_u64(&nonce, "identityContractNonce")?; + let nonce: IdentityNonce = try_to_u64(nonce, "identityContractNonce")?; use StateTransition::*; self.0 = match self.0.clone() { DataContractCreate(_) => { @@ -625,9 +625,9 @@ impl StateTransitionWasm { } #[wasm_bindgen(js_name = "setIdentityNonce")] - pub fn set_identity_nonce(&mut self, nonce: JsValue) -> WasmDppResult<()> { + pub fn set_identity_nonce(&mut self, nonce: &js_sys::BigInt) -> WasmDppResult<()> { use crate::utils::try_to_u64; - let nonce: IdentityNonce = try_to_u64(&nonce, "identityNonce")?; + let nonce: IdentityNonce = try_to_u64(nonce, "identityNonce")?; use StateTransition::*; self.0 = match self.0.clone() { DataContractCreate(mut contract_create) => { diff --git a/packages/wasm-dpp2/src/state_transitions/batch/batch_transition.rs b/packages/wasm-dpp2/src/state_transitions/batch/batch_transition.rs index 65800ce2209..0f360f9f99f 100644 --- a/packages/wasm-dpp2/src/state_transitions/batch/batch_transition.rs +++ b/packages/wasm-dpp2/src/state_transitions/batch/batch_transition.rs @@ -183,9 +183,9 @@ impl BatchTransitionWasm { } #[wasm_bindgen(js_name = "setIdentityContractNonce")] - pub fn set_identity_contract_nonce(&mut self, nonce: JsValue) -> WasmDppResult<()> { + pub fn set_identity_contract_nonce(&mut self, nonce: &js_sys::BigInt) -> WasmDppResult<()> { self.0 - .set_identity_contract_nonce(try_to_u64(&nonce, "identityContractNonce")?); + .set_identity_contract_nonce(try_to_u64(nonce, "identityContractNonce")?); Ok(()) } diff --git a/packages/wasm-dpp2/src/state_transitions/batch/document_base_transition.rs b/packages/wasm-dpp2/src/state_transitions/batch/document_base_transition.rs index 8a30c76e58a..829d1f334a8 100644 --- a/packages/wasm-dpp2/src/state_transitions/batch/document_base_transition.rs +++ b/packages/wasm-dpp2/src/state_transitions/batch/document_base_transition.rs @@ -10,7 +10,6 @@ use dpp::state_transition::batch_transition::document_base_transition::v1::Docum use dpp::state_transition::batch_transition::document_base_transition::v1::v1_methods::DocumentBaseTransitionV1Methods; use dpp::tokens::token_payment_info::TokenPaymentInfo; use serde::Deserialize; -use wasm_bindgen::JsValue; use wasm_bindgen::prelude::wasm_bindgen; #[derive(Deserialize)] @@ -119,9 +118,9 @@ impl DocumentBaseTransitionWasm { } #[wasm_bindgen(setter = "identityContractNonce")] - pub fn set_identity_contract_nonce(&mut self, nonce: JsValue) -> WasmDppResult<()> { + pub fn set_identity_contract_nonce(&mut self, nonce: &js_sys::BigInt) -> WasmDppResult<()> { self.0 - .set_identity_contract_nonce(try_to_u64(&nonce, "identityContractNonce")?); + .set_identity_contract_nonce(try_to_u64(nonce, "identityContractNonce")?); Ok(()) } diff --git a/packages/wasm-dpp2/src/state_transitions/batch/document_transition.rs b/packages/wasm-dpp2/src/state_transitions/batch/document_transition.rs index 26e0808507f..7a16b8caefb 100644 --- a/packages/wasm-dpp2/src/state_transitions/batch/document_transition.rs +++ b/packages/wasm-dpp2/src/state_transitions/batch/document_transition.rs @@ -17,7 +17,6 @@ use dpp::state_transition::batch_transition::batched_transition::document_transi DocumentTransitionActionType, DocumentTransitionActionTypeGetter, }; use crate::utils::try_to_u64; -use wasm_bindgen::JsValue; use wasm_bindgen::prelude::wasm_bindgen; #[derive(Clone)] @@ -164,18 +163,18 @@ impl DocumentTransitionWasm { } #[wasm_bindgen(setter = "revision")] - pub fn set_revision(&mut self, revision: JsValue) -> WasmDppResult<()> { - self.0.set_revision(try_to_u64(&revision, "revision")?); + pub fn set_revision(&mut self, revision: &js_sys::BigInt) -> WasmDppResult<()> { + self.0.set_revision(try_to_u64(revision, "revision")?); Ok(()) } #[wasm_bindgen(setter = "identityContractNonce")] pub fn set_identity_contract_nonce( &mut self, - #[wasm_bindgen(js_name = "identityContractNonce")] identity_contract_nonce: JsValue, + #[wasm_bindgen(js_name = "identityContractNonce")] identity_contract_nonce: &js_sys::BigInt, ) -> WasmDppResult<()> { self.0.set_identity_contract_nonce(try_to_u64( - &identity_contract_nonce, + identity_contract_nonce, "identityContractNonce", )?); Ok(()) diff --git a/packages/wasm-dpp2/src/state_transitions/batch/document_transitions/purchase.rs b/packages/wasm-dpp2/src/state_transitions/batch/document_transitions/purchase.rs index 7edd1690bcc..6fa0745c34b 100644 --- a/packages/wasm-dpp2/src/state_transitions/batch/document_transitions/purchase.rs +++ b/packages/wasm-dpp2/src/state_transitions/batch/document_transitions/purchase.rs @@ -13,7 +13,6 @@ use dpp::state_transition::batch_transition::batched_transition::document_transi use dpp::state_transition::batch_transition::batched_transition::DocumentPurchaseTransition; use dpp::state_transition::batch_transition::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; use wasm_bindgen::prelude::wasm_bindgen; -use wasm_bindgen::JsValue; #[wasm_bindgen(typescript_custom_section)] const DOCUMENT_PURCHASE_OPTIONS_TS: &str = r#" @@ -97,9 +96,9 @@ impl DocumentPurchaseTransitionWasm { } #[wasm_bindgen(setter = "price")] - pub fn set_price(&mut self, price: JsValue) -> WasmDppResult<()> { + pub fn set_price(&mut self, price: &js_sys::BigInt) -> WasmDppResult<()> { use crate::utils::try_to_u64; - let price = try_to_u64(&price, "price")?; + let price = try_to_u64(price, "price")?; match self.0 { DocumentPurchaseTransition::V0(ref mut v0) => v0.price = price, } @@ -107,9 +106,9 @@ impl DocumentPurchaseTransitionWasm { } #[wasm_bindgen(setter = "revision")] - pub fn set_revision(&mut self, revision: JsValue) -> WasmDppResult<()> { + pub fn set_revision(&mut self, revision: &js_sys::BigInt) -> WasmDppResult<()> { use crate::utils::try_to_u64; - self.0.set_revision(try_to_u64(&revision, "revision")?); + self.0.set_revision(try_to_u64(revision, "revision")?); Ok(()) } diff --git a/packages/wasm-dpp2/src/state_transitions/batch/document_transitions/replace.rs b/packages/wasm-dpp2/src/state_transitions/batch/document_transitions/replace.rs index 926b85f30c6..ec9d4ace0a0 100644 --- a/packages/wasm-dpp2/src/state_transitions/batch/document_transitions/replace.rs +++ b/packages/wasm-dpp2/src/state_transitions/batch/document_transitions/replace.rs @@ -107,9 +107,9 @@ impl DocumentReplaceTransitionWasm { } #[wasm_bindgen(setter = "revision")] - pub fn set_revision(&mut self, revision: JsValue) -> WasmDppResult<()> { + pub fn set_revision(&mut self, revision: &js_sys::BigInt) -> WasmDppResult<()> { use crate::utils::try_to_u64; - self.0.set_revision(try_to_u64(&revision, "revision")?); + self.0.set_revision(try_to_u64(revision, "revision")?); Ok(()) } diff --git a/packages/wasm-dpp2/src/state_transitions/batch/document_transitions/update_price.rs b/packages/wasm-dpp2/src/state_transitions/batch/document_transitions/update_price.rs index 4ac69d3ce36..e60dd1350f8 100644 --- a/packages/wasm-dpp2/src/state_transitions/batch/document_transitions/update_price.rs +++ b/packages/wasm-dpp2/src/state_transitions/batch/document_transitions/update_price.rs @@ -13,7 +13,6 @@ use dpp::state_transition::batch_transition::batched_transition::document_update use dpp::state_transition::batch_transition::batched_transition::DocumentUpdatePriceTransition; use dpp::state_transition::batch_transition::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; use wasm_bindgen::prelude::wasm_bindgen; -use wasm_bindgen::JsValue; #[wasm_bindgen(typescript_custom_section)] const DOCUMENT_UPDATE_PRICE_OPTIONS_TS: &str = r#" @@ -87,9 +86,9 @@ impl DocumentUpdatePriceTransitionWasm { } #[wasm_bindgen(setter = "price")] - pub fn set_price(&mut self, price: JsValue) -> WasmDppResult<()> { + pub fn set_price(&mut self, price: &js_sys::BigInt) -> WasmDppResult<()> { use crate::utils::try_to_u64; - self.0.set_price(try_to_u64(&price, "price")?); + self.0.set_price(try_to_u64(price, "price")?); Ok(()) } diff --git a/packages/wasm-dpp2/src/state_transitions/batch/token_base_transition.rs b/packages/wasm-dpp2/src/state_transitions/batch/token_base_transition.rs index c215db93a75..fbd2db95ecf 100644 --- a/packages/wasm-dpp2/src/state_transitions/batch/token_base_transition.rs +++ b/packages/wasm-dpp2/src/state_transitions/batch/token_base_transition.rs @@ -117,9 +117,9 @@ impl TokenBaseTransitionWasm { } #[wasm_bindgen(setter = tokenContractPosition)] - pub fn set_token_contract_position(&mut self, pos: JsValue) -> WasmDppResult<()> { + pub fn set_token_contract_position(&mut self, pos: &js_sys::Number) -> WasmDppResult<()> { self.0 - .set_token_contract_position(try_to_u16(&pos, "tokenContractPosition")?); + .set_token_contract_position(try_to_u16(pos, "tokenContractPosition")?); Ok(()) } diff --git a/packages/wasm-dpp2/src/state_transitions/batch/token_transition.rs b/packages/wasm-dpp2/src/state_transitions/batch/token_transition.rs index 99cc918feaf..18529a7ca09 100644 --- a/packages/wasm-dpp2/src/state_transitions/batch/token_transition.rs +++ b/packages/wasm-dpp2/src/state_transitions/batch/token_transition.rs @@ -237,10 +237,10 @@ impl TokenTransitionWasm { } #[wasm_bindgen(setter = "identityContractNonce")] - pub fn set_identity_contract_nonce(&mut self, nonce: JsValue) -> WasmDppResult<()> { + pub fn set_identity_contract_nonce(&mut self, nonce: &js_sys::BigInt) -> WasmDppResult<()> { use crate::utils::try_to_u64; self.0 - .set_identity_contract_nonce(try_to_u64(&nonce, "identityContractNonce")?); + .set_identity_contract_nonce(try_to_u64(nonce, "identityContractNonce")?); Ok(()) } diff --git a/packages/wasm-dpp2/src/state_transitions/batch/token_transitions/token_burn.rs b/packages/wasm-dpp2/src/state_transitions/batch/token_transitions/token_burn.rs index 26bf37fc15f..ae9d7316fa4 100644 --- a/packages/wasm-dpp2/src/state_transitions/batch/token_transitions/token_burn.rs +++ b/packages/wasm-dpp2/src/state_transitions/batch/token_transitions/token_burn.rs @@ -7,7 +7,6 @@ use dpp::state_transition::batch_transition::token_base_transition::token_base_t use dpp::state_transition::batch_transition::token_burn_transition::v0::v0_methods::TokenBurnTransitionV0Methods; use dpp::state_transition::batch_transition::token_burn_transition::TokenBurnTransitionV0; use dpp::state_transition::batch_transition::TokenBurnTransition; -use wasm_bindgen::JsValue; use wasm_bindgen::prelude::wasm_bindgen; #[wasm_bindgen(typescript_custom_section)] @@ -82,8 +81,8 @@ impl TokenBurnTransitionWasm { } #[wasm_bindgen(setter = burnAmount)] - pub fn set_burn_amount(&mut self, amount: JsValue) -> WasmDppResult<()> { - self.0.set_burn_amount(try_to_u64(&amount, "burnAmount")?); + pub fn set_burn_amount(&mut self, amount: &js_sys::BigInt) -> WasmDppResult<()> { + self.0.set_burn_amount(try_to_u64(amount, "burnAmount")?); Ok(()) } diff --git a/packages/wasm-dpp2/src/state_transitions/batch/token_transitions/token_mint.rs b/packages/wasm-dpp2/src/state_transitions/batch/token_transitions/token_mint.rs index d67bc89db27..bf6c796508b 100644 --- a/packages/wasm-dpp2/src/state_transitions/batch/token_transitions/token_mint.rs +++ b/packages/wasm-dpp2/src/state_transitions/batch/token_transitions/token_mint.rs @@ -14,7 +14,6 @@ use dpp::state_transition::batch_transition::token_mint_transition::v0::v0_metho use dpp::state_transition::batch_transition::token_mint_transition::TokenMintTransitionV0; use dpp::state_transition::batch_transition::TokenMintTransition; use wasm_bindgen::prelude::wasm_bindgen; -use wasm_bindgen::JsValue; #[wasm_bindgen(typescript_custom_section)] const TOKEN_MINT_OPTIONS_TS: &str = r#" @@ -112,8 +111,8 @@ impl TokenMintTransitionWasm { } #[wasm_bindgen(setter = amount)] - pub fn set_amount(&mut self, amount: JsValue) -> WasmDppResult<()> { - self.0.set_amount(try_to_u64(&amount, "amount")?); + pub fn set_amount(&mut self, amount: &js_sys::BigInt) -> WasmDppResult<()> { + self.0.set_amount(try_to_u64(amount, "amount")?); Ok(()) } diff --git a/packages/wasm-dpp2/src/state_transitions/batch/token_transitions/token_transfer.rs b/packages/wasm-dpp2/src/state_transitions/batch/token_transitions/token_transfer.rs index 913aff4b2d1..a53f3627ab2 100644 --- a/packages/wasm-dpp2/src/state_transitions/batch/token_transitions/token_transfer.rs +++ b/packages/wasm-dpp2/src/state_transitions/batch/token_transitions/token_transfer.rs @@ -132,8 +132,8 @@ impl TokenTransferTransitionWasm { } #[wasm_bindgen(setter = "amount")] - pub fn set_amount(&mut self, amount: JsValue) -> WasmDppResult<()> { - self.0.set_amount(try_to_u64(&amount, "amount")?); + pub fn set_amount(&mut self, amount: &js_sys::BigInt) -> WasmDppResult<()> { + self.0.set_amount(try_to_u64(amount, "amount")?); Ok(()) } diff --git a/packages/wasm-dpp2/src/tokens/configuration/token_configuration.rs b/packages/wasm-dpp2/src/tokens/configuration/token_configuration.rs index a6bab734c88..61648a0ba68 100644 --- a/packages/wasm-dpp2/src/tokens/configuration/token_configuration.rs +++ b/packages/wasm-dpp2/src/tokens/configuration/token_configuration.rs @@ -254,9 +254,9 @@ impl TokenConfigurationWasm { } #[wasm_bindgen(setter = "baseSupply")] - pub fn set_base_supply(&mut self, base_supply: JsValue) -> WasmDppResult<()> { + pub fn set_base_supply(&mut self, base_supply: &js_sys::BigInt) -> WasmDppResult<()> { self.0 - .set_base_supply(try_to_u64(&base_supply, "baseSupply")?); + .set_base_supply(try_to_u64(base_supply, "baseSupply")?); Ok(()) } From ce9a6abd721c578165b20016b833c495028095df Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Tue, 10 Mar 2026 20:45:42 +0700 Subject: [PATCH 05/15] fix(sdk): replace panicking into_inner() with fallible try_into_inner() PlatformAddressOutput::into_inner() panicked via expect() when amount was None. Replace it with try_into_inner() that returns a WasmDppError instead. Make outputs_to_btree_map fallible accordingly, and update all callers (set_output, set_outputs, set_recipient_addresses, constructors) to propagate the error via ? instead of panicking. Co-Authored-By: Claude Sonnet 4.6 --- .../src/platform_address/input_output.rs | 18 +++++++++--------- .../address_credit_withdrawal_transition.rs | 8 ++++++-- .../address_funds_transfer_transition.rs | 7 ++++--- ..._credit_transfer_to_addresses_transition.rs | 10 +++++++--- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/packages/wasm-dpp2/src/platform_address/input_output.rs b/packages/wasm-dpp2/src/platform_address/input_output.rs index ea55c003d17..2a4613300ff 100644 --- a/packages/wasm-dpp2/src/platform_address/input_output.rs +++ b/packages/wasm-dpp2/src/platform_address/input_output.rs @@ -149,13 +149,12 @@ impl PlatformAddressOutputWasm { } } - /// Returns the inner values as a tuple suitable for BTreeMap insertion. - /// Panics if amount is None - use `into_inner_optional` for optional amounts. - pub fn into_inner(self) -> (PlatformAddress, Credits) { - ( - self.address.into(), - self.amount.expect("amount is required for this operation"), - ) + /// Returns the inner values as a tuple, or an error if amount is None. + pub fn try_into_inner(self) -> WasmDppResult<(PlatformAddress, Credits)> { + let amount = self.amount.ok_or_else(|| { + WasmDppError::invalid_argument("PlatformAddressOutput: amount is required") + })?; + Ok((self.address.into(), amount)) } /// Returns the inner values with optional amount. @@ -165,10 +164,11 @@ impl PlatformAddressOutputWasm { } /// Converts a vector of PlatformAddressOutput into a BTreeMap. +/// Returns an error if any output has no amount set. pub fn outputs_to_btree_map( outputs: Vec, -) -> BTreeMap { - outputs.into_iter().map(|o| o.into_inner()).collect() +) -> WasmDppResult> { + outputs.into_iter().map(|o| o.try_into_inner()).collect() } /// Converts a vector of PlatformAddressOutput into a BTreeMap with optional amounts. diff --git a/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs index 981599e001b..ff0881e9af7 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs @@ -184,13 +184,17 @@ impl AddressCreditWithdrawalTransitionWasm { } #[wasm_bindgen(setter = "output")] - pub fn set_output(&mut self, output: Option) { - let new_output = output.map(|o| o.into_inner()); + pub fn set_output( + &mut self, + output: Option, + ) -> WasmDppResult<()> { + let new_output = output.map(|o| o.try_into_inner()).transpose()?; match &mut self.0 { AddressCreditWithdrawalTransition::V0(v0) => { v0.output = new_output; } } + Ok(()) } #[wasm_bindgen(getter = "outputScript")] diff --git a/packages/wasm-dpp2/src/platform_address/transitions/address_funds_transfer_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/address_funds_transfer_transition.rs index a7e59ff0e94..df6418573c0 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/address_funds_transfer_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/address_funds_transfer_transition.rs @@ -80,7 +80,7 @@ impl AddressFundsTransferTransitionWasm { .unwrap_or(0); let inputs_map = inputs.into_iter().map(|i| i.into_inner()).collect(); - let outputs_map = outputs_to_btree_map(outputs); + let outputs_map = outputs_to_btree_map(outputs)?; let fee_strategy = fee_strategy_from_steps_or_default(fee_strategy); Ok(AddressFundsTransferTransitionWasm( @@ -167,13 +167,14 @@ impl AddressFundsTransferTransitionWasm { } #[wasm_bindgen(setter = "outputs")] - pub fn set_outputs(&mut self, outputs: Vec) { - let outputs_map = outputs_to_btree_map(outputs); + pub fn set_outputs(&mut self, outputs: Vec) -> WasmDppResult<()> { + let outputs_map = outputs_to_btree_map(outputs)?; match &mut self.0 { AddressFundsTransferTransition::V0(v0) => { v0.outputs = outputs_map; } } + Ok(()) } #[wasm_bindgen(getter = "userFeeIncrease")] diff --git a/packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs index 48e7988caf5..1a9d2a11189 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs @@ -95,7 +95,7 @@ impl IdentityCreditTransferToAddressesTransitionWasm { })? .unwrap_or(0); - let recipient_addresses = outputs_to_btree_map(recipient_outputs); + let recipient_addresses = outputs_to_btree_map(recipient_outputs)?; Ok(IdentityCreditTransferToAddressesTransitionWasm( IdentityCreditTransferToAddressesTransition::V0( @@ -166,9 +166,13 @@ impl IdentityCreditTransferToAddressesTransitionWasm { } #[wasm_bindgen(setter = "recipientAddresses")] - pub fn set_recipient_addresses(&mut self, outputs: Vec) { + pub fn set_recipient_addresses( + &mut self, + outputs: Vec, + ) -> WasmDppResult<()> { self.0 - .set_recipient_addresses(outputs_to_btree_map(outputs)); + .set_recipient_addresses(outputs_to_btree_map(outputs)?); + Ok(()) } #[wasm_bindgen(setter = "senderId")] From 4b7646f7e5748137841535dd0ea0fc1d3cb563a7 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Tue, 10 Mar 2026 21:07:53 +0700 Subject: [PATCH 06/15] fix(sdk): fix remaining into_inner() calls and missing trait import - Replace o.into_inner() with o.try_into_inner().transpose()? in constructors and set_output setters for address_credit_withdrawal, identity_top_up_from_addresses, and identity_create_from_addresses transitions (into_inner was removed in the prior commit) - Make set_output return WasmDppResult<()> in the two transitions that still had a void setter - Add missing StateTransitionHasUserFeeIncrease import in identity_credit_transfer_to_addresses_transition (required by user_fee_increase getter/setter method calls) - Remove unused StateTransitionLike import from the same file Co-Authored-By: Claude Sonnet 4.6 --- .../address_credit_withdrawal_transition.rs | 2 +- .../identity_create_from_addresses_transition.rs | 10 +++++++--- ...identity_credit_transfer_to_addresses_transition.rs | 2 +- .../identity_top_up_from_addresses_transition.rs | 10 +++++++--- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs index ff0881e9af7..94d1849dbfa 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs @@ -97,7 +97,7 @@ impl AddressCreditWithdrawalTransitionWasm { .unwrap_or(0); let inputs_map = inputs.into_iter().map(|i| i.into_inner()).collect(); - let output = output.map(|o| o.into_inner()); + let output = output.map(|o| o.try_into_inner()).transpose()?; let fee_strategy = fee_strategy_from_steps_or_default(fee_strategy); Ok(AddressCreditWithdrawalTransitionWasm( diff --git a/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs index 61770e8091f..fe5f77ad82a 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs @@ -90,7 +90,7 @@ impl IdentityCreateFromAddressesTransitionWasm { .unwrap_or(0); let inputs_map = inputs.into_iter().map(|i| i.into_inner()).collect(); - let output = output.map(|o| o.into_inner()); + let output = output.map(|o| o.try_into_inner()).transpose()?; let fee_strategy = fee_strategy_from_steps_or_default(fee_strategy); Ok(IdentityCreateFromAddressesTransitionWasm( @@ -204,13 +204,17 @@ impl IdentityCreateFromAddressesTransitionWasm { } #[wasm_bindgen(setter = "output")] - pub fn set_output(&mut self, output: Option) { - let new_output = output.map(|o| o.into_inner()); + pub fn set_output( + &mut self, + output: Option, + ) -> WasmDppResult<()> { + let new_output = output.map(|o| o.try_into_inner()).transpose()?; match &mut self.0 { IdentityCreateFromAddressesTransition::V0(v0) => { v0.output = new_output; } } + Ok(()) } #[wasm_bindgen(getter = "userFeeIncrease")] diff --git a/packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs index 1a9d2a11189..b644a3a5241 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs @@ -16,7 +16,7 @@ use dpp::state_transition::identity_credit_transfer_to_addresses_transition::Ide use dpp::state_transition::identity_credit_transfer_to_addresses_transition::accessors::IdentityCreditTransferToAddressesTransitionAccessorsV0; use dpp::state_transition::identity_credit_transfer_to_addresses_transition::v0::IdentityCreditTransferToAddressesTransitionV0; use dpp::state_transition::{ - StateTransition, StateTransitionIdentitySigned, StateTransitionLike, + StateTransition, StateTransitionHasUserFeeIncrease, StateTransitionIdentitySigned, StateTransitionSingleSigned, }; use wasm_bindgen::prelude::wasm_bindgen; diff --git a/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs index 8aae7f760cd..86ce63f9ca7 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs @@ -84,7 +84,7 @@ impl IdentityTopUpFromAddressesTransitionWasm { .unwrap_or(0); let inputs_map = inputs.into_iter().map(|i| i.into_inner()).collect(); - let output = output.map(|o| o.into_inner()); + let output = output.map(|o| o.try_into_inner()).transpose()?; let fee_strategy = fee_strategy_from_steps_or_default(fee_strategy); Ok(IdentityTopUpFromAddressesTransitionWasm( @@ -190,13 +190,17 @@ impl IdentityTopUpFromAddressesTransitionWasm { } #[wasm_bindgen(setter = "output")] - pub fn set_output(&mut self, output: Option) { - let new_output = output.map(|o| o.into_inner()); + pub fn set_output( + &mut self, + output: Option, + ) -> WasmDppResult<()> { + let new_output = output.map(|o| o.try_into_inner()).transpose()?; match &mut self.0 { IdentityTopUpFromAddressesTransition::V0(v0) => { v0.output = new_output; } } + Ok(()) } #[wasm_bindgen(getter = "userFeeIncrease")] From 97706f43e1a53a41d48c88547f0b88396d004de3 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Tue, 10 Mar 2026 21:16:23 +0700 Subject: [PATCH 07/15] style(sdk): collapse set_output signatures to single line per rustfmt Co-Authored-By: Claude Sonnet 4.6 --- .../transitions/address_credit_withdrawal_transition.rs | 5 +---- .../transitions/identity_create_from_addresses_transition.rs | 5 +---- .../transitions/identity_top_up_from_addresses_transition.rs | 5 +---- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs index 94d1849dbfa..dff0440e049 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs @@ -184,10 +184,7 @@ impl AddressCreditWithdrawalTransitionWasm { } #[wasm_bindgen(setter = "output")] - pub fn set_output( - &mut self, - output: Option, - ) -> WasmDppResult<()> { + pub fn set_output(&mut self, output: Option) -> WasmDppResult<()> { let new_output = output.map(|o| o.try_into_inner()).transpose()?; match &mut self.0 { AddressCreditWithdrawalTransition::V0(v0) => { diff --git a/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs index fe5f77ad82a..bb414c979ad 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs @@ -204,10 +204,7 @@ impl IdentityCreateFromAddressesTransitionWasm { } #[wasm_bindgen(setter = "output")] - pub fn set_output( - &mut self, - output: Option, - ) -> WasmDppResult<()> { + pub fn set_output(&mut self, output: Option) -> WasmDppResult<()> { let new_output = output.map(|o| o.try_into_inner()).transpose()?; match &mut self.0 { IdentityCreateFromAddressesTransition::V0(v0) => { diff --git a/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs index 86ce63f9ca7..cdaba4824cd 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs @@ -190,10 +190,7 @@ impl IdentityTopUpFromAddressesTransitionWasm { } #[wasm_bindgen(setter = "output")] - pub fn set_output( - &mut self, - output: Option, - ) -> WasmDppResult<()> { + pub fn set_output(&mut self, output: Option) -> WasmDppResult<()> { let new_output = output.map(|o| o.try_into_inner()).transpose()?; match &mut self.0 { IdentityTopUpFromAddressesTransition::V0(v0) => { From 6654d11a9609e4517ff3748b42818a2b6e75f130 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Tue, 10 Mar 2026 21:35:51 +0700 Subject: [PATCH 08/15] fix(wasm-sdk): propagate fallible outputs_to_btree_map result Update callers of outputs_to_btree_map and try_into_inner in wasm-sdk addresses to use ? operator after the change to fallible conversions. Co-Authored-By: Claude Sonnet 4.6 --- .../wasm-sdk/src/state_transitions/addresses.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/wasm-sdk/src/state_transitions/addresses.rs b/packages/wasm-sdk/src/state_transitions/addresses.rs index 7b4d5ac0595..a00720098bb 100644 --- a/packages/wasm-sdk/src/state_transitions/addresses.rs +++ b/packages/wasm-sdk/src/state_transitions/addresses.rs @@ -164,8 +164,8 @@ impl WasmSdk { let parsed = deserialize_transfer_options(options.into())?; // Convert inputs and outputs to maps - let inputs_map = outputs_to_btree_map(parsed.inputs); - let outputs_map = outputs_to_btree_map(parsed.outputs); + let inputs_map = outputs_to_btree_map(parsed.inputs)?; + let outputs_map = outputs_to_btree_map(parsed.outputs)?; // Convert fee strategy from input using wasm-dpp2 helper let fee_strategy = fee_strategy_from_steps_or_default(parsed.fee_strategy); @@ -292,7 +292,7 @@ impl WasmSdk { let parsed = deserialize_identity_top_up_options(options.into())?; // Convert inputs to map - let inputs_map = outputs_to_btree_map(parsed.inputs); + let inputs_map = outputs_to_btree_map(parsed.inputs)?; // Use the SDK's top_up_from_addresses method let (address_infos, new_balance) = identity @@ -436,10 +436,10 @@ impl WasmSdk { let parsed = deserialize_withdraw_options(options.into())?; // Convert inputs to map - let inputs_map = outputs_to_btree_map(parsed.inputs); + let inputs_map = outputs_to_btree_map(parsed.inputs)?; // Convert change output if provided - let change_output = parsed.change_output.map(|output| output.into_inner()); + let change_output = parsed.change_output.map(|output| output.try_into_inner()).transpose()?; // Convert fee strategy from input using wasm-dpp2 helper let fee_strategy = fee_strategy_from_steps_or_default(parsed.fee_strategy); @@ -490,7 +490,7 @@ impl WasmSdk { let parsed = deserialize_identity_transfer_options(options.into())?; // Convert outputs to map (recipient addresses with amounts) - let outputs_map = outputs_to_btree_map(parsed.outputs); + let outputs_map = outputs_to_btree_map(parsed.outputs)?; // Get the signing key if a specific key ID was requested use dash_sdk::dpp::identity::accessors::IdentityGettersV0; @@ -901,11 +901,11 @@ impl WasmSdk { let parsed = deserialize_identity_create_options(options.into())?; // Convert inputs to map (address -> amount) - let inputs_map = outputs_to_btree_map(parsed.inputs); + let inputs_map = outputs_to_btree_map(parsed.inputs)?; // Extend inputs with nonces let inputs = fetch_nonces_into_address_map(self.inner_sdk(), inputs_map).await?; // Convert change output if provided - let change_output = parsed.change_output.map(|output| output.into_inner()); + let change_output = parsed.change_output.map(|output| output.try_into_inner()).transpose()?; // Use the SDK's put_with_address_funding method let (created_identity, address_infos) = identity From f3088f655233c3893b6bd34b905823810254cf17 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Tue, 10 Mar 2026 21:42:42 +0700 Subject: [PATCH 09/15] style(wasm-sdk): apply rustfmt to addresses.rs Co-Authored-By: Claude Sonnet 4.6 --- packages/wasm-sdk/src/state_transitions/addresses.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/wasm-sdk/src/state_transitions/addresses.rs b/packages/wasm-sdk/src/state_transitions/addresses.rs index a00720098bb..fc2816e8f88 100644 --- a/packages/wasm-sdk/src/state_transitions/addresses.rs +++ b/packages/wasm-sdk/src/state_transitions/addresses.rs @@ -439,7 +439,10 @@ impl WasmSdk { let inputs_map = outputs_to_btree_map(parsed.inputs)?; // Convert change output if provided - let change_output = parsed.change_output.map(|output| output.try_into_inner()).transpose()?; + let change_output = parsed + .change_output + .map(|output| output.try_into_inner()) + .transpose()?; // Convert fee strategy from input using wasm-dpp2 helper let fee_strategy = fee_strategy_from_steps_or_default(parsed.fee_strategy); @@ -905,7 +908,10 @@ impl WasmSdk { // Extend inputs with nonces let inputs = fetch_nonces_into_address_map(self.inner_sdk(), inputs_map).await?; // Convert change output if provided - let change_output = parsed.change_output.map(|output| output.try_into_inner()).transpose()?; + let change_output = parsed + .change_output + .map(|output| output.try_into_inner()) + .transpose()?; // Use the SDK's put_with_address_funding method let (created_identity, address_infos) = identity From c76f25d86a892626d989325330bdb4b45035eb82 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Tue, 10 Mar 2026 21:51:56 +0700 Subject: [PATCH 10/15] refactor(wasm-dpp2): simplify inputs/outputs_from_js_options using try_from_options_with Replace manual Reflect::get + null/array checks with try_from_options_with + try_to_array. Co-Authored-By: Claude Sonnet 4.6 --- .../src/platform_address/input_output.rs | 36 ++----------------- 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/packages/wasm-dpp2/src/platform_address/input_output.rs b/packages/wasm-dpp2/src/platform_address/input_output.rs index 2a4613300ff..cb9e1db7906 100644 --- a/packages/wasm-dpp2/src/platform_address/input_output.rs +++ b/packages/wasm-dpp2/src/platform_address/input_output.rs @@ -1,7 +1,7 @@ use super::{PlatformAddressLikeJs, PlatformAddressWasm}; use crate::error::{WasmDppError, WasmDppResult}; use crate::impl_wasm_type_info; -use crate::utils::{IntoWasm, try_to_u64}; +use crate::utils::{IntoWasm, try_from_options_with, try_to_array, try_to_u64}; use dpp::address_funds::PlatformAddress; use dpp::fee::Credits; use dpp::prelude::AddressNonce; @@ -192,22 +192,7 @@ pub fn inputs_from_js_options( options: &JsValue, field_name: &str, ) -> WasmDppResult> { - let value = js_sys::Reflect::get(options, &JsValue::from_str(field_name)).map_err(|_| { - WasmDppError::invalid_argument(format!("failed to read '{}' from options", field_name)) - })?; - if value.is_undefined() || value.is_null() { - return Err(WasmDppError::invalid_argument(format!( - "'{}' is required", - field_name - ))); - } - if !js_sys::Array::is_array(&value) { - return Err(WasmDppError::invalid_argument(format!( - "'{}' must be an array", - field_name - ))); - } - let array = js_sys::Array::from(&value); + let array = try_from_options_with(options, field_name, |v| try_to_array(v, field_name))?; array .iter() .enumerate() @@ -232,22 +217,7 @@ pub fn outputs_from_js_options( options: &JsValue, field_name: &str, ) -> WasmDppResult> { - let value = js_sys::Reflect::get(options, &JsValue::from_str(field_name)).map_err(|_| { - WasmDppError::invalid_argument(format!("failed to read '{}' from options", field_name)) - })?; - if value.is_undefined() || value.is_null() { - return Err(WasmDppError::invalid_argument(format!( - "'{}' is required", - field_name - ))); - } - if !js_sys::Array::is_array(&value) { - return Err(WasmDppError::invalid_argument(format!( - "'{}' must be an array", - field_name - ))); - } - let array = js_sys::Array::from(&value); + let array = try_from_options_with(options, field_name, |v| try_to_array(v, field_name))?; array .iter() .enumerate() From d2a6aa917f6a5737e7ebacd7d3d6f82b62872447 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Tue, 10 Mar 2026 22:02:44 +0700 Subject: [PATCH 11/15] refactor(wasm-dpp2): simplify optional_output_from_js_options using try_from_options_optional_with Co-Authored-By: Claude Sonnet 4.6 --- .../src/platform_address/input_output.rs | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/packages/wasm-dpp2/src/platform_address/input_output.rs b/packages/wasm-dpp2/src/platform_address/input_output.rs index cb9e1db7906..7356bc73173 100644 --- a/packages/wasm-dpp2/src/platform_address/input_output.rs +++ b/packages/wasm-dpp2/src/platform_address/input_output.rs @@ -1,7 +1,9 @@ use super::{PlatformAddressLikeJs, PlatformAddressWasm}; use crate::error::{WasmDppError, WasmDppResult}; use crate::impl_wasm_type_info; -use crate::utils::{IntoWasm, try_from_options_with, try_to_array, try_to_u64}; +use crate::utils::{ + IntoWasm, try_from_options_optional_with, try_from_options_with, try_to_array, try_to_u64, +}; use dpp::address_funds::PlatformAddress; use dpp::fee::Credits; use dpp::prelude::AddressNonce; @@ -241,19 +243,14 @@ pub fn optional_output_from_js_options( options: &JsValue, field_name: &str, ) -> WasmDppResult> { - let value = js_sys::Reflect::get(options, &JsValue::from_str(field_name)).map_err(|_| { - WasmDppError::invalid_argument(format!("failed to read '{}' from options", field_name)) - })?; - if value.is_undefined() || value.is_null() { - return Ok(None); - } - value - .to_wasm::("PlatformAddressOutput") - .map(|r| Some((*r).clone())) - .map_err(|_| { - WasmDppError::invalid_argument(format!( - "'{}' is not a PlatformAddressOutput", - field_name - )) - }) + try_from_options_optional_with(options, field_name, |v| { + v.to_wasm::("PlatformAddressOutput") + .map(|r| (*r).clone()) + .map_err(|_| { + WasmDppError::invalid_argument(format!( + "'{}' is not a PlatformAddressOutput", + field_name + )) + }) + }) } From c2cc43f50680dfd77b4e3df045b68b45e4ad77b3 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Tue, 10 Mar 2026 22:05:17 +0700 Subject: [PATCH 12/15] refactor(wasm-dpp2): use try_from_options_optional directly for optional_output_from_js_options Co-Authored-By: Claude Sonnet 4.6 --- .../wasm-dpp2/src/platform_address/input_output.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/wasm-dpp2/src/platform_address/input_output.rs b/packages/wasm-dpp2/src/platform_address/input_output.rs index 7356bc73173..9ac4bb41a9e 100644 --- a/packages/wasm-dpp2/src/platform_address/input_output.rs +++ b/packages/wasm-dpp2/src/platform_address/input_output.rs @@ -2,7 +2,7 @@ use super::{PlatformAddressLikeJs, PlatformAddressWasm}; use crate::error::{WasmDppError, WasmDppResult}; use crate::impl_wasm_type_info; use crate::utils::{ - IntoWasm, try_from_options_optional_with, try_from_options_with, try_to_array, try_to_u64, + IntoWasm, try_from_options_optional, try_from_options_with, try_to_array, try_to_u64, }; use dpp::address_funds::PlatformAddress; use dpp::fee::Credits; @@ -243,14 +243,5 @@ pub fn optional_output_from_js_options( options: &JsValue, field_name: &str, ) -> WasmDppResult> { - try_from_options_optional_with(options, field_name, |v| { - v.to_wasm::("PlatformAddressOutput") - .map(|r| (*r).clone()) - .map_err(|_| { - WasmDppError::invalid_argument(format!( - "'{}' is not a PlatformAddressOutput", - field_name - )) - }) - }) + try_from_options_optional(options, field_name) } From 801f9519696d2a8f916ddff988f50b0bfdebaee4 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Tue, 10 Mar 2026 22:11:53 +0700 Subject: [PATCH 13/15] refactor(wasm-dpp2): implement TryFrom<&JsValue> for PlatformAddressOutputWasm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove optional_output_from_js_options wrapper — callers use try_from_options_optional directly now that PlatformAddressOutputWasm implements TryFrom<&JsValue> via impl_try_from_js_value!. Co-Authored-By: Claude Sonnet 4.6 --- .../src/platform_address/input_output.rs | 16 +++------------- packages/wasm-dpp2/src/platform_address/mod.rs | 3 +-- .../address_credit_withdrawal_transition.rs | 8 +++++--- .../identity_create_from_addresses_transition.rs | 8 +++++--- .../identity_top_up_from_addresses_transition.rs | 7 ++++--- 5 files changed, 18 insertions(+), 24 deletions(-) diff --git a/packages/wasm-dpp2/src/platform_address/input_output.rs b/packages/wasm-dpp2/src/platform_address/input_output.rs index 9ac4bb41a9e..635bca6f5a7 100644 --- a/packages/wasm-dpp2/src/platform_address/input_output.rs +++ b/packages/wasm-dpp2/src/platform_address/input_output.rs @@ -1,9 +1,8 @@ use super::{PlatformAddressLikeJs, PlatformAddressWasm}; use crate::error::{WasmDppError, WasmDppResult}; +use crate::impl_try_from_js_value; use crate::impl_wasm_type_info; -use crate::utils::{ - IntoWasm, try_from_options_optional, try_from_options_with, try_to_array, try_to_u64, -}; +use crate::utils::{IntoWasm, try_from_options_with, try_to_array, try_to_u64}; use dpp::address_funds::PlatformAddress; use dpp::fee::Credits; use dpp::prelude::AddressNonce; @@ -100,6 +99,7 @@ pub struct PlatformAddressOutputWasm { } impl_wasm_type_info!(PlatformAddressOutputWasm, PlatformAddressOutput); +impl_try_from_js_value!(PlatformAddressOutputWasm, "PlatformAddressOutput"); #[wasm_bindgen(js_class = PlatformAddressOutput)] impl PlatformAddressOutputWasm { @@ -235,13 +235,3 @@ pub fn outputs_from_js_options( }) .collect() } - -/// Extract an optional PlatformAddressOutputWasm from a JS options object property. -/// -/// Returns None if the property is undefined or null. -pub fn optional_output_from_js_options( - options: &JsValue, - field_name: &str, -) -> WasmDppResult> { - try_from_options_optional(options, field_name) -} diff --git a/packages/wasm-dpp2/src/platform_address/mod.rs b/packages/wasm-dpp2/src/platform_address/mod.rs index 0308f9a5cb0..3808b2a15ef 100644 --- a/packages/wasm-dpp2/src/platform_address/mod.rs +++ b/packages/wasm-dpp2/src/platform_address/mod.rs @@ -11,7 +11,6 @@ pub use fee_strategy::{ }; pub use input_output::{ PlatformAddressInputWasm, PlatformAddressOutputWasm, inputs_from_js_options, - optional_output_from_js_options, outputs_from_js_options, outputs_to_btree_map, - outputs_to_optional_btree_map, + outputs_from_js_options, outputs_to_btree_map, outputs_to_optional_btree_map, }; pub use signer::PlatformAddressSignerWasm; diff --git a/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs index dff0440e049..e3ffb7cb627 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs @@ -5,11 +5,12 @@ use crate::impl_wasm_conversions; use crate::impl_wasm_type_info; use crate::platform_address::{ PlatformAddressInputWasm, PlatformAddressOutputWasm, fee_strategy_from_js_options, - fee_strategy_from_steps_or_default, inputs_from_js_options, optional_output_from_js_options, + fee_strategy_from_steps_or_default, inputs_from_js_options, }; use crate::state_transitions::StateTransitionWasm; use crate::utils::{ - try_from_options, try_from_options_optional_with, try_from_options_with, try_to_u16, try_to_u32, + try_from_options, try_from_options_optional, try_from_options_optional_with, + try_from_options_with, try_to_u16, try_to_u32, }; use dpp::platform_value::string_encoding::Encoding::{Base64, Hex}; use dpp::platform_value::string_encoding::{decode, encode}; @@ -83,7 +84,8 @@ impl AddressCreditWithdrawalTransitionWasm { let output_script: CoreScriptWasm = try_from_options(&options, "outputScript")?; let pooling: PoolingWasm = PoolingWasm::try_from_options(&options, "pooling")?; let inputs = inputs_from_js_options(js_opts, "inputs")?; - let output = optional_output_from_js_options(js_opts, "output")?; + let output: Option = + try_from_options_optional(js_opts, "output")?; // Extract simple fields let fee_strategy = fee_strategy_from_js_options(js_opts, "feeStrategy")?; diff --git a/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs index bb414c979ad..c6493616008 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs @@ -4,11 +4,12 @@ use crate::impl_wasm_conversions; use crate::impl_wasm_type_info; use crate::platform_address::{ PlatformAddressInputWasm, PlatformAddressOutputWasm, fee_strategy_from_js_options, - fee_strategy_from_steps_or_default, inputs_from_js_options, optional_output_from_js_options, + fee_strategy_from_steps_or_default, inputs_from_js_options, }; use crate::state_transitions::StateTransitionWasm; use crate::utils::{ - try_from_options_optional_with, try_from_options_with, try_to_array, try_to_u16, + try_from_options_optional, try_from_options_optional_with, try_from_options_with, try_to_array, + try_to_u16, }; use dpp::platform_value::string_encoding::Encoding::{Base64, Hex}; use dpp::platform_value::string_encoding::{decode, encode}; @@ -79,7 +80,8 @@ impl IdentityCreateFromAddressesTransitionWasm { let public_keys: Vec = IdentityPublicKeyInCreationWasm::vec_from_array(&js_public_keys_array)?; let inputs = inputs_from_js_options(js_opts, "inputs")?; - let output = optional_output_from_js_options(js_opts, "output")?; + let output: Option = + try_from_options_optional(js_opts, "output")?; // Extract simple fields let fee_strategy = fee_strategy_from_js_options(js_opts, "feeStrategy")?; diff --git a/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs b/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs index cdaba4824cd..3fb480cdc9e 100644 --- a/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs +++ b/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs @@ -4,10 +4,10 @@ use crate::impl_wasm_conversions; use crate::impl_wasm_type_info; use crate::platform_address::{ PlatformAddressInputWasm, PlatformAddressOutputWasm, fee_strategy_from_js_options, - fee_strategy_from_steps_or_default, inputs_from_js_options, optional_output_from_js_options, + fee_strategy_from_steps_or_default, inputs_from_js_options, }; use crate::state_transitions::StateTransitionWasm; -use crate::utils::{try_from_options_optional_with, try_to_u16}; +use crate::utils::{try_from_options_optional, try_from_options_optional_with, try_to_u16}; use dpp::platform_value::string_encoding::Encoding::{Base64, Hex}; use dpp::platform_value::string_encoding::{decode, encode}; use dpp::prelude::UserFeeIncrease; @@ -73,7 +73,8 @@ impl IdentityTopUpFromAddressesTransitionWasm { // Extract complex wasm-bindgen types manually let identity_id: IdentifierWasm = crate::utils::try_from_options(&options, "identityId")?; let inputs = inputs_from_js_options(js_opts, "inputs")?; - let output = optional_output_from_js_options(js_opts, "output")?; + let output: Option = + try_from_options_optional(js_opts, "output")?; // Extract simple fields let fee_strategy = fee_strategy_from_js_options(js_opts, "feeStrategy")?; From 7b1f516146cb3d1dab78e1c582e2fc5994e7823b Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Wed, 11 Mar 2026 09:10:33 +0700 Subject: [PATCH 14/15] fix(wasm-dpp2): fix ESLint errors in transition spec files Apply object-shorthand and prefer-destructuring rules. Co-Authored-By: Claude Sonnet 4.6 --- .../tests/unit/AddressCreditWithdrawalTransition.spec.ts | 2 +- .../unit/IdentityCreateFromAddressesTransition.spec.ts | 8 ++++---- .../unit/IdentityTopUpFromAddressesTransition.spec.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/wasm-dpp2/tests/unit/AddressCreditWithdrawalTransition.spec.ts b/packages/wasm-dpp2/tests/unit/AddressCreditWithdrawalTransition.spec.ts index abdf99d1c06..7f9b230a3de 100644 --- a/packages/wasm-dpp2/tests/unit/AddressCreditWithdrawalTransition.spec.ts +++ b/packages/wasm-dpp2/tests/unit/AddressCreditWithdrawalTransition.spec.ts @@ -25,7 +25,7 @@ describe('AddressCreditWithdrawalTransition', () => { return new wasm.AddressCreditWithdrawalTransition({ inputs: [input], - output: output, + output, outputScript: script, pooling: 'never', coreFeePerByte: 1, diff --git a/packages/wasm-dpp2/tests/unit/IdentityCreateFromAddressesTransition.spec.ts b/packages/wasm-dpp2/tests/unit/IdentityCreateFromAddressesTransition.spec.ts index 676dfde11d9..2de48feba78 100644 --- a/packages/wasm-dpp2/tests/unit/IdentityCreateFromAddressesTransition.spec.ts +++ b/packages/wasm-dpp2/tests/unit/IdentityCreateFromAddressesTransition.spec.ts @@ -39,7 +39,7 @@ describe('IdentityCreateFromAddressesTransition', () => { return new wasm.IdentityCreateFromAddressesTransition({ publicKeys: [pk], inputs: [input], - output: output, + output, }); } @@ -124,7 +124,7 @@ describe('IdentityCreateFromAddressesTransition', () => { describe('inputs', () => { it('should return inputs array', () => { const transition = createTransition(); - const inputs = transition.inputs; + const { inputs } = transition; expect(inputs).to.be.an('array'); expect(inputs).to.have.lengthOf(1); expect(inputs[0].nonce).to.equal(0); @@ -137,7 +137,7 @@ describe('IdentityCreateFromAddressesTransition', () => { const newInput = new wasm.PlatformAddressInput(newAddr, 3, BigInt(50000)); transition.inputs = [newInput]; - const inputs = transition.inputs; + const { inputs } = transition; expect(inputs).to.have.lengthOf(1); expect(inputs[0].nonce).to.equal(3); }); @@ -146,7 +146,7 @@ describe('IdentityCreateFromAddressesTransition', () => { describe('output', () => { it('should return output', () => { const transition = createTransition(); - const output = transition.output; + const { output } = transition; expect(output).to.exist(); expect(output.amount).to.equal(BigInt(90000)); }); diff --git a/packages/wasm-dpp2/tests/unit/IdentityTopUpFromAddressesTransition.spec.ts b/packages/wasm-dpp2/tests/unit/IdentityTopUpFromAddressesTransition.spec.ts index be51d704ce1..e891295cbcd 100644 --- a/packages/wasm-dpp2/tests/unit/IdentityTopUpFromAddressesTransition.spec.ts +++ b/packages/wasm-dpp2/tests/unit/IdentityTopUpFromAddressesTransition.spec.ts @@ -23,7 +23,7 @@ describe('IdentityTopUpFromAddressesTransition', () => { return new wasm.IdentityTopUpFromAddressesTransition({ identityId: '11111111111111111111111111111111', inputs: [input], - output: output, + output, }); } From 7cf9cc95a71dcf540264f77c250a0d3d7bf4764d Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Wed, 11 Mar 2026 10:02:20 +0700 Subject: [PATCH 15/15] fix(wasm-dpp2): use object destructuring in address transition tests Co-Authored-By: Claude Sonnet 4.6 --- .../tests/unit/AddressCreditWithdrawalTransition.spec.ts | 6 +++--- .../unit/AddressFundingFromAssetLockTransition.spec.ts | 8 ++++---- .../tests/unit/AddressFundsTransferTransition.spec.ts | 8 ++++---- .../unit/IdentityTopUpFromAddressesTransition.spec.ts | 6 +++--- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/wasm-dpp2/tests/unit/AddressCreditWithdrawalTransition.spec.ts b/packages/wasm-dpp2/tests/unit/AddressCreditWithdrawalTransition.spec.ts index 7f9b230a3de..e8815b4ab21 100644 --- a/packages/wasm-dpp2/tests/unit/AddressCreditWithdrawalTransition.spec.ts +++ b/packages/wasm-dpp2/tests/unit/AddressCreditWithdrawalTransition.spec.ts @@ -99,7 +99,7 @@ describe('AddressCreditWithdrawalTransition', () => { describe('inputs', () => { it('should return inputs array', () => { const transition = createTransition(); - const inputs = transition.inputs; + const { inputs } = transition; expect(inputs).to.be.an('array'); expect(inputs).to.have.lengthOf(1); expect(inputs[0].nonce).to.equal(0); @@ -112,7 +112,7 @@ describe('AddressCreditWithdrawalTransition', () => { const newInput = new wasm.PlatformAddressInput(newAddr, 5, BigInt(50000)); transition.inputs = [newInput]; - const inputs = transition.inputs; + const { inputs } = transition; expect(inputs).to.have.lengthOf(1); expect(inputs[0].nonce).to.equal(5); }); @@ -121,7 +121,7 @@ describe('AddressCreditWithdrawalTransition', () => { describe('output', () => { it('should return output', () => { const transition = createTransition(); - const output = transition.output; + const { output } = transition; expect(output).to.exist(); expect(output.amount).to.equal(BigInt(90000)); }); diff --git a/packages/wasm-dpp2/tests/unit/AddressFundingFromAssetLockTransition.spec.ts b/packages/wasm-dpp2/tests/unit/AddressFundingFromAssetLockTransition.spec.ts index a2d8288ddf2..af62d43feeb 100644 --- a/packages/wasm-dpp2/tests/unit/AddressFundingFromAssetLockTransition.spec.ts +++ b/packages/wasm-dpp2/tests/unit/AddressFundingFromAssetLockTransition.spec.ts @@ -134,7 +134,7 @@ describe('AddressFundingFromAssetLockTransition', () => { describe('inputs', () => { it('should return inputs array', () => { const transition = createTransition(); - const inputs = transition.inputs; + const { inputs } = transition; expect(inputs).to.be.an('array'); expect(inputs).to.have.lengthOf(1); expect(inputs[0].nonce).to.equal(0); @@ -147,7 +147,7 @@ describe('AddressFundingFromAssetLockTransition', () => { const newInput = new wasm.PlatformAddressInput(newAddr, 3, BigInt(50000)); transition.inputs = [newInput]; - const inputs = transition.inputs; + const { inputs } = transition; expect(inputs).to.have.lengthOf(1); expect(inputs[0].nonce).to.equal(3); }); @@ -156,7 +156,7 @@ describe('AddressFundingFromAssetLockTransition', () => { describe('outputs', () => { it('should return outputs array', () => { const transition = createTransition(); - const outputs = transition.outputs; + const { outputs } = transition; expect(outputs).to.be.an('array'); expect(outputs).to.have.lengthOf(1); }); @@ -167,7 +167,7 @@ describe('AddressFundingFromAssetLockTransition', () => { const newOutput = new wasm.PlatformAddressOutput(newAddr, BigInt(50000)); transition.outputs = [newOutput]; - const outputs = transition.outputs; + const { outputs } = transition; expect(outputs).to.have.lengthOf(1); }); }); diff --git a/packages/wasm-dpp2/tests/unit/AddressFundsTransferTransition.spec.ts b/packages/wasm-dpp2/tests/unit/AddressFundsTransferTransition.spec.ts index 747a378a1d4..510cd160b88 100644 --- a/packages/wasm-dpp2/tests/unit/AddressFundsTransferTransition.spec.ts +++ b/packages/wasm-dpp2/tests/unit/AddressFundsTransferTransition.spec.ts @@ -102,7 +102,7 @@ describe('AddressFundsTransferTransition', () => { describe('inputs', () => { it('should return inputs array', () => { const transition = createTransition(); - const inputs = transition.inputs; + const { inputs } = transition; expect(inputs).to.be.an('array'); expect(inputs).to.have.lengthOf(1); expect(inputs[0].nonce).to.equal(0); @@ -115,7 +115,7 @@ describe('AddressFundsTransferTransition', () => { const newInput = new wasm.PlatformAddressInput(newAddr, 5, BigInt(50000)); transition.inputs = [newInput]; - const inputs = transition.inputs; + const { inputs } = transition; expect(inputs).to.have.lengthOf(1); expect(inputs[0].nonce).to.equal(5); expect(inputs[0].amount).to.equal(BigInt(50000)); @@ -125,7 +125,7 @@ describe('AddressFundsTransferTransition', () => { describe('outputs', () => { it('should return outputs array', () => { const transition = createTransition(); - const outputs = transition.outputs; + const { outputs } = transition; expect(outputs).to.be.an('array'); expect(outputs).to.have.lengthOf(1); expect(outputs[0].amount).to.equal(BigInt(90000)); @@ -137,7 +137,7 @@ describe('AddressFundsTransferTransition', () => { const newOutput = new wasm.PlatformAddressOutput(newAddr, BigInt(80000)); transition.outputs = [newOutput]; - const outputs = transition.outputs; + const { outputs } = transition; expect(outputs).to.have.lengthOf(1); expect(outputs[0].amount).to.equal(BigInt(80000)); }); diff --git a/packages/wasm-dpp2/tests/unit/IdentityTopUpFromAddressesTransition.spec.ts b/packages/wasm-dpp2/tests/unit/IdentityTopUpFromAddressesTransition.spec.ts index e891295cbcd..40cb18eab1f 100644 --- a/packages/wasm-dpp2/tests/unit/IdentityTopUpFromAddressesTransition.spec.ts +++ b/packages/wasm-dpp2/tests/unit/IdentityTopUpFromAddressesTransition.spec.ts @@ -117,7 +117,7 @@ describe('IdentityTopUpFromAddressesTransition', () => { describe('inputs', () => { it('should return inputs array', () => { const transition = createTransition(); - const inputs = transition.inputs; + const { inputs } = transition; expect(inputs).to.be.an('array'); expect(inputs).to.have.lengthOf(1); expect(inputs[0].nonce).to.equal(0); @@ -130,7 +130,7 @@ describe('IdentityTopUpFromAddressesTransition', () => { const newInput = new wasm.PlatformAddressInput(newAddr, 7, BigInt(200000)); transition.inputs = [newInput]; - const inputs = transition.inputs; + const { inputs } = transition; expect(inputs).to.have.lengthOf(1); expect(inputs[0].nonce).to.equal(7); }); @@ -139,7 +139,7 @@ describe('IdentityTopUpFromAddressesTransition', () => { describe('output', () => { it('should return output', () => { const transition = createTransition(); - const output = transition.output; + const { output } = transition; expect(output).to.exist(); expect(output.amount).to.equal(BigInt(90000)); });