Skip to content

Conversation

@shumkov
Copy link
Collaborator

@shumkov shumkov commented Dec 28, 2025

Issue being fixed or feature implemented

Currently, state transition methods accept many arguments instead of typed objects, which is a better UX.

What was done?

  • Refactored state transitions methods to accept typed objects with a signer.
  • Updated return values.

How Has This Been Tested?

With new functional and unit tests.
Enabled skiped tests.

Breaking Changes

Public API of Evo SDK is changed

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

  • New Features

    • Full WASM APIs for contracts (publish/update), documents (create/replace/delete/transfer/purchase/setPrice), tokens (mint/burn/transfer/freeze/unfreeze/destroy/emergency/claim/setPrice/directPurchase), identities (create/topUp/creditTransfer/withdrawal/update/masternodeVote), key generation, and identity nonce refresh.
  • Refactor

    • Public JS/TS facades and SDK methods now use unified options objects and typed option/result bindings; module renames for state_transitions.
  • Tests

    • Expanded and added unit and functional tests exercising contracts, documents, identities, tokens, key generation, and transitions.

✏️ Tip: You can customize this high-level summary in your review settings.

@shumkov shumkov self-assigned this Dec 28, 2025
@github-actions github-actions bot added this to the v3.0.0 milestone Dec 28, 2025
@shumkov shumkov moved this to In review / testing in Platform team Dec 28, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 28, 2025

📝 Walkthrough

Walkthrough

Adds a macro-based options extraction utility to wasm-dpp2, converts many WASM SDK state-transition bindings to take single options objects, introduces full document/contract/identity/token WASM flows and JS facades updates, and adjusts serialization for data contract schemas to use platform values.

Changes

Cohort / File(s) Summary
Option-extraction macro & util
packages/wasm-dpp2/src/utils.rs, packages/wasm-dpp2/src/* (many files)
Adds impl_try_from_options! macro and applies it across wasm-dpp2 types to generate try_from_options / try_from_optional_options helpers, centralizing JS options parsing.
Data contract serialization
packages/wasm-dpp2/src/data_contract/model.rs
Replaces JSON round-trip with platform_value_from_object(...).into_btree_string_map() in set_schemas to preserve integer types; maps errors to invalid_argument.
WASM-dpp2 type conversions & small APIs
packages/wasm-dpp2/src/identifier.rs, packages/wasm-dpp2/src/private_key.rs, packages/wasm-dpp2/src/lib.rs, plus many model files
Adds IdentifierWasm::try_from_options, PrivateKeyWasm::try_from_options, re-exports PrivateKeyWasm, and applies macro invocations to many Wasm wrapper types (DocumentWasm, IdentityWasm, VotePollWasm, ResourceVoteChoiceWasm, CoreScriptWasm, AssetLockProofWasm, etc.).
Signer and platform address refactor
packages/wasm-dpp2/src/identity/signer.rs, packages/wasm-dpp2/src/platform_address/signer.rs
Expands IdentitySignerWasm to support ECDSA_SECP256K1 and ECDSA_HASH160, adds signer public APIs (constructors, add_key, add_key_from_wif, getters), and replaces manual JS-option helpers with macro-generated extractors for PlatformAddressSignerWasm.
WASM SDK — contract flows
packages/wasm-sdk/src/state_transitions/contract.rs, packages/wasm-sdk/src/state_transitions/mod.rs, packages/js-evo-sdk/src/contracts/facade.ts, tests
Adds contract_publish(options) and contract_update(options) WASM bindings and TS/JS facades; extracts DataContractWasm, IdentityPublicKeyWasm, IdentitySignerWasm, and settings from options and integrates caching/broadcast flows.
WASM SDK — document flows (new)
packages/wasm-sdk/src/state_transitions/document.rs, packages/js-evo-sdk/src/documents/facade.ts, unit & functional tests
Adds full document lifecycle bindings (create/replace/delete/transfer/purchase/setPrice), option parsing, signing, broadcasting, TS types, and test updates to use options objects.
WASM SDK — identity flows (new/refactor)
packages/wasm-sdk/src/state_transitions/identity.rs, packages/wasm-sdk/src/state_transitions/addresses.rs, JS facades/tests
Adds/refactors identity transitions to options-based APIs (create, topUp, creditTransfer, creditWithdrawal, update, masternodeVote), shifts many flows from identifier fetches to IdentityWasm extraction.
WASM SDK — token flows (new)
packages/wasm-sdk/src/state_transitions/token.rs, packages/js-evo-sdk/src/tokens/facade.ts, tests
Introduces option-driven token operations (mint, burn, transfer, freeze, unfreeze, destroyFrozen, emergencyAction, setPrice, directPurchase, claim) with Wasm result wrappers and TS bindings; updates facades/tests.
WASM SDK — module surface & helpers
packages/wasm-sdk/src/state_transitions/mod.rs, packages/wasm-sdk/src/settings.rs, packages/wasm-sdk/src/sdk.rs
Renames modules (contracts→contract, documents→document, tokens→token), adds extract_settings_from_options, get_user_fee_increase, add_contract_to_context_cache, and refresh_identity_nonce.
Tests, fixtures & JS facades
packages/js-evo-sdk/src/*, packages/wasm-sdk/tests/*, packages/js-evo-sdk/tests/*
Large test and facade updates to accept and pass option objects; adds deterministic key-generation helpers and many functional test suites; removes some deprecated test files.
Retry/error handling plan & docs
packages/rs-sdk/docs/IMPROVE_RETRY_ERROR_HANDLING.md, packages/wasm-dpp2/TODO.md
Adds design note to preserve last meaningful error in retry loops, proposes deriving Clone for many error enums and outlines required changes.
Misc / refactors
packages/rs-dpp/src/..., packages/rs-drive-abci/src/..., packages/wasm-dpp2/src/*
Removes verbose tracing in some state-transition code, adjusts genesis token test setup, minor signature additions (macro uses) and small API helpers added/removed.

Sequence Diagram(s)

sequenceDiagram
    participant JS as JavaScript caller
    participant WASM as WasmSdk (wasm_bindgen)
    participant Conv as wasm-dpp2 converters
    participant SDK as Inner Rust SDK (signing/builder)
    participant Network as Platform / Broadcast

    rect rgba(200,230,255,0.4)
    JS->>WASM: call contractPublish(options)
    end

    rect rgba(230,250,230,0.4)
    WASM->>Conv: DataContractWasm::try_from_options(options.dataContract)
    WASM->>Conv: IdentitySignerWasm::try_from_options(options.signer)
    WASM->>WASM: extract_settings_from_options(options.settings)
    end

    rect rgba(255,240,220,0.35)
    WASM->>SDK: build & sign publish transition
    SDK->>Network: broadcast transition
    Network-->>SDK: broadcast result
    SDK-->>WASM: result / published DataContract
    WASM-->>JS: return DataContractWasm
    end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Poem

🐇 I packed the args into one neat chest,

Options tidy, signing dressed,
Converters hop, the cache takes flight,
Tests patrol the new-made night,
Hooray — the bindings sleep alright!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor(sdk)!: typed params for state transition methods' clearly summarizes the main change: refactoring state transition methods to accept typed parameters.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 56db02e and a188c8b.

📒 Files selected for processing (5)
  • packages/js-evo-sdk/tests/unit/facades/contracts.spec.mjs
  • packages/js-evo-sdk/tests/unit/facades/documents.spec.mjs
  • packages/js-evo-sdk/tests/unit/facades/identities.spec.mjs
  • packages/js-evo-sdk/tests/unit/facades/tokens.spec.mjs
  • packages/js-evo-sdk/tests/unit/facades/voting.spec.mjs
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/js-evo-sdk/tests/unit/facades/contracts.spec.mjs
🧰 Additional context used
🧠 Learnings (10)
📚 Learning: 2024-10-18T15:37:21.329Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2249
File: packages/dashmate/test/unit/status/scopes/platform.spec.js:466-467
Timestamp: 2024-10-18T15:37:21.329Z
Learning: In test files for the dashmate project, such as `packages/dashmate/test/unit/status/scopes/platform.spec.js`, prefer to keep mocks explicitly in tests rather than consolidating them, to increase readability.

Applied to files:

  • packages/js-evo-sdk/tests/unit/facades/documents.spec.mjs
  • packages/js-evo-sdk/tests/unit/facades/identities.spec.mjs
  • packages/js-evo-sdk/tests/unit/facades/tokens.spec.mjs
📚 Learning: 2024-10-18T15:37:36.387Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2249
File: packages/dashmate/test/unit/status/scopes/platform.spec.js:77-78
Timestamp: 2024-10-18T15:37:36.387Z
Learning: In `packages/dashmate/test/unit/status/scopes/platform.spec.js`, prefer to keep mocks explicitly in tests to increase readability, rather than refactoring them into shared `beforeEach` blocks or helper functions.

Applied to files:

  • packages/js-evo-sdk/tests/unit/facades/documents.spec.mjs
  • packages/js-evo-sdk/tests/unit/facades/identities.spec.mjs
  • packages/js-evo-sdk/tests/unit/facades/tokens.spec.mjs
📚 Learning: 2025-07-28T20:00:08.502Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2711
File: packages/wasm-sdk/AI_REFERENCE.md:771-783
Timestamp: 2025-07-28T20:00:08.502Z
Learning: In packages/wasm-sdk/AI_REFERENCE.md, the documentation correctly shows the actual SDK method signatures (including identityCreate and identityTopUp with their full parameter lists), which may differ from the UI inputs shown in fixed_definitions.json. The UI may collect fewer parameters from users while handling additional requirements internally.

Applied to files:

  • packages/js-evo-sdk/tests/unit/facades/documents.spec.mjs
  • packages/js-evo-sdk/tests/unit/facades/identities.spec.mjs
  • packages/js-evo-sdk/tests/unit/facades/tokens.spec.mjs
📚 Learning: 2025-07-28T20:00:24.323Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2711
File: packages/wasm-sdk/docs.html:2359-2383
Timestamp: 2025-07-28T20:00:24.323Z
Learning: In packages/wasm-sdk/docs.html, QuantumExplorer confirmed that placeholder private keys in documentation examples are acceptable as they are not real keys, though field name accuracy for the SDK API should still be maintained.

Applied to files:

  • packages/js-evo-sdk/tests/unit/facades/documents.spec.mjs
📚 Learning: 2025-12-29T10:53:03.792Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2868
File: packages/wasm-sdk/tests/functional/addresses.spec.mjs:75-95
Timestamp: 2025-12-29T10:53:03.792Z
Learning: In this repository, tests use the dirty-chai plugin for Chai. Write assertions using the function-call style (e.g., expect(...).to.be.ok()) instead of the property-based style. Ensure dirty-chai is loaded in the test setup and documented so new tests conform to this pattern.

Applied to files:

  • packages/js-evo-sdk/tests/unit/facades/documents.spec.mjs
  • packages/js-evo-sdk/tests/unit/facades/voting.spec.mjs
  • packages/js-evo-sdk/tests/unit/facades/identities.spec.mjs
  • packages/js-evo-sdk/tests/unit/facades/tokens.spec.mjs
📚 Learning: 2025-06-18T03:44:14.385Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2673
File: packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_update/mod.rs:1164-1197
Timestamp: 2025-06-18T03:44:14.385Z
Learning: QuantumExplorer determined that a CodeRabbit suggestion about fixing signable_bytes calculation in identity update tests with contract-bound keys was incorrect - the code flow is working as intended without the suggested changes.

Applied to files:

  • packages/js-evo-sdk/tests/unit/facades/identities.spec.mjs
  • packages/js-evo-sdk/tests/unit/facades/tokens.spec.mjs
📚 Learning: 2024-10-30T11:19:59.163Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/rs-sdk/tests/fetch/config.rs:233-233
Timestamp: 2024-10-30T11:19:59.163Z
Learning: In the Rust SDK's `rs-sdk/tests` integration tests (e.g., in `packages/rs-sdk/tests/fetch/config.rs`), we cannot create objects during tests because there is no support for object creation in this context. Therefore, hardcoded values for test identities must be used.

Applied to files:

  • packages/js-evo-sdk/tests/unit/facades/identities.spec.mjs
📚 Learning: 2025-08-05T13:55:39.147Z
Learnt from: thephez
Repo: dashpay/platform PR: 2718
File: packages/wasm-sdk/index.html:0-0
Timestamp: 2025-08-05T13:55:39.147Z
Learning: The get_identity_keys_with_proof_info function in the Rust WASM bindings does not support the "search" key request type and lacks the searchPurposeMap parameter. When proof mode is enabled with keyRequestType === 'search', the implementation falls back to the non-proof version (get_identity_keys) to maintain functionality.

Applied to files:

  • packages/js-evo-sdk/tests/unit/facades/identities.spec.mjs
📚 Learning: 2025-01-23T02:10:08.979Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2439
File: packages/rs-dpp/src/errors/consensus/state/token/mod.rs:4-22
Timestamp: 2025-01-23T02:10:08.979Z
Learning: The user QuantumExplorer prefers to handle documentation of breaking changes separately from the code changes, particularly for token-related error types and validation rules.

Applied to files:

  • packages/js-evo-sdk/tests/unit/facades/tokens.spec.mjs
📚 Learning: 2025-11-25T13:10:47.943Z
Learnt from: CR
Repo: dashpay/platform PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T13:10:47.943Z
Learning: Applies to **/tests/**/*.{js,jsx,ts,tsx,rs} : Unit and integration tests should not perform network calls; mock dependencies

Applied to files:

  • packages/js-evo-sdk/tests/unit/facades/tokens.spec.mjs
🧬 Code graph analysis (3)
packages/js-evo-sdk/tests/unit/facades/documents.spec.mjs (2)
packages/js-evo-sdk/src/sdk.ts (1)
  • EvoSDK (38-177)
packages/js-evo-sdk/src/documents/facade.ts (1)
  • query (12-15)
packages/js-evo-sdk/tests/unit/facades/identities.spec.mjs (1)
packages/js-evo-sdk/src/sdk.ts (1)
  • EvoSDK (38-177)
packages/js-evo-sdk/tests/unit/facades/tokens.spec.mjs (1)
packages/js-evo-sdk/src/sdk.ts (1)
  • EvoSDK (38-177)
🪛 Gitleaks (8.30.0)
packages/js-evo-sdk/tests/unit/facades/tokens.spec.mjs

[high] 12-12: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: Rust packages (dash-sdk) / Check each feature
  • GitHub Check: Rust packages (dash-sdk) / Tests
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Rust packages (dash-sdk) / Linting
  • GitHub Check: Rust packages (wasm-dpp2) / Unused dependencies
  • GitHub Check: Rust packages (wasm-dpp2) / Linting
  • GitHub Check: Rust packages (rs-sdk-ffi) / Tests
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (dpp) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Detect immutable structure changes
  • GitHub Check: Rust packages (wasm-dpp) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Build JS packages / Build JS
  • GitHub Check: Rust crates security audit
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
🔇 Additional comments (4)
packages/js-evo-sdk/tests/unit/facades/tokens.spec.mjs (1)

1-432: Comprehensive test coverage for options-based token API.

The test suite successfully validates the refactored token facade that now uses options objects instead of individual parameters. The test structure is well-organized with clear groups for static methods, query operations, and state transitions. Mock setup is thorough and realistic, using proper prototype chains for wasm types.

All assertions correctly use the dirty-chai function-call style (e.g., expect(...).to.be.calledOnceWithExactly()), which aligns with the repository's testing conventions.

Note: The static analysis warning on Line 12 about a "Generic API Key" is a false positive. The tokenId constant is a Base58-encoded test identifier (44 characters), not an API key. These identifiers are standard for Dash Platform testing and are safe to use in test fixtures.

packages/js-evo-sdk/tests/unit/facades/documents.spec.mjs (1)

1-189: Well-structured tests for options-based document operations.

The test suite effectively validates the document facade's migration to options-based APIs. The organization into "Query Methods" and "Transition Methods" groups provides clear separation of concerns. Mock setup properly uses Object.create with wasm prototypes, ensuring type consistency.

Notable strengths:

  • Query tests validate structured query objects are forwarded correctly (lines 46-89)
  • Transition tests cover both Document instances and identifier objects for delete operations (lines 118-145)
  • All operations verify exact options objects passed to wasm SDK methods
  • Consistent use of dirty-chai assertion style throughout
packages/js-evo-sdk/tests/unit/facades/voting.spec.mjs (1)

1-198: Thorough test coverage for voting facade refactoring.

The test suite validates the voting facade's transition to options-based APIs with comprehensive coverage of both query and transition operations. The tests properly verify that structured query objects are forwarded to wasm SDK methods without modification.

Key highlights:

  • Query tests cover contested resources, identity votes, and vote polls with pagination support (lines 58-146)
  • Transition tests validate masternodeVote with multiple vote choice scenarios: yes, abstain, and lock (lines 148-196)
  • All tests verify exact options objects are passed through to wasmSdk methods
  • Mock setup uses proper prototype chains for IdentitySigner
packages/js-evo-sdk/tests/unit/facades/identities.spec.mjs (1)

1-329: Extensive test coverage for identity facade operations.

The test suite provides comprehensive validation of the identities facade refactoring with the most extensive coverage of all four test files. The tests properly verify both query and transition operations using the new options-based API pattern.

Strengths:

  • Comprehensive query method coverage: fetch operations, key retrieval, nonces, balances, lookups by public key hash, contract keys, and token balances (lines 111-256)
  • Complete transition method coverage: create, topUp, creditTransfer, creditWithdrawal, and update operations (lines 258-328)
  • Proper validation of return values for operations that return data (e.g., balances, nonces)
  • Mock setup includes all necessary identity-related wasm types (identity, keys, signer, asset lock proof)
  • Tests verify both regular and "WithProof" variants for all applicable operations

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.

@shumkov shumkov marked this pull request as draft December 28, 2025 15:49
@github-actions
Copy link

github-actions bot commented Dec 31, 2025

✅ gRPC Query Coverage Report

================================================================================
gRPC Query Coverage Report - NEW QUERIES ONLY
================================================================================

Total queries in proto: 53
Previously known queries: 47
New queries found: 6

================================================================================

New Query Implementation Status:
--------------------------------------------------------------------------------
✓ getAddressInfo                                /home/runner/work/platform/platform/packages/rs-sdk/src/platform/query.rs
✓ getAddressesBranchState                       /home/runner/work/platform/platform/packages/rs-sdk/src/platform/address_sync/mod.rs
✓ getAddressesInfos                             /home/runner/work/platform/platform/packages/rs-sdk/src/platform/fetch_many.rs
✓ getAddressesTrunkState                        /home/runner/work/platform/platform/packages/rs-sdk/src/platform/address_sync/mod.rs
✓ getRecentAddressBalanceChanges                /home/runner/work/platform/platform/packages/rs-sdk/src/platform/query.rs
✓ getRecentCompactedAddressBalanceChanges       /home/runner/work/platform/platform/packages/rs-sdk/src/platform/query.rs

================================================================================
Summary:
--------------------------------------------------------------------------------
New queries implemented: 6 (100.0%)
New queries missing: 0 (0.0%)

Total known queries: 53
  - Implemented: 50
  - Not implemented: 2
  - Excluded: 1

Not implemented queries:
  - getConsensusParams
  - getTokenPreProgrammedDistributions

@shumkov shumkov marked this pull request as ready for review December 31, 2025 12:53
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: 5

♻️ Duplicate comments (1)
packages/wasm-sdk/tests/functional/protocol.spec.mjs (1)

44-47: Same empty string verification applies here.

This test uses the same fallback pattern as the previous test. The same verification for empty string handling in getProtocolVersionUpgradeVoteStatusWithProofInfo() applies here as well.

🧹 Nitpick comments (16)
packages/rs-sdk/docs/IMPROVE_RETRY_ERROR_HANDLING.md (1)

8-8: Specify language for fenced code blocks.

Markdown linting requires language identifiers on code blocks for consistency and syntax highlighting. Lines 8 and 13 contain code examples without language specifiers.

🔎 Proposed fix
-Example: `getDataContractHistory()` fails with proof verification error, but after all addresses are banned, the user sees:
-```
+Example: `getDataContractHistory()` fails with proof verification error, but after all addresses are banned, the user sees:
+```text
 Dapi client error: no available addresses to use
-```
+```text

 Instead of the meaningful:
-```
+```text
 Proof verification error: <actual error details>
-```
+```text

Also applies to: 13-13

packages/wasm-sdk/tests/functional/epochs-blocks.spec.mjs (2)

20-24: Consider extracting the magic delay constant.

The 100ms delay works, but it's a magic number. Consider extracting it as a named constant for clarity, or adding a brief comment explaining why this specific duration was chosen.

🔎 Optional: Extract named constant
+const CLEANUP_DELAY_MS = 100; // Allow pending microtasks to settle
+
 after(async () => {
-    // Wait briefly to ensure any pending async operations complete
-    await new Promise((resolve) => { setTimeout(resolve, 100); });
+    await new Promise((resolve) => { setTimeout(resolve, CLEANUP_DELAY_MS); });
     if (client) { client.free(); }
   });

65-98: Test may be skipped entirely if no proTxHash is available.

When both evonodeProTxHash is null and byRange returns no results, the core getEvonodesProposedEpochBlocksByIdsWithProofInfo call and its assertions (lines 92-97) are skipped entirely. Consider adding a this.skip() or a log message to make it explicit when this happens, so test runs are transparent about what was actually verified.

🔎 Optional: Make test skip explicit
     // Only test by IDs if we have a valid proTxHash
     if (testProTxHash) {
       const res = await client.getEvonodesProposedEpochBlocksByIdsWithProofInfo(epochIndex, [testProTxHash]);
       expect(res).to.be.ok();
       expect(res.data).to.be.instanceOf(Map);
       expect(res.proof).to.be.ok();
       expect(res.metadata).to.be.ok();
+    } else {
+      this.skip(); // No proTxHash available to test byIds with proof
     }
packages/wasm-sdk/src/wallet/key_generation.rs (1)

268-272: Consider moving imports to module level.

These imports are used only within this function, but module-level imports are conventional in Rust. This is a minor style consideration that doesn't affect functionality.

🔎 Suggested refactor

Move these imports to the top of the file with other imports:

use dash_sdk::dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0;
use dash_sdk::dpp::identity::IdentityPublicKey;
use dash_sdk::dpp::version::LATEST_PLATFORM_VERSION;
use rand::rngs::StdRng;
use rand::SeedableRng;
packages/wasm-sdk/tests/functional/transitions/documents.spec.mjs (1)

192-195: Consider more meaningful assertions for replace/delete/transfer tests.

expect(true).to.be.true is essentially a no-op. While the tests do verify success implicitly (no exception thrown), consider asserting on the operation result or fetching the document to verify the change. Based on learnings, use dirty-chai function-call style.

🔎 Example improvement for documentReplace
// After replace, optionally fetch and verify the document was updated
// Or at minimum, use a more descriptive assertion pattern
// The current approach relies on "no throw = success" which is valid but weak
packages/wasm-sdk/src/state_transitions/document.rs (2)

29-39: Consider consolidating string extraction with other option utilities.

extract_string_from_options is only used once (line 373 for documentTypeName). Consider either:

  1. Moving to the shared utils module if it will be reused
  2. Inlining at the call site if truly single-use

105-106: Document cloning may be unnecessary.

document_wasm.clone() is called even though document_wasm is consumed immediately after. This pattern repeats in replace, transfer, purchase, and set_price methods. Consider using the value directly without cloning when possible.

🔎 Example for document_create
-        let document: Document = document_wasm.clone().into();
+        let document: Document = document_wasm.into();

Note: This depends on whether document_wasm is used after the conversion. Check each method individually.

packages/wasm-dpp2/src/private_key.rs (1)

129-151: Implementation looks correct.

The try_from_options method properly validates field presence and handles conversions with clear error messages. The pattern is consistent with similar manual implementations in this PR.

Consider whether this manual implementation could use the impl_try_from_options! macro for consistency with other types like IdentityWasm, CoreScriptWasm, and DocumentWasm. The manual approach may be necessary due to the IntoWasm trait usage, but verifying this would improve codebase uniformity.

packages/wasm-dpp2/src/identifier.rs (1)

297-316: Implementation is correct.

The try_from_options method properly validates field presence and delegates to the existing try_from implementation. Error handling is clear and consistent.

Similar to PrivateKeyWasm, consider whether the impl_try_from_options! macro could be used here for consistency with types like IdentityWasm and DocumentWasm, assuming the macro can accommodate the conversion logic.

packages/wasm-sdk/tests/functional/transitions/contracts.spec.mjs (1)

87-156: Test dependency between suites.

The contractUpdate test depends on createdContractId being set by the prior contractPublish test. While Mocha runs tests sequentially by default (making this work), this creates an implicit ordering dependency. Consider documenting this dependency explicitly or using a shared setup if the tests ever need to run independently.

The test logic itself is sound—proper security level selection (CRITICAL for updates), nonce cache refresh, schema augmentation, and version verification.

packages/wasm-sdk/tests/functional/transitions/identity.spec.mjs (1)

126-158: Test interdependency between add and disable key tests.

The "disables a public key" test (line 126) depends on the previous "adds a new public key" test having successfully added a MEDIUM-level key. Line 141 asserts keyToDisable exists, which will fail if the previous test didn't run or failed.

This is acceptable for functional/integration tests where sequential operations are being validated, but consider adding a comment noting the dependency.

🔎 Suggested documentation improvement
   it('disables a public key on identity', async function testDisablePublicKey() {
+    // Note: This test depends on the previous test having added a MEDIUM-level key
     // Identity update requires MASTER key (key index 0)
     const { signer } = createTestSignerAndKey(sdk, 1, 0);
packages/wasm-dpp2/src/identity/signer.rs (1)

103-137: Multi-key-type support correctly implemented, but clippy warning should be addressed.

The get_key_hash method properly distinguishes between ECDSA_HASH160 (20-byte hash) and ECDSA_SECP256K1 (33-byte compressed pubkey that needs hashing). The logic is sound.

However, clippy reports result_large_err because ProtocolError is at least 768 bytes. Since ProtocolError is from the dpp crate, you can suppress this locally:

🔎 Proposed fix to suppress clippy warning
+    #[allow(clippy::result_large_err)]
     fn get_key_hash(identity_public_key: &IdentityPublicKey) -> Result<[u8; 20], ProtocolError> {

Alternatively, if this pattern is widespread, consider using Box<ProtocolError> in the Err variant at a higher level, but that would require broader changes to the dpp crate.

packages/wasm-sdk/src/state_transitions/token.rs (3)

329-338: Redundant call to extract_settings_from_options for user fee increase.

Settings are already extracted on line 300 and stored in settings. The code on lines 334-335 calls extract_settings_from_options again, which duplicates the deserialization work.

🔎 Proposed fix to reuse the already-extracted settings
         // Add user fee increase from settings
-        let user_fee_increase =
-            get_user_fee_increase(extract_settings_from_options(&options_value)?.as_ref());
+        let user_fee_increase = get_user_fee_increase(settings.as_ref());
         if user_fee_increase > 0 {
             builder = builder.with_user_fee_increase(user_fee_increase);
         }

584-589: Same redundant extract_settings_from_options pattern in token_burn.

This pattern is repeated across multiple token operations. Consider fixing this in all places for consistency and efficiency.

🔎 Proposed fix
         // Add user fee increase from settings
-        let user_fee_increase =
-            get_user_fee_increase(extract_settings_from_options(&options_value)?.as_ref());
+        let user_fee_increase = get_user_fee_increase(settings.as_ref());
         if user_fee_increase > 0 {
             builder = builder.with_user_fee_increase(user_fee_increase);
         }

831-836: Repeated redundant extract_settings_from_options calls across all token operations.

This same pattern appears in token_transfer (831-836), token_freeze (1061-1066), token_unfreeze (1291-1296), token_destroy_frozen (1502-1507), token_emergency_action (1726-1731), token_claim (1935-1940), token_set_price (2177-2182), and token_direct_purchase (2399-2404).

Consider refactoring all of these to reuse the already-extracted settings variable.

Also applies to: 1061-1066, 1291-1296, 1502-1507, 1726-1731, 1935-1940, 2177-2182, 2399-2404

packages/wasm-sdk/src/state_transitions/addresses.rs (1)

924-931: Identity extraction in identity_create_from_addresses uses different pattern than other methods.

Lines 924-931 use manual js_sys::Reflect::get and to_wasm for identity extraction, while other methods in this file (lines 303-304, 511-512) use IdentityWasm::try_from_options. Consider using the consistent pattern for uniformity.

🔎 Proposed fix for consistency
-        // Extract identity from options
-        let identity_js = js_sys::Reflect::get(&options_value, &JsValue::from_str("identity"))
-            .map_err(|_| WasmSdkError::invalid_argument("identity is required"))?;
-        let identity: Identity = identity_js
-            .to_wasm::<wasm_dpp2::IdentityWasm>("Identity")?
-            .clone()
-            .into();
+        // Extract identity from options
+        let identity: Identity = IdentityWasm::try_from_options(&options_value, "identity")?.into();

Comment on lines +738 to +767
impl From<TransferResult> for TokenTransferResultWasm {
fn from(result: TransferResult) -> Self {
match result {
TransferResult::IdentitiesBalances(balances) => {
// Get the first two balances (sender and recipient)
let mut iter = balances.into_values();
let first_balance = iter.next();
let second_balance = iter.next();
TokenTransferResultWasm {
sender_balance: first_balance,
recipient_balance: second_balance,
group_power: None,
document: None,
}
}
TransferResult::HistoricalDocument(doc) => TokenTransferResultWasm {
sender_balance: None,
recipient_balance: None,
group_power: None,
document: Some(doc.into()),
},
TransferResult::GroupActionWithDocument(power, doc) => TokenTransferResultWasm {
sender_balance: None,
recipient_balance: None,
group_power: Some(power as u32),
document: doc.map(|d| d.into()),
},
}
}
}
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 | 🟠 Major

TransferResult::IdentitiesBalances conversion may incorrectly assign sender/recipient balances.

The conversion iterates over balances.into_values() and assigns the first value to sender_balance and the second to recipient_balance. However, BTreeMap::into_values() (or similar) iterates in key order, not insertion order. If the recipient's identifier sorts before the sender's, the balances will be swapped.

Consider returning both balances with their corresponding identifiers, or document that the order is based on identifier sorting rather than semantic sender/recipient roles.

🔎 Proposed fix - return identifiers with balances
 #[wasm_bindgen(js_name = "TokenTransferResult")]
 pub struct TokenTransferResultWasm {
-    /// For IdentitiesBalances result - sender's new balance
-    sender_balance: Option<u64>,
-    /// For IdentitiesBalances result - recipient's new balance
-    recipient_balance: Option<u64>,
+    /// For IdentitiesBalances result - first identity ID
+    first_identity_id: Option<IdentifierWasm>,
+    /// For IdentitiesBalances result - first identity's new balance
+    first_balance: Option<u64>,
+    /// For IdentitiesBalances result - second identity ID
+    second_identity_id: Option<IdentifierWasm>,
+    /// For IdentitiesBalances result - second identity's new balance
+    second_balance: Option<u64>,
     // ... rest unchanged
 }

And update the From impl accordingly to preserve identity-balance associations.

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +859 to +904
export interface TokenFreezeOptions {
/**
* The ID of the data contract containing the token.
*/
dataContractId: Identifier;
/**
* The position of the token in the contract (0-indexed).
*/
tokenPosition: number;
/**
* The identity ID of the token authority performing the freeze.
*/
authorityId: Identifier;
/**
* The identity ID to freeze.
*/
frozenIdentityId: Identifier;
/**
* Optional public note for the freeze operation.
*/
publicNote?: string;
/**
* Signer containing the private key for the authority's authentication key.
* Use IdentitySigner to add the authentication key before calling.
*/
signer: IdentitySigner;
/**
* Optional group action info for group-managed token freezing.
* Use GroupStateTransitionInfoStatus.proposer() to propose a new group action,
* or GroupStateTransitionInfoStatus.otherSigner() to vote on an existing action.
*/
groupInfo?: GroupStateTransitionInfoStatus;
/**
* Optional settings for the broadcast operation.
* Includes retries, timeouts, userFeeIncrease, etc.
*/
settings?: PutSettings;
}
"#;
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 | 🟠 Major

TypeScript interfaces for TokenFreezeOptions and TokenDestroyFrozenOptions are missing identityKey field.

Looking at lines 859-904 (TokenFreezeOptions) and 1313-1363 (TokenDestroyFrozenOptions), the identityKey field is not documented in the TypeScript interfaces, but the Rust code attempts to extract it (lines 1022-1024 and 1463-1465). This mismatch could cause runtime errors.

🔎 Proposed fix for TokenFreezeOptions

Add after line 889 in the TypeScript interface:

  /**
   * The identity public key to use for signing the transition.
   */
  identityKey: IdentityPublicKey;

Also applies to: 1313-1363

🤖 Prompt for AI Agents
In packages/wasm-sdk/src/state_transitions/token.rs around lines 859-904 and
1313-1363, the TypeScript interfaces TokenFreezeOptions and
TokenDestroyFrozenOptions are missing the identityKey field referenced by the
Rust extraction code; add a new documented property named identityKey of type
IdentityPublicKey to both interfaces (insert it near the signer field or where
identity-related fields are grouped) so the TypeScript definitions match the
Rust usage and prevent runtime mismatches.

Comment on lines +2079 to +2106
impl From<SetPriceResult> for TokenSetPriceResultWasm {
fn from(result: SetPriceResult) -> Self {
match result {
SetPriceResult::PricingSchedule(_owner_id, _schedule) => TokenSetPriceResultWasm {
group_power: None,
group_action_status: None,
document: None,
},
SetPriceResult::HistoricalDocument(doc) => TokenSetPriceResultWasm {
group_power: None,
group_action_status: None,
document: Some(doc.into()),
},
SetPriceResult::GroupActionWithDocument(power, doc) => TokenSetPriceResultWasm {
group_power: Some(power as u32),
group_action_status: None,
document: doc.map(|d| d.into()),
},
SetPriceResult::GroupActionWithPricingSchedule(power, status, _schedule) => {
TokenSetPriceResultWasm {
group_power: Some(power as u32),
group_action_status: Some(format!("{:?}", status)),
document: None,
}
}
}
}
}
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

SetPriceResult::PricingSchedule variant discards useful information.

When the result is PricingSchedule(owner_id, schedule), both the owner ID and the pricing schedule are discarded. The WASM result returns None for all fields, which provides no useful information to the caller.

Consider exposing at least the owner_id or a boolean indicating success, so callers can distinguish this result variant from an error state.

🤖 Prompt for AI Agents
In packages/wasm-sdk/src/state_transitions/token.rs around lines 2079 to 2106,
the match arm for SetPriceResult::PricingSchedule currently returns all None and
discards owner_id and schedule; update that arm to preserve useful info by
populating at least one field: include the owner_id (e.g., group_action_status:
Some(owner_id.to_string())) or, if schedule is convertible to the WASM document
type, set document: Some(schedule.into()); ensure any necessary conversions are
available and adjust field choices to match TokenSetPriceResultWasm types so
callers can distinguish PricingSchedule from error cases.

Comment on lines +119 to +130
/**
* Convert hex string to Uint8Array
* @param {string} hex - Hex string
* @returns {Uint8Array} Byte array
*/
function hexToBytes(hex) {
const bytes = new Uint8Array(hex.length / 2);
for (let i = 0; i < hex.length; i += 2) {
bytes[i / 2] = parseInt(hex.substr(i, 2), 16);
}
return bytes;
}
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

hexToBytes function is defined but never used.

This helper function is not exported and not used within this file. Consider removing it or using it where applicable.

🔎 Suggested fix

Remove the unused function:

-/**
- * Convert hex string to Uint8Array
- * @param {string} hex - Hex string
- * @returns {Uint8Array} Byte array
- */
-function hexToBytes(hex) {
-  const bytes = new Uint8Array(hex.length / 2);
-  for (let i = 0; i < hex.length; i += 2) {
-    bytes[i / 2] = parseInt(hex.substr(i, 2), 16);
-  }
-  return bytes;
-}
📝 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
/**
* Convert hex string to Uint8Array
* @param {string} hex - Hex string
* @returns {Uint8Array} Byte array
*/
function hexToBytes(hex) {
const bytes = new Uint8Array(hex.length / 2);
for (let i = 0; i < hex.length; i += 2) {
bytes[i / 2] = parseInt(hex.substr(i, 2), 16);
}
return bytes;
}
🤖 Prompt for AI Agents
In packages/wasm-sdk/tests/functional/fixtures/requiredTestData.mjs around lines
119 to 130, the helper function hexToBytes is defined but never used or
exported; remove the unused function definition to eliminate dead code, or if
it’s intended for reuse, export it (export function hexToBytes...) and update
callers to import and use it; choose removal if not required by tests to keep
the fixture file minimal.

Comment on lines +10 to +14
* Test identities:
* - Identity 1: 4vJ9JU1bJJE96FWSJKvHsmmFADCg4gpZQff4P3bkLKi
* - Identity 2: 8pkwN93v4wTWzzJAJkBCVPQJHMGwNa9TYfJUW24sAq11
* - Identity 3: CktRuQ2mttgRGkXJtyksdKHjUdc2C4TgDzyB98oEzy8
*
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

Identity 2 ID in comment doesn't match fixture.

The comment on line 12 shows 8pkwN93v4wTWzzJAJkBCVPQJHMGwNa9TYfJUW24sAq11 but the fixture in requiredTestData.mjs defines identityId2 as 8qbHbw2BbbTHBW1sbeqakYXVKRQM8Ne7pLK7m6CVfeR.

🔎 Suggested fix
 * Test identities:
 * - Identity 1: 4vJ9JU1bJJE96FWSJKvHsmmFADCg4gpZQff4P3bkLKi
-* - Identity 2: 8pkwN93v4wTWzzJAJkBCVPQJHMGwNa9TYfJUW24sAq11
+* - Identity 2: 8qbHbw2BbbTHBW1sbeqakYXVKRQM8Ne7pLK7m6CVfeR
 * - Identity 3: CktRuQ2mttgRGkXJtyksdKHjUdc2C4TgDzyB98oEzy8

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

Labels

None yet

Projects

Status: In review / testing

Development

Successfully merging this pull request may close these issues.

2 participants