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 bf24d4348d0..b4728e243e1 100644 --- a/packages/wasm-dpp2/src/identity/transitions/create_transition.rs +++ b/packages/wasm-dpp2/src/identity/transitions/create_transition.rs @@ -21,7 +21,6 @@ use dpp::state_transition::{ StateTransition, StateTransitionHasUserFeeIncrease, StateTransitionSingleSigned, }; use serde::Deserialize; -use wasm_bindgen::JsValue; use wasm_bindgen::prelude::wasm_bindgen; #[derive(Deserialize)] @@ -209,9 +208,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 06e342d3039..74b53bddc08 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,7 +253,7 @@ 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<()> { // MasternodeVoteTransition no longer supports user fee increase; no-op. Ok(()) } diff --git a/packages/wasm-dpp2/src/identity/transitions/update_transition.rs b/packages/wasm-dpp2/src/identity/transitions/update_transition.rs index 348bd1dca48..9c9794bbb05 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::{ StateTransitionLike, 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/lib.rs b/packages/wasm-dpp2/src/lib.rs index 845706a0cf2..8ff7050bff0 100644 --- a/packages/wasm-dpp2/src/lib.rs +++ b/packages/wasm-dpp2/src/lib.rs @@ -55,6 +55,11 @@ 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, 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..635bca6f5a7 100644 --- a/packages/wasm-dpp2/src/platform_address/input_output.rs +++ b/packages/wasm-dpp2/src/platform_address/input_output.rs @@ -1,6 +1,8 @@ use super::{PlatformAddressLikeJs, PlatformAddressWasm}; -use crate::error::WasmDppResult; -use crate::utils::try_to_u64; +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_with, try_to_array, try_to_u64}; use dpp::address_funds::PlatformAddress; use dpp::fee::Credits; use dpp::prelude::AddressNonce; @@ -22,6 +24,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 +69,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 +98,9 @@ pub struct PlatformAddressOutputWasm { amount: Option, } +impl_wasm_type_info!(PlatformAddressOutputWasm, PlatformAddressOutput); +impl_try_from_js_value!(PlatformAddressOutputWasm, "PlatformAddressOutput"); + #[wasm_bindgen(js_class = PlatformAddressOutput)] impl PlatformAddressOutputWasm { /// Creates a new PlatformAddressOutput with a specific amount. @@ -122,13 +137,26 @@ impl PlatformAddressOutputWasm { } 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"), - ) + 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, 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. @@ -138,10 +166,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. @@ -156,3 +185,53 @@ 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 array = try_from_options_with(options, field_name, |v| try_to_array(v, field_name))?; + 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 array = try_from_options_with(options, field_name, |v| try_to_array(v, field_name))?; + 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() +} diff --git a/packages/wasm-dpp2/src/platform_address/mod.rs b/packages/wasm-dpp2/src/platform_address/mod.rs index 21e528da0b9..3808b2a15ef 100644 --- a/packages/wasm-dpp2/src/platform_address/mod.rs +++ b/packages/wasm-dpp2/src/platform_address/mod.rs @@ -2,14 +2,15 @@ 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, - outputs_to_optional_btree_map, + PlatformAddressInputWasm, PlatformAddressOutputWasm, inputs_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..e3ffb7cb627 --- /dev/null +++ b/packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs @@ -0,0 +1,304 @@ +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, +}; +use crate::state_transitions::StateTransitionWasm; +use crate::utils::{ + 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}; +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: Option = + try_from_options_optional(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.try_into_inner()).transpose()?; + 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: 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")] + 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: &CoreScriptWasm) { + match &mut self.0 { + AddressCreditWithdrawalTransition::V0(v0) => { + v0.output_script = script.clone().into(); + } + } + } + + #[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..2d7db57b191 --- /dev/null +++ b/packages/wasm-dpp2/src/platform_address/transitions/address_funding_from_asset_lock_transition.rs @@ -0,0 +1,247 @@ +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::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 wasm_bindgen::JsValue; +use wasm_bindgen::prelude::wasm_bindgen; + +#[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..df6418573c0 --- /dev/null +++ b/packages/wasm-dpp2/src/platform_address/transitions/address_funds_transfer_transition.rs @@ -0,0 +1,229 @@ +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::StateTransition; +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#" +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) -> 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")] + 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..c6493616008 --- /dev/null +++ b/packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs @@ -0,0 +1,270 @@ +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, +}; +use crate::state_transitions::StateTransitionWasm; +use crate::utils::{ + 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}; +use dpp::prelude::UserFeeIncrease; +use dpp::serialization::{PlatformDeserializable, PlatformSerializable}; +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 wasm_bindgen::JsValue; +use wasm_bindgen::prelude::wasm_bindgen; + +#[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: Option = + try_from_options_optional(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.try_into_inner()).transpose()?; + 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: 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")] + 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..b644a3a5241 --- /dev/null +++ b/packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs @@ -0,0 +1,275 @@ +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::{ + 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; +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, StateTransitionHasUserFeeIncrease, StateTransitionIdentitySigned, + 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, + ) -> WasmDppResult<()> { + self.0 + .set_recipient_addresses(outputs_to_btree_map(outputs)?); + Ok(()) + } + + #[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..3fb480cdc9e --- /dev/null +++ b/packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs @@ -0,0 +1,255 @@ +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, +}; +use crate::state_transitions::StateTransitionWasm; +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; +use dpp::serialization::{PlatformDeserializable, PlatformSerializable}; +use dpp::state_transition::StateTransition; +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#" +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: Option = + try_from_options_optional(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.try_into_inner()).transpose()?; + 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: 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")] + 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..cc6a60232fd --- /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_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; 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 ac29a07750d..5c7625f979c 100644 --- a/packages/wasm-dpp2/src/state_transitions/base/state_transition.rs +++ b/packages/wasm-dpp2/src/state_transitions/base/state_transition.rs @@ -579,9 +579,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(_) => { @@ -654,9 +654,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(()) } 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..e8815b4ab21 --- /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, + 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; + 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; + 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; + 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..af62d43feeb --- /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; + 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; + 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; + 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; + 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..510cd160b88 --- /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; + 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; + 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; + 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; + 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..2de48feba78 --- /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, + }); + } + + 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; + 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; + 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; + 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..40cb18eab1f --- /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, + }); + } + + 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; + 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; + 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; + 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()), + ); + }); + }); +}); diff --git a/packages/wasm-sdk/src/state_transitions/addresses.rs b/packages/wasm-sdk/src/state_transitions/addresses.rs index 7b4d5ac0595..fc2816e8f88 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,13 @@ 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 +493,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 +904,14 @@ 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