Skip to content

Commit b3bd9ed

Browse files
shumkovclaude
andauthored
feat(sdk): add platform address transition WASM bindings (#3147)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5953d17 commit b3bd9ed

38 files changed

Lines changed: 2946 additions & 82 deletions

‎packages/wasm-dpp2/src/data_contract/model.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -460,8 +460,8 @@ impl DataContractWasm {
460460
}
461461

462462
#[wasm_bindgen(setter = "version")]
463-
pub fn set_version(&mut self, version: JsValue) -> WasmDppResult<()> {
464-
self.0.set_version(try_to_u32(&version, "version")?);
463+
pub fn set_version(&mut self, version: &js_sys::Number) -> WasmDppResult<()> {
464+
self.0.set_version(try_to_u32(version, "version")?);
465465
Ok(())
466466
}
467467

‎packages/wasm-dpp2/src/identity/model.rs‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use dpp::platform_value::string_encoding::{decode, encode};
1414
use dpp::prelude::Identifier;
1515
use dpp::serialization::{PlatformDeserializable, PlatformSerializable, ValueConvertible};
1616
use dpp::version::{PlatformVersion, TryFromPlatformVersioned};
17-
use wasm_bindgen::JsValue;
1817
use wasm_bindgen::prelude::wasm_bindgen;
1918

2019
#[wasm_bindgen(typescript_custom_section)]
@@ -86,14 +85,14 @@ impl IdentityWasm {
8685
}
8786

8887
#[wasm_bindgen(setter = "balance")]
89-
pub fn set_balance(&mut self, balance: JsValue) -> WasmDppResult<()> {
90-
self.0.set_balance(try_to_u64(&balance, "balance")?);
88+
pub fn set_balance(&mut self, balance: &js_sys::BigInt) -> WasmDppResult<()> {
89+
self.0.set_balance(try_to_u64(balance, "balance")?);
9190
Ok(())
9291
}
9392

9493
#[wasm_bindgen(setter = "revision")]
95-
pub fn set_revision(&mut self, revision: JsValue) -> WasmDppResult<()> {
96-
self.0.set_revision(try_to_u64(&revision, "revision")?);
94+
pub fn set_revision(&mut self, revision: &js_sys::BigInt) -> WasmDppResult<()> {
95+
self.0.set_revision(try_to_u64(revision, "revision")?);
9796
Ok(())
9897
}
9998

‎packages/wasm-dpp2/src/identity/transitions/create_transition.rs‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ use dpp::state_transition::{
2121
StateTransition, StateTransitionHasUserFeeIncrease, StateTransitionSingleSigned,
2222
};
2323
use serde::Deserialize;
24-
use wasm_bindgen::JsValue;
2524
use wasm_bindgen::prelude::wasm_bindgen;
2625

2726
#[derive(Deserialize)]
@@ -209,9 +208,9 @@ impl IdentityCreateTransitionWasm {
209208
}
210209

211210
#[wasm_bindgen(setter = "userFeeIncrease")]
212-
pub fn set_user_fee_increase(&mut self, amount: JsValue) -> WasmDppResult<()> {
211+
pub fn set_user_fee_increase(&mut self, amount: &js_sys::Number) -> WasmDppResult<()> {
213212
self.0
214-
.set_user_fee_increase(try_to_u16(&amount, "userFeeIncrease")?);
213+
.set_user_fee_increase(try_to_u16(amount, "userFeeIncrease")?);
215214
Ok(())
216215
}
217216

‎packages/wasm-dpp2/src/identity/transitions/masternode_vote_transition.rs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,8 @@ impl MasternodeVoteTransitionWasm {
183183
}
184184

185185
#[wasm_bindgen(setter = nonce)]
186-
pub fn set_nonce(&mut self, nonce: JsValue) -> WasmDppResult<()> {
187-
let nonce = try_to_u64(&nonce, "nonce")?;
186+
pub fn set_nonce(&mut self, nonce: &js_sys::BigInt) -> WasmDppResult<()> {
187+
let nonce = try_to_u64(nonce, "nonce")?;
188188
self.0 = match self.0.clone() {
189189
MasternodeVoteTransition::V0(mut vote) => {
190190
vote.nonce = nonce;
@@ -253,7 +253,7 @@ impl MasternodeVoteTransitionWasm {
253253
}
254254

255255
#[wasm_bindgen(setter = "userFeeIncrease")]
256-
pub fn set_user_fee_increase(&mut self, _amount: JsValue) -> WasmDppResult<()> {
256+
pub fn set_user_fee_increase(&mut self, _amount: &js_sys::Number) -> WasmDppResult<()> {
257257
// MasternodeVoteTransition no longer supports user fee increase; no-op.
258258
Ok(())
259259
}

‎packages/wasm-dpp2/src/identity/transitions/update_transition.rs‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ use dpp::state_transition::{
2222
StateTransitionLike, StateTransitionSingleSigned,
2323
};
2424
use serde::Deserialize;
25-
use wasm_bindgen::JsValue;
2625
use wasm_bindgen::prelude::wasm_bindgen;
2726

2827
#[wasm_bindgen(typescript_custom_section)]
@@ -212,14 +211,14 @@ impl IdentityUpdateTransitionWasm {
212211
}
213212

214213
#[wasm_bindgen(setter = "revision")]
215-
pub fn set_revision(&mut self, revision: JsValue) -> WasmDppResult<()> {
216-
self.0.set_revision(try_to_u64(&revision, "revision")?);
214+
pub fn set_revision(&mut self, revision: &js_sys::BigInt) -> WasmDppResult<()> {
215+
self.0.set_revision(try_to_u64(revision, "revision")?);
217216
Ok(())
218217
}
219218

220219
#[wasm_bindgen(setter = "nonce")]
221-
pub fn set_nonce(&mut self, nonce: JsValue) -> WasmDppResult<()> {
222-
self.0.set_nonce(try_to_u64(&nonce, "nonce")?);
220+
pub fn set_nonce(&mut self, nonce: &js_sys::BigInt) -> WasmDppResult<()> {
221+
self.0.set_nonce(try_to_u64(nonce, "nonce")?);
223222
Ok(())
224223
}
225224

‎packages/wasm-dpp2/src/lib.rs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ pub use identity::{
5555
IdentityUpdateTransitionWasm, IdentityWasm, MasternodeVoteTransitionWasm, PartialIdentityWasm,
5656
PublicKeyHashLikeJs, public_key_hash_from_js,
5757
};
58+
pub use platform_address::transitions::{
59+
AddressCreditWithdrawalTransitionWasm, AddressFundingFromAssetLockTransitionWasm,
60+
AddressFundsTransferTransitionWasm, IdentityCreateFromAddressesTransitionWasm,
61+
IdentityCreditTransferToAddressesTransitionWasm, IdentityTopUpFromAddressesTransitionWasm,
62+
};
5863
pub use platform_address::{
5964
FeeStrategyStepWasm, PlatformAddressInputWasm, PlatformAddressLikeArrayJs,
6065
PlatformAddressLikeJs, PlatformAddressOutputWasm, PlatformAddressSignerWasm,

‎packages/wasm-dpp2/src/platform_address/address.rs‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ use crate::utils::IntoWasm;
55
use dpp::address_funds::PlatformAddress;
66
use dpp::dashcore::Network;
77
use js_sys::Uint8Array;
8-
use serde::de::{self, Error, Visitor};
8+
use serde::de::{self, Error, MapAccess, Visitor};
99
use serde::ser::Serializer;
1010
use serde::{Deserialize, Deserializer, Serialize};
11+
use serde_json::Value as JsonValue;
1112
use std::fmt;
1213
use wasm_bindgen::prelude::*;
1314

@@ -197,6 +198,16 @@ impl<'de> Visitor<'de> for PlatformAddressWasmVisitor {
197198
.map(PlatformAddressWasm)
198199
.map_err(|e| A::Error::custom(e.to_string()))
199200
}
201+
202+
fn visit_map<M>(self, map: M) -> Result<Self::Value, M::Error>
203+
where
204+
M: MapAccess<'de>,
205+
{
206+
let value = JsonValue::deserialize(de::value::MapAccessDeserializer::new(map))
207+
.map_err(M::Error::custom)?;
208+
let js_value = serde_wasm_bindgen::to_value(&value).map_err(M::Error::custom)?;
209+
PlatformAddressWasm::try_from(&js_value).map_err(|err| M::Error::custom(err.to_string()))
210+
}
200211
}
201212

202213
impl<'de> Deserialize<'de> for PlatformAddressWasm {

‎packages/wasm-dpp2/src/platform_address/fee_strategy.rs‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
use crate::error::{WasmDppError, WasmDppResult};
2+
use crate::impl_wasm_type_info;
3+
use crate::utils::{IntoWasm, try_from_options_optional_with, try_to_array};
14
use dpp::address_funds::{AddressFundsFeeStrategy, AddressFundsFeeStrategyStep};
25
use serde::Deserialize;
36
use serde::de::{self, Deserializer, MapAccess, Visitor};
@@ -56,6 +59,8 @@ impl FeeStrategyStepWasm {
5659
}
5760
}
5861

62+
impl_wasm_type_info!(FeeStrategyStepWasm, FeeStrategyStep);
63+
5964
impl From<FeeStrategyStepWasm> for AddressFundsFeeStrategyStep {
6065
fn from(step: FeeStrategyStepWasm) -> Self {
6166
step.0
@@ -87,6 +92,32 @@ pub fn fee_strategy_from_steps_or_default(
8792
.unwrap_or_else(default_fee_strategy)
8893
}
8994

95+
/// Extract an optional Vec<FeeStrategyStepWasm> from a JS options object property.
96+
///
97+
/// Returns None if the property is undefined or null.
98+
pub fn fee_strategy_from_js_options(
99+
options: &JsValue,
100+
field_name: &str,
101+
) -> WasmDppResult<Option<Vec<FeeStrategyStepWasm>>> {
102+
try_from_options_optional_with(options, field_name, |v| {
103+
let array = try_to_array(v, field_name)?;
104+
array
105+
.iter()
106+
.enumerate()
107+
.map(|(i, item)| {
108+
item.to_wasm::<FeeStrategyStepWasm>("FeeStrategyStep")
109+
.map(|r| (*r).clone())
110+
.map_err(|_| {
111+
WasmDppError::invalid_argument(format!(
112+
"{}[{}] is not a FeeStrategyStep",
113+
field_name, i
114+
))
115+
})
116+
})
117+
.collect()
118+
})
119+
}
120+
90121
impl<'de> Deserialize<'de> for FeeStrategyStepWasm {
91122
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
92123
where

‎packages/wasm-dpp2/src/platform_address/input_output.rs‎

Lines changed: 90 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use super::{PlatformAddressLikeJs, PlatformAddressWasm};
2-
use crate::error::WasmDppResult;
3-
use crate::utils::try_to_u64;
2+
use crate::error::{WasmDppError, WasmDppResult};
3+
use crate::impl_try_from_js_value;
4+
use crate::impl_wasm_type_info;
5+
use crate::utils::{IntoWasm, try_from_options_with, try_to_array, try_to_u64};
46
use dpp::address_funds::PlatformAddress;
57
use dpp::fee::Credits;
68
use dpp::prelude::AddressNonce;
@@ -22,6 +24,8 @@ pub struct PlatformAddressInputWasm {
2224
amount: Credits,
2325
}
2426

27+
impl_wasm_type_info!(PlatformAddressInputWasm, PlatformAddressInput);
28+
2529
#[wasm_bindgen(js_class = PlatformAddressInput)]
2630
impl PlatformAddressInputWasm {
2731
/// Creates a new PlatformAddressInput.
@@ -65,6 +69,14 @@ impl PlatformAddressInputWasm {
6569
}
6670

6771
impl PlatformAddressInputWasm {
72+
pub fn new(address: PlatformAddress, nonce: AddressNonce, amount: Credits) -> Self {
73+
Self {
74+
address: address.into(),
75+
nonce,
76+
amount,
77+
}
78+
}
79+
6880
/// Returns the inner values as a tuple suitable for BTreeMap insertion.
6981
pub fn into_inner(self) -> (PlatformAddress, (AddressNonce, Credits)) {
7082
(self.address.into(), (self.nonce, self.amount))
@@ -86,6 +98,9 @@ pub struct PlatformAddressOutputWasm {
8698
amount: Option<Credits>,
8799
}
88100

101+
impl_wasm_type_info!(PlatformAddressOutputWasm, PlatformAddressOutput);
102+
impl_try_from_js_value!(PlatformAddressOutputWasm, "PlatformAddressOutput");
103+
89104
#[wasm_bindgen(js_class = PlatformAddressOutput)]
90105
impl PlatformAddressOutputWasm {
91106
/// Creates a new PlatformAddressOutput with a specific amount.
@@ -122,13 +137,26 @@ impl PlatformAddressOutputWasm {
122137
}
123138

124139
impl PlatformAddressOutputWasm {
125-
/// Returns the inner values as a tuple suitable for BTreeMap insertion.
126-
/// Panics if amount is None - use `into_inner_optional` for optional amounts.
127-
pub fn into_inner(self) -> (PlatformAddress, Credits) {
128-
(
129-
self.address.into(),
130-
self.amount.expect("amount is required for this operation"),
131-
)
140+
pub fn new(address: PlatformAddress, amount: Credits) -> Self {
141+
Self {
142+
address: address.into(),
143+
amount: Some(amount),
144+
}
145+
}
146+
147+
pub fn new_optional(address: PlatformAddress, amount: Option<Credits>) -> Self {
148+
Self {
149+
address: address.into(),
150+
amount,
151+
}
152+
}
153+
154+
/// Returns the inner values as a tuple, or an error if amount is None.
155+
pub fn try_into_inner(self) -> WasmDppResult<(PlatformAddress, Credits)> {
156+
let amount = self.amount.ok_or_else(|| {
157+
WasmDppError::invalid_argument("PlatformAddressOutput: amount is required")
158+
})?;
159+
Ok((self.address.into(), amount))
132160
}
133161

134162
/// Returns the inner values with optional amount.
@@ -138,10 +166,11 @@ impl PlatformAddressOutputWasm {
138166
}
139167

140168
/// Converts a vector of PlatformAddressOutput into a BTreeMap.
169+
/// Returns an error if any output has no amount set.
141170
pub fn outputs_to_btree_map(
142171
outputs: Vec<PlatformAddressOutputWasm>,
143-
) -> BTreeMap<PlatformAddress, Credits> {
144-
outputs.into_iter().map(|o| o.into_inner()).collect()
172+
) -> WasmDppResult<BTreeMap<PlatformAddress, Credits>> {
173+
outputs.into_iter().map(|o| o.try_into_inner()).collect()
145174
}
146175

147176
/// Converts a vector of PlatformAddressOutput into a BTreeMap with optional amounts.
@@ -156,3 +185,53 @@ pub fn outputs_to_optional_btree_map(
156185
.map(|o| o.into_inner_optional())
157186
.collect()
158187
}
188+
189+
/// Extract a Vec<PlatformAddressInputWasm> from a JS options object property.
190+
///
191+
/// Reads the named property as a JS array, then extracts each element
192+
/// as a PlatformAddressInput wasm-bindgen object via its __wbg_ptr.
193+
pub fn inputs_from_js_options(
194+
options: &JsValue,
195+
field_name: &str,
196+
) -> WasmDppResult<Vec<PlatformAddressInputWasm>> {
197+
let array = try_from_options_with(options, field_name, |v| try_to_array(v, field_name))?;
198+
array
199+
.iter()
200+
.enumerate()
201+
.map(|(i, item)| {
202+
item.to_wasm::<PlatformAddressInputWasm>("PlatformAddressInput")
203+
.map(|r| (*r).clone())
204+
.map_err(|_| {
205+
WasmDppError::invalid_argument(format!(
206+
"{}[{}] is not a PlatformAddressInput",
207+
field_name, i
208+
))
209+
})
210+
})
211+
.collect()
212+
}
213+
214+
/// Extract a Vec<PlatformAddressOutputWasm> from a JS options object property.
215+
///
216+
/// Reads the named property as a JS array, then extracts each element
217+
/// as a PlatformAddressOutput wasm-bindgen object via its __wbg_ptr.
218+
pub fn outputs_from_js_options(
219+
options: &JsValue,
220+
field_name: &str,
221+
) -> WasmDppResult<Vec<PlatformAddressOutputWasm>> {
222+
let array = try_from_options_with(options, field_name, |v| try_to_array(v, field_name))?;
223+
array
224+
.iter()
225+
.enumerate()
226+
.map(|(i, item)| {
227+
item.to_wasm::<PlatformAddressOutputWasm>("PlatformAddressOutput")
228+
.map(|r| (*r).clone())
229+
.map_err(|_| {
230+
WasmDppError::invalid_argument(format!(
231+
"{}[{}] is not a PlatformAddressOutput",
232+
field_name, i
233+
))
234+
})
235+
})
236+
.collect()
237+
}

‎packages/wasm-dpp2/src/platform_address/mod.rs‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@ mod address;
22
mod fee_strategy;
33
mod input_output;
44
mod signer;
5+
pub mod transitions;
56

67
pub use address::{PlatformAddressLikeArrayJs, PlatformAddressLikeJs, PlatformAddressWasm};
78
pub use fee_strategy::{
8-
FeeStrategyStepWasm, default_fee_strategy, fee_strategy_from_steps,
9-
fee_strategy_from_steps_or_default,
9+
FeeStrategyStepWasm, default_fee_strategy, fee_strategy_from_js_options,
10+
fee_strategy_from_steps, fee_strategy_from_steps_or_default,
1011
};
1112
pub use input_output::{
12-
PlatformAddressInputWasm, PlatformAddressOutputWasm, outputs_to_btree_map,
13-
outputs_to_optional_btree_map,
13+
PlatformAddressInputWasm, PlatformAddressOutputWasm, inputs_from_js_options,
14+
outputs_from_js_options, outputs_to_btree_map, outputs_to_optional_btree_map,
1415
};
1516
pub use signer::PlatformAddressSignerWasm;

0 commit comments

Comments
 (0)