Skip to content

feat(wasm-dpp2): add platform address transition WASM bindings#3147

Open
shumkov wants to merge 1 commit intov3.1-devfrom
feat/sdk/platform-address-transitions
Open

feat(wasm-dpp2): add platform address transition WASM bindings#3147
shumkov wants to merge 1 commit intov3.1-devfrom
feat/sdk/platform-address-transitions

Conversation

@shumkov
Copy link
Collaborator

@shumkov shumkov commented Feb 23, 2026

Issue being fixed or feature implemented

JavaScript/TypeScript applications need WASM bindings for the 6 platform address-based state transitions to create, serialize, and
interact with them from the browser and Node.js.

What was done?

New transition bindings (platform_address/transitions/)

Added WASM bindings for all 6 address-based state transitions:

  • AddressFundsTransferTransition — transfer credits between platform addresses
  • AddressCreditWithdrawalTransition — withdraw credits to Core via output script
  • AddressFundingFromAssetLockTransition — fund platform addresses via asset lock proofs
  • IdentityCreateFromAddressesTransition — create identity from platform address inputs
  • IdentityTopUpFromAddressesTransition — top up identity from platform addresses
  • IdentityCreditTransferToAddressesTransition — transfer credits from identity to platform addresses

Each binding exposes:

  • Constructor from a typed JS options object
  • Binary serialization: toBytes/fromBytes, toBase64/fromBase64, toHex/fromHex
  • Serde conversions: toObject/fromObject, toJSON/fromJSON (via impl_wasm_conversions!)
  • toStateTransition/fromStateTransition for enum wrapping
  • Typed getters/setters for all fields

Supporting changes

  • input_output.rs — added PlatformAddressOutput::new/new_optional, helper functions inputs_from_js_options,
    optional_output_from_js_options, fee_strategy_from_js_options, outputs_from_js_options
  • fee_strategy.rs — added FeeStrategyStepWasm with deductFromInput/reduceOutput constructors and to_wasm conversion
  • address.rs — added PlatformAddressWasm::new constructor, impl_wasm_type_info!
  • lib.rs — exported new transition types and FeeStrategyStepWasm

How Has This Been Tested?

yarn workspace @dashevo/wasm-dpp2 test — 838 passing, 0 failing.

Added 7 test files:

  • AddressFundsTransferTransition.spec.ts — constructor, bytes/base64/hex round-trips, inputs/outputs getters/setters,
    userFeeIncrease, StateTransition conversion
  • AddressCreditWithdrawalTransition.spec.ts — constructor (with/without output),
    inputs/output/outputScript/pooling/coreFeePerByte getters/setters, StateTransition conversion
  • AddressFundingFromAssetLockTransition.spec.ts — constructor with asset lock proof, inputs/outputs/assetLockProof
    getters/setters, StateTransition conversion
  • IdentityCreateFromAddressesTransition.spec.ts — constructor with public keys, inputs getter/setter, StateTransition conversion
  • IdentityTopUpFromAddressesTransition.spec.ts — constructor with identityId (string and Identifier), inputs/output/identityId
    getters/setters, StateTransition conversion
  • IdentityCreditTransferToAddresses.spec.ts — constructor, recipientAddresses/senderId/nonce/signature/signaturePublicKeyId
    getters/setters, StateTransition conversion
  • AddressFundsTransfer.spec.tsFeeStrategyStepWasm deductFromInput/reduceOutput tests

Note: toObject/fromObject/toJSON/fromJSON conversion tests deferred to a separate PR to address a pre-existing
is_human_readable mismatch in the impl_wasm_conversions! macro.

Breaking Changes

None

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

Summary by CodeRabbit

Release Notes

  • New Features
    • Added six new transition types for platform address and identity operations accessible via WebAssembly
    • Enhanced serialization/deserialization capabilities supporting bytes, Base64, and hexadecimal formats
    • Added utility functions for configuring fee strategies and managing inputs/outputs from JavaScript
    • Improved type conversions and validation for cross-language interoperability

@github-actions github-actions bot added this to the v3.1.0 milestone Feb 23, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 23, 2026

📝 Walkthrough

Walkthrough

The PR adds WebAssembly bindings for six platform address transition types (AddressCreditWithdrawal, AddressFundingFromAssetLock, AddressFundsTransfer, IdentityCreateFromAddresses, IdentityCreditTransferToAddresses, IdentityTopUpFromAddresses) with full construction, serialization, deserialization, and field mutation APIs. Helper functions extract and validate inputs/outputs from JavaScript options objects, and comprehensive unit tests validate all functionality.

Changes

Cohort / File(s) Summary
Core Library Exports
packages/wasm-dpp2/src/lib.rs
Re-exports six new TransitionWasm items from platform_address::transitions module for public API surface.
Platform Address Utilities
packages/wasm-dpp2/src/platform_address/address.rs, fee_strategy.rs, input_output.rs, mod.rs
Enhanced platform address support with JSON deserialization, fee strategy conversion/validation, input/output constructors, and JS options extraction helpers; extended module re-exports.
Platform Address Transitions
packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs, address_funding_from_asset_lock_transition.rs, address_funds_transfer_transition.rs, identity_create_from_addresses_transition.rs, identity_credit_transfer_to_addresses_transition.rs, identity_top_up_from_addresses_transition.rs
Six new wasm-bindgen modules exposing transition construction, serialization (toBytes/toHex/toBase64), deserialization (fromBytes/fromHex/fromBase64), field accessors/mutators, and StateTransition conversion with comprehensive JS options parsing and error handling.
Transition Module Management
packages/wasm-dpp2/src/platform_address/transitions/mod.rs
Module declarations and public re-exports for all six new transition wasm types.
Unit Test Coverage
packages/wasm-dpp2/tests/unit/AddressCreditWithdrawalTransition.spec.ts, AddressFundingFromAssetLockTransition.spec.ts, AddressFundsTransferTransition.spec.ts, IdentityCreateFromAddressesTransition.spec.ts, IdentityCreditTransferToAddresses.spec.ts, IdentityTopUpFromAddressesTransition.spec.ts, AddressFundsTransfer.spec.ts
Comprehensive test suites validating constructor variants, serialization round-trips (bytes/base64/hex), field accessors/mutators, StateTransition integration, and default behaviors for each transition type.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • QuantumExplorer

Poem

🐰 Six transitions leap through WASM gates,
Each binding fields with careful waits,
From options parsed to bytes encoded clear,
The platform address transitions appear!
Tests hop along to verify each bound,
New APIs flourish all around! 🌟

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely describes the main change: adding WASM bindings for platform address transitions, which is the primary objective of this changeset.
Docstring Coverage ✅ Passed Docstring coverage is 99.25% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/sdk/platform-address-transitions

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs (1)

159-175: Same outputs_to_btree_map panic risk applies here.

set_recipient_addresses (Line 174) and the constructor (Line 96) both use outputs_to_btree_map, which internally calls into_inner() with an .expect(). If a PlatformAddressOutput without an amount reaches this path, it will panic. This is the same root cause flagged in the address_credit_withdrawal_transition.rs review.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs`
around lines 159 - 175, The setter set_recipient_addresses calls
outputs_to_btree_map which currently uses into_inner().expect() and can panic if
a PlatformAddressOutput lacks an amount; change outputs_to_btree_map to return a
Result<BTreeMap<...>, JsValue> (or custom error) instead of unwrapping, update
set_recipient_addresses (and the constructor that also calls
outputs_to_btree_map) to handle the Result by propagating the error to JS (e.g.,
return Result<(), JsValue> or use wasm_bindgen::throw_str) and validate each
PlatformAddressOutputWasm for a present amount before converting so no .expect()
is used. Ensure references are updated for outputs_to_btree_map,
set_recipient_addresses, and the constructor that calls outputs_to_btree_map.
🧹 Nitpick comments (9)
packages/wasm-dpp2/tests/unit/AddressFundsTransfer.spec.ts (1)

42-45: Filename uses PascalCase instead of kebab-case.

Per coding guidelines, files matching packages/**/!(node_modules)/**/*.{js,jsx,ts,tsx} should use kebab-case for filenames. This file is AddressFundsTransfer.spec.ts but should be address-funds-transfer.spec.ts. The same applies to the other new test files in this PR. However, if PascalCase is the established convention in wasm-dpp2 tests, feel free to disregard.

As per coding guidelines: "Use kebab-case for filenames within JS packages"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/wasm-dpp2/tests/unit/AddressFundsTransfer.spec.ts` around lines 42 -
45, The test filename uses PascalCase (AddressFundsTransfer.spec.ts) but should
follow the repo's kebab-case rule; rename the file to
address-funds-transfer.spec.ts and update any imports or test references that
point to AddressFundsTransfer.spec.ts (and do the same for other new test files
in this PR) so test runner and imports resolve correctly; verify references in
test suites or any index files that mention AddressFundsTransferTransition or
the skipped describe('AddressFundsTransferTransition (.build API)') remain valid
after the rename.
packages/wasm-dpp2/src/platform_address/input_output.rs (1)

186-265: Consider extracting a generic helper to reduce duplication between inputs_from_js_options and outputs_from_js_options.

Both functions share identical scaffolding (Reflect::get → null check → array check → enumerate → to_wasm → clone → map_err), differing only in the Wasm type and its name string. A generic helper parameterized on the target type would eliminate this ~40-line duplication. Note that fee_strategy_from_js_options already uses the try_from_options_optional_with + try_to_array utils for similar work but with optional semantics.

Not blocking — deferring is fine if the current clarity is preferred.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/wasm-dpp2/src/platform_address/input_output.rs` around lines 186 -
265, Extract a generic helper (e.g., items_from_js_options<T>) that encapsulates
the common scaffolding in inputs_from_js_options and outputs_from_js_options:
read the property via js_sys::Reflect::get, check undefined/null, ensure it's an
array, iterate/enumerate, call item.to_wasm::<T>(type_name) and clone the inner
value, and map errors with the same "{}[{}] is not a <Type>" message; make the
helper accept the JsValue options, field_name: &str, type_name: &str and a
generic T used in to_wasm (with the same trait bounds required for cloning),
then replace inputs_from_js_options and outputs_from_js_options to call this
helper and return its result (keep the existing WasmDppError messages and
signatures).
packages/wasm-dpp2/tests/unit/AddressFundingFromAssetLockTransition.spec.ts (1)

164-172: Consider asserting the output amount after the setter.

The outputs setter test verifies the array length but not the updated amount value (BigInt(50000)). A value assertion would strengthen this test.

✏️ Suggested addition
     transition.outputs = [newOutput];
     const outputs = transition.outputs;
     expect(outputs).to.have.lengthOf(1);
+    expect(outputs[0].amount).to.equal(BigInt(50000));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/wasm-dpp2/tests/unit/AddressFundingFromAssetLockTransition.spec.ts`
around lines 164 - 172, The test currently only checks the outputs array length;
after setting transition.outputs to [newOutput] also assert the amount on the
stored output matches the intended BigInt(50000). Locate the test using
createTransition(), new wasm.PlatformAddressOutput(newAddr, BigInt(50000)) and
transition.outputs, then add an assertion that the retrieved outputs[0] (or
outputs.at(0)) has an amount equal to BigInt(50000) to validate the setter
preserved the value.
packages/wasm-dpp2/tests/unit/IdentityCreateFromAddressesTransition.spec.ts (1)

81-100: Missing toHex/fromHex round-trip coverage — same gap as IdentityTopUpFromAddressesTransition.spec.ts. Consider adding a toHex() / fromHex() describe block for consistency with the other transition suites.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/wasm-dpp2/tests/unit/IdentityCreateFromAddressesTransition.spec.ts`
around lines 81 - 100, Add missing hex round-trip tests for
IdentityCreateFromAddressesTransition: add a describe('toHex() / fromHex()')
block mirroring the existing toBase64/toBytes tests, create a transition via
createTransition(), call transition.toHex(), verify Buffer.from(hex, 'hex')
equals Buffer.from(transition.toBytes()), then restore with
wasm.IdentityCreateFromAddressesTransition.fromHex(hex) and assert
Buffer.from(restored.toBytes()) equals the original bytes; reference the
existing createTransition(), transition.toHex(),
wasm.IdentityCreateFromAddressesTransition.fromHex(), transition.toBytes(), and
restored.toBytes() methods when locating where to insert the new test.
packages/wasm-dpp2/tests/unit/IdentityTopUpFromAddressesTransition.spec.ts (1)

76-95: Missing toHex/fromHex round-trip coverage.

The other transition spec files (AddressFundsTransferTransition.spec.ts, IdentityCreditTransferToAddresses.spec.ts, AddressFundingFromAssetLockTransition.spec.ts) all include a toHex() / fromHex() suite. Consider adding one here for consistency:

✏️ Suggested addition
+  describe('toHex() / fromHex()', () => {
+    it('should round-trip via hex', () => {
+      const transition = createTransition();
+      const hex = transition.toHex();
+      const bytes = transition.toBytes();
+
+      const restored = wasm.IdentityTopUpFromAddressesTransition.fromHex(hex);
+      expect(Buffer.from(restored.toBytes())).to.deep.equal(Buffer.from(bytes));
+    });
+  });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/wasm-dpp2/tests/unit/IdentityTopUpFromAddressesTransition.spec.ts`
around lines 76 - 95, Add a toHex()/fromHex() round-trip test for
IdentityTopUpFromAddressesTransition similar to other transition specs: create a
transition via createTransition(), call transition.toHex(), assert
Buffer.from(hex, 'hex') equals Buffer.from(transition.toBytes()), then restore
with wasm.IdentityTopUpFromAddressesTransition.fromHex(hex) and assert
Buffer.from(restored.toBytes()) equals the original bytes; place this in a new
describe('toHex() / fromHex()') / it('should round-trip via hex') block
alongside the existing toBytes/toBase64 tests.
packages/wasm-dpp2/tests/unit/AddressCreditWithdrawalTransition.spec.ts (1)

78-97: Missing toHex/fromHex round-trip coverage — same gap as two other spec files in this PR. Consider adding a toHex() / fromHex() describe block for consistency across the transition suite.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/wasm-dpp2/tests/unit/AddressCreditWithdrawalTransition.spec.ts`
around lines 78 - 97, Add a new describe block testing toHex()/fromHex()
round-trip for AddressCreditWithdrawalTransition: call createTransition(), get
hex via transition.toHex(), assert Buffer.from(hex, 'hex') equals
Buffer.from(transition.toBytes()), then restore via
wasm.AddressCreditWithdrawalTransition.fromHex(hex) and assert
Buffer.from(restored.toBytes()) equals the original bytes; place the test
alongside the existing toBytes/toBase64 blocks and use the same createTransition
helper and wasm.AddressCreditWithdrawalTransition methods.
packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs (2)

163-179: Same unnecessary clone pattern in set_public_keys.

keys is a local Vec that's not reused — into_iter() avoids the per-element clone.

♻️ Suggested optimization
             IdentityCreateFromAddressesTransition::V0(v0) => {
-                v0.public_keys = keys
-                    .iter()
-                    .map(|k| IdentityPublicKeyInCreation::from(k.clone()))
+                v0.public_keys = keys
+                    .into_iter()
+                    .map(|k| IdentityPublicKeyInCreation::from(k))
                     .collect();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs`
around lines 163 - 179, The setter set_public_keys currently iterates over the
local Vec keys with keys.iter() and calls k.clone() for each element; replace
that clone pattern by consuming the vector with keys.into_iter() and mapping
each IdentityPublicKeyInCreationWasm directly into IdentityPublicKeyInCreation
(i.e., use IdentityPublicKeyInCreation::from(k) inside the map) when assigning
to v0.public_keys in the IdentityCreateFromAddressesTransition::V0 arm to avoid
unnecessary per-element cloning of IdentityPublicKeyInCreationWasm.

94-105: Unnecessary .clone()public_keys is not used after this point.

public_keys.iter().map(|k| k.clone().into()) borrows the vec and clones each element. Since public_keys is a local that's not used afterwards, .into_iter() avoids the clone.

♻️ Suggested optimization
                 IdentityCreateFromAddressesTransitionV0 {
-                    public_keys: public_keys.iter().map(|k| k.clone().into()).collect(),
+                    public_keys: public_keys.into_iter().map(|k| k.into()).collect(),
                     inputs: inputs_map,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs`
around lines 94 - 105, The public_keys vector is cloned unnecessarily when
constructing IdentityCreateFromAddressesTransitionV0; update the construction in
IdentityCreateFromAddressesTransitionWasm /
IdentityCreateFromAddressesTransition::V0 /
IdentityCreateFromAddressesTransitionV0 to consume public_keys instead of
iterating and cloning it by replacing public_keys.iter().map(|k|
k.clone().into()) with an into-iterator that converts each element (e.g.,
public_keys.into_iter().map(Into::into)), since public_keys is not used after
this point.
packages/wasm-dpp2/src/platform_address/transitions/address_funding_from_asset_lock_transition.rs (1)

153-204: Minor inconsistency: inputs uses manual match while asset_lock_proof and outputs use accessor trait methods.

The inputs getter/setter (lines 163–184) manually matches on V0, while asset_lock_proof and outputs use the AddressFundingFromAssetLockTransitionAccessorsV0 trait methods. This works fine, but if an accessor for inputs becomes available on the trait in the future, consider aligning for consistency.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/wasm-dpp2/src/platform_address/transitions/address_funding_from_asset_lock_transition.rs`
around lines 153 - 204, The inputs getter/setter manually pattern-match on
AddressFundingFromAssetLockTransition::V0 while asset_lock_proof and outputs use
the AddressFundingFromAssetLockTransitionAccessorsV0 trait; change inputs() and
set_inputs() to call the same accessor methods on self.0 (e.g., use
AddressFundingFromAssetLockTransitionAccessorsV0::inputs and ::set_inputs or the
impl-provided inputs()/set_inputs() methods) and convert between
PlatformAddressInputWasm and the inner types as before so the code consistently
uses the transition accessor API (update the inputs() getter to iterate over
self.0.inputs() and the set_inputs() to call self.0.set_inputs(inputs_map)).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs`:
- Around line 179-206: The setter AddressCreditWithdrawalTransition::set_output
currently calls PlatformAddressOutputWasm::into_inner(), which can panic if the
PlatformAddressOutput has no amount; replace this with a fallible conversion
(e.g., add and call a try_into_inner() on PlatformAddressOutputWasm that returns
WasmDppResult<PlatformAddressOutput>) or explicitly validate the output_wasm has
an amount before converting and return a WasmDppError (invalid_argument) instead
of panicking. Update callers that use into_inner() (including
outputs_to_btree_map and implementations in AddressFundsTransferTransition and
other transition setters) to use the new try_into_inner() or the
validation+error pattern so all setters return graceful WasmDppResult errors
instead of causing a WASM panic.

In `@packages/wasm-dpp2/src/platform_address/transitions/mod.rs`:
- Line 10: The import line uses the misspelled module name
address_funds_transfer_transsition (extra "s"), causing an unresolved import for
AddressFundsTransferTransitionWasm; change the module path to the correct
address_funds_transfer_transition so the pub use
AddressFundsTransferTransitionWasm; resolves to the declared module name.

---

Duplicate comments:
In
`@packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs`:
- Around line 159-175: The setter set_recipient_addresses calls
outputs_to_btree_map which currently uses into_inner().expect() and can panic if
a PlatformAddressOutput lacks an amount; change outputs_to_btree_map to return a
Result<BTreeMap<...>, JsValue> (or custom error) instead of unwrapping, update
set_recipient_addresses (and the constructor that also calls
outputs_to_btree_map) to handle the Result by propagating the error to JS (e.g.,
return Result<(), JsValue> or use wasm_bindgen::throw_str) and validate each
PlatformAddressOutputWasm for a present amount before converting so no .expect()
is used. Ensure references are updated for outputs_to_btree_map,
set_recipient_addresses, and the constructor that calls outputs_to_btree_map.

---

Nitpick comments:
In `@packages/wasm-dpp2/src/platform_address/input_output.rs`:
- Around line 186-265: Extract a generic helper (e.g., items_from_js_options<T>)
that encapsulates the common scaffolding in inputs_from_js_options and
outputs_from_js_options: read the property via js_sys::Reflect::get, check
undefined/null, ensure it's an array, iterate/enumerate, call
item.to_wasm::<T>(type_name) and clone the inner value, and map errors with the
same "{}[{}] is not a <Type>" message; make the helper accept the JsValue
options, field_name: &str, type_name: &str and a generic T used in to_wasm (with
the same trait bounds required for cloning), then replace inputs_from_js_options
and outputs_from_js_options to call this helper and return its result (keep the
existing WasmDppError messages and signatures).

In
`@packages/wasm-dpp2/src/platform_address/transitions/address_funding_from_asset_lock_transition.rs`:
- Around line 153-204: The inputs getter/setter manually pattern-match on
AddressFundingFromAssetLockTransition::V0 while asset_lock_proof and outputs use
the AddressFundingFromAssetLockTransitionAccessorsV0 trait; change inputs() and
set_inputs() to call the same accessor methods on self.0 (e.g., use
AddressFundingFromAssetLockTransitionAccessorsV0::inputs and ::set_inputs or the
impl-provided inputs()/set_inputs() methods) and convert between
PlatformAddressInputWasm and the inner types as before so the code consistently
uses the transition accessor API (update the inputs() getter to iterate over
self.0.inputs() and the set_inputs() to call self.0.set_inputs(inputs_map)).

In
`@packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs`:
- Around line 163-179: The setter set_public_keys currently iterates over the
local Vec keys with keys.iter() and calls k.clone() for each element; replace
that clone pattern by consuming the vector with keys.into_iter() and mapping
each IdentityPublicKeyInCreationWasm directly into IdentityPublicKeyInCreation
(i.e., use IdentityPublicKeyInCreation::from(k) inside the map) when assigning
to v0.public_keys in the IdentityCreateFromAddressesTransition::V0 arm to avoid
unnecessary per-element cloning of IdentityPublicKeyInCreationWasm.
- Around line 94-105: The public_keys vector is cloned unnecessarily when
constructing IdentityCreateFromAddressesTransitionV0; update the construction in
IdentityCreateFromAddressesTransitionWasm /
IdentityCreateFromAddressesTransition::V0 /
IdentityCreateFromAddressesTransitionV0 to consume public_keys instead of
iterating and cloning it by replacing public_keys.iter().map(|k|
k.clone().into()) with an into-iterator that converts each element (e.g.,
public_keys.into_iter().map(Into::into)), since public_keys is not used after
this point.

In `@packages/wasm-dpp2/tests/unit/AddressCreditWithdrawalTransition.spec.ts`:
- Around line 78-97: Add a new describe block testing toHex()/fromHex()
round-trip for AddressCreditWithdrawalTransition: call createTransition(), get
hex via transition.toHex(), assert Buffer.from(hex, 'hex') equals
Buffer.from(transition.toBytes()), then restore via
wasm.AddressCreditWithdrawalTransition.fromHex(hex) and assert
Buffer.from(restored.toBytes()) equals the original bytes; place the test
alongside the existing toBytes/toBase64 blocks and use the same createTransition
helper and wasm.AddressCreditWithdrawalTransition methods.

In `@packages/wasm-dpp2/tests/unit/AddressFundingFromAssetLockTransition.spec.ts`:
- Around line 164-172: The test currently only checks the outputs array length;
after setting transition.outputs to [newOutput] also assert the amount on the
stored output matches the intended BigInt(50000). Locate the test using
createTransition(), new wasm.PlatformAddressOutput(newAddr, BigInt(50000)) and
transition.outputs, then add an assertion that the retrieved outputs[0] (or
outputs.at(0)) has an amount equal to BigInt(50000) to validate the setter
preserved the value.

In `@packages/wasm-dpp2/tests/unit/AddressFundsTransfer.spec.ts`:
- Around line 42-45: The test filename uses PascalCase
(AddressFundsTransfer.spec.ts) but should follow the repo's kebab-case rule;
rename the file to address-funds-transfer.spec.ts and update any imports or test
references that point to AddressFundsTransfer.spec.ts (and do the same for other
new test files in this PR) so test runner and imports resolve correctly; verify
references in test suites or any index files that mention
AddressFundsTransferTransition or the skipped
describe('AddressFundsTransferTransition (.build API)') remain valid after the
rename.

In `@packages/wasm-dpp2/tests/unit/IdentityCreateFromAddressesTransition.spec.ts`:
- Around line 81-100: Add missing hex round-trip tests for
IdentityCreateFromAddressesTransition: add a describe('toHex() / fromHex()')
block mirroring the existing toBase64/toBytes tests, create a transition via
createTransition(), call transition.toHex(), verify Buffer.from(hex, 'hex')
equals Buffer.from(transition.toBytes()), then restore with
wasm.IdentityCreateFromAddressesTransition.fromHex(hex) and assert
Buffer.from(restored.toBytes()) equals the original bytes; reference the
existing createTransition(), transition.toHex(),
wasm.IdentityCreateFromAddressesTransition.fromHex(), transition.toBytes(), and
restored.toBytes() methods when locating where to insert the new test.

In `@packages/wasm-dpp2/tests/unit/IdentityTopUpFromAddressesTransition.spec.ts`:
- Around line 76-95: Add a toHex()/fromHex() round-trip test for
IdentityTopUpFromAddressesTransition similar to other transition specs: create a
transition via createTransition(), call transition.toHex(), assert
Buffer.from(hex, 'hex') equals Buffer.from(transition.toBytes()), then restore
with wasm.IdentityTopUpFromAddressesTransition.fromHex(hex) and assert
Buffer.from(restored.toBytes()) equals the original bytes; place this in a new
describe('toHex() / fromHex()') / it('should round-trip via hex') block
alongside the existing toBytes/toBase64 tests.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cb174d1 and 73591df.

📒 Files selected for processing (19)
  • packages/wasm-dpp2/src/lib.rs
  • packages/wasm-dpp2/src/platform_address/address.rs
  • packages/wasm-dpp2/src/platform_address/fee_strategy.rs
  • packages/wasm-dpp2/src/platform_address/input_output.rs
  • packages/wasm-dpp2/src/platform_address/mod.rs
  • packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs
  • packages/wasm-dpp2/src/platform_address/transitions/address_funding_from_asset_lock_transition.rs
  • packages/wasm-dpp2/src/platform_address/transitions/address_funds_transfer_transition.rs
  • packages/wasm-dpp2/src/platform_address/transitions/identity_create_from_addresses_transition.rs
  • packages/wasm-dpp2/src/platform_address/transitions/identity_credit_transfer_to_addresses_transition.rs
  • packages/wasm-dpp2/src/platform_address/transitions/identity_top_up_from_addresses_transition.rs
  • packages/wasm-dpp2/src/platform_address/transitions/mod.rs
  • packages/wasm-dpp2/tests/unit/AddressCreditWithdrawalTransition.spec.ts
  • packages/wasm-dpp2/tests/unit/AddressFundingFromAssetLockTransition.spec.ts
  • packages/wasm-dpp2/tests/unit/AddressFundsTransfer.spec.ts
  • packages/wasm-dpp2/tests/unit/AddressFundsTransferTransition.spec.ts
  • packages/wasm-dpp2/tests/unit/IdentityCreateFromAddressesTransition.spec.ts
  • packages/wasm-dpp2/tests/unit/IdentityCreditTransferToAddresses.spec.ts
  • packages/wasm-dpp2/tests/unit/IdentityTopUpFromAddressesTransition.spec.ts

Comment on lines +179 to +206
#[wasm_bindgen(getter = "output")]
pub fn output(&self) -> Option<PlatformAddressOutputWasm> {
let output = match &self.0 {
AddressCreditWithdrawalTransition::V0(v0) => &v0.output,
};
output.map(|(address, credits)| PlatformAddressOutputWasm::new(address, credits))
}

#[wasm_bindgen(setter = "output")]
pub fn set_output(&mut self, output: JsValue) -> WasmDppResult<()> {
let new_output = if output.is_undefined() || output.is_null() {
None
} else {
let output_wasm = output
.to_wasm::<PlatformAddressOutputWasm>("PlatformAddressOutput")
.map(|r| (*r).clone())
.map_err(|_| {
WasmDppError::invalid_argument("'output' is not a PlatformAddressOutput")
})?;
Some(output_wasm.into_inner())
};
match &mut self.0 {
AddressCreditWithdrawalTransition::V0(v0) => {
v0.output = new_output;
}
}
Ok(())
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

into_inner() will panic in WASM if the output has no amount.

Line 198 calls output_wasm.into_inner() which uses .expect(...) internally. If a user constructs a PlatformAddressOutput without an amount and passes it to the output setter, this will panic rather than returning a graceful error to JavaScript.

Consider using a fallible conversion (e.g., a try_into_inner that returns WasmDppResult) or validating the amount before calling into_inner.

This same risk applies to outputs_to_btree_map used in AddressFundsTransferTransition and other transitions.

Proposed fix in input_output.rs (root cause)
-    pub fn into_inner(self) -> (PlatformAddress, Credits) {
-        (
-            self.address.into(),
-            self.amount.expect("amount is required for this operation"),
-        )
-    }
+    pub fn into_inner(self) -> (PlatformAddress, Credits) {
+        (
+            self.address.into(),
+            self.amount.expect("amount is required for this operation"),
+        )
+    }
+
+    pub fn try_into_inner(self) -> WasmDppResult<(PlatformAddress, Credits)> {
+        let amount = self.amount.ok_or_else(|| {
+            WasmDppError::invalid_argument("amount is required for this output")
+        })?;
+        Ok((self.address.into(), amount))
+    }

Then callers like outputs_to_btree_map and the output setter can use try_into_inner() to return errors instead of panicking.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/wasm-dpp2/src/platform_address/transitions/address_credit_withdrawal_transition.rs`
around lines 179 - 206, The setter AddressCreditWithdrawalTransition::set_output
currently calls PlatformAddressOutputWasm::into_inner(), which can panic if the
PlatformAddressOutput has no amount; replace this with a fallible conversion
(e.g., add and call a try_into_inner() on PlatformAddressOutputWasm that returns
WasmDppResult<PlatformAddressOutput>) or explicitly validate the output_wasm has
an amount before converting and return a WasmDppError (invalid_argument) instead
of panicking. Update callers that use into_inner() (including
outputs_to_btree_map and implementations in AddressFundsTransferTransition and
other transition setters) to use the new try_into_inner() or the
validation+error pattern so all setters return graceful WasmDppResult errors
instead of causing a WASM panic.


pub use address_credit_withdrawal_transition::AddressCreditWithdrawalTransitionWasm;
pub use address_funding_from_asset_lock_transition::AddressFundingFromAssetLockTransitionWasm;
pub use address_funds_transfer_transsition::AddressFundsTransferTransitionWasm;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Typo in module path causes a compile error.

address_funds_transfer_transsition (double s) does not match the module declared on Line 3 (address_funds_transfer_transition). Rust will emit error[E0432]: unresolved import when building from source.

🐛 Proposed fix
-pub use address_funds_transfer_transsition::AddressFundsTransferTransitionWasm;
+pub use address_funds_transfer_transition::AddressFundsTransferTransitionWasm;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub use address_funds_transfer_transsition::AddressFundsTransferTransitionWasm;
pub use address_funds_transfer_transition::AddressFundsTransferTransitionWasm;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/wasm-dpp2/src/platform_address/transitions/mod.rs` at line 10, The
import line uses the misspelled module name address_funds_transfer_transsition
(extra "s"), causing an unresolved import for
AddressFundsTransferTransitionWasm; change the module path to the correct
address_funds_transfer_transition so the pub use
AddressFundsTransferTransitionWasm; resolves to the declared module name.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant