Skip to content

feat(wasm-sdk): add shielded pool WASM bindings and query methods#3235

Open
QuantumExplorer wants to merge 6 commits intov3.1-devfrom
feat/zk-wasm-js-bindings
Open

feat(wasm-sdk): add shielded pool WASM bindings and query methods#3235
QuantumExplorer wants to merge 6 commits intov3.1-devfrom
feat/zk-wasm-js-bindings

Conversation

@QuantumExplorer
Copy link
Member

@QuantumExplorer QuantumExplorer commented Mar 12, 2026

Issue being fixed or feature implemented

Adds the WASM/JS layer for shielded pool functionality in wasm-dpp2 and wasm-sdk.

What was done?

wasm-dpp2: Shielded state transition wrappers

  • ShieldTransitionWasm — shield (deposit) with inputs, actions, amount, proof, binding signature
  • ShieldFromAssetLockTransitionWasm — shield from asset lock with proof verification
  • ShieldedTransferTransitionWasm — private transfer between shielded addresses
  • UnshieldTransitionWasm — withdraw from shielded pool to transparent address
  • ShieldedWithdrawalTransitionWasm — withdraw from shielded pool to core chain
  • computePlatformSighash utility function exposed to JS
  • All wrappers include toBytes/fromBytes/toJSON/toObject/toStateTransition/getModifiedDataIds
  • Replaced todo!() panics in StateTransitionWasm for shielded variants with proper handling

wasm-sdk: Shielded pool query methods

  • getShieldedPoolState — total shielded pool balance (BigInt)
  • getShieldedEncryptedNotes(startIndex, count) — paginated encrypted notes
  • getShieldedAnchors — valid anchors for Orchard spend proofs
  • getMostRecentShieldedAnchor — latest 32-byte anchor
  • getShieldedNullifiers(nullifiers) — check nullifier spent/unspent status
  • All 5 queries have WithProofInfo variants returning ProofMetadataResponse<T>
  • ShieldedEncryptedNoteWasm and ShieldedNullifierStatusWasm wrapper types with TypeScript interfaces

How Has This Been Tested?

  • cargo check -p wasm-dpp2
  • cargo check -p wasm-sdk
  • cargo clippy -p wasm-dpp2 ✅ (no warnings)
  • cargo clippy -p wasm-sdk ✅ (no warnings)
  • cargo fmt

Breaking Changes

None. All additions are new public API.

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 tests
  • I have made corresponding changes to the documentation
  • I have added the PR to a milestone (if applicable)

🤖 Generated with Claude Code

…thods

Add WASM bindings for all 5 shielded state transition types in wasm-dpp2:
- ShieldTransitionWasm
- ShieldedTransferTransitionWasm
- UnshieldTransitionWasm
- ShieldFromAssetLockTransitionWasm
- ShieldedWithdrawalTransitionWasm

Each wrapper exposes type-specific getters (anchor, proof, binding signature,
actions, etc.), serialization (toBytes/fromBytes/toJSON/toObject), and
toStateTransition conversion following wasm-dpp2 patterns.

Also adds computePlatformSighash utility for constructing the platform sighash
used by Orchard binding signatures.

Replaces all shielded todo!() panics in wasm-dpp2's StateTransitionWasm with
proper None returns or error messages for identityContractNonce, identityNonce,
setOwnerId, setIdentityContractNonce, and setIdentityNonce.

Updates wasm-dpp to:
- Register shielded types (15-19) in StateTransitionTypeWasm enum
- Handle shielded transitions in createFromBuffer factory via serde

Adds JS SDK shielded methods (platform.shielded.*):
- shield, shieldedTransfer, unshield, shieldFromAssetLock, shieldedWithdrawal
All accept pre-serialized transition bytes and broadcast with skipValidation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 12, 2026

Warning

Rate limit exceeded

@QuantumExplorer has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 6 minutes and 37 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 54aa90cd-a74a-4513-a54c-93a94913330a

📥 Commits

Reviewing files that changed from the base of the PR and between c5325c9 and 98a20b6.

📒 Files selected for processing (5)
  • packages/wasm-dpp2/src/shielded/mod.rs
  • packages/wasm-dpp2/src/state_transitions/proof_result.rs
  • packages/wasm-sdk/src/lib.rs
  • packages/wasm-sdk/src/queries/mod.rs
  • packages/wasm-sdk/src/queries/shielded.rs
📝 Walkthrough

Walkthrough

This PR introduces comprehensive shielded state transition support to the Dash SDK by adding five new shielded methods (shield, shieldedTransfer, unshield, shieldFromAssetLock, shieldedWithdrawal) to the Platform class and implementing WebAssembly bindings for the corresponding transition types.

Changes

Cohort / File(s) Summary
Platform Shielded Namespace
packages/js-dash-sdk/src/SDK/Client/Platform/Platform.ts
Added new Shielded interface and shielded member on Platform, grouping five shield-related methods under a single namespace with bound implementations.
Shielded Method Implementations
packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shield.ts, shieldedTransfer.ts, unshield.ts, shieldFromAssetLock.ts, shieldedWithdrawal.ts
Five new async methods that serialize, initialize platform, construct state transitions via DPP, and broadcast with skipValidation enabled. Each follows an identical pattern with debug/silly logging.
WASM DPP Enum Support
packages/wasm-dpp/src/identity/state_transition/transition_types.rs, state_transition/state_transition_factory.rs
Added five new enum variants (Shield, ShieldedTransfer, Unshield, ShieldFromAssetLock, ShieldedWithdrawal) to StateTransitionTypeWasm and replaced placeholder todos with concrete mappings in state transition factory.
WASM DPP2 Module Surface
packages/wasm-dpp2/src/lib.rs, shielded/mod.rs
Added public shielded module with exports for five Wasm transition types and a new compute_platform_sighash_wasm function with input validation for bundle_commitment length.
WASM Shielded Transition Wrappers
packages/wasm-dpp2/src/shielded/shield_transition.rs, shielded_transfer_transition.rs, unshield_transition.rs, shieldFromAssetLockTransition.rs, shieldedWithdrawalTransition.rs
Five new Wasm wrapper types (ShieldTransitionWasm, ShieldedTransferTransitionWasm, UnshieldTransitionWasm, ShieldFromAssetLockTransitionWasm, ShieldedWithdrawalTransitionWasm) exposing comprehensive getters, serialization helpers (to/from bytes, JSON, object), and state transition conversions via wasm_bindgen.
State Transition Error Handling
packages/wasm-dpp2/src/state_transitions/base/state_transition.rs
Converted placeholder panic-like todos for shielded withdrawal to None returns in getters; added invalid_argument error returns for set operations (setOwnerId, setIdentityContractNonce, setIdentityNonce) on shielded transitions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Five shielded transitions bloom,
WASM wrappers light the room,
Platform methods cast their charm,
Broadcasting transitions warm,
Privacy and safety arm in arm!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main addition: shielded pool WASM bindings and query/broadcast methods across wasm-dpp2, wasm-dpp, and js-dash-sdk packages.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/zk-wasm-js-bindings
📝 Coding Plan
  • Generate coding plan for human review comments

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.

@github-actions github-actions bot added this to the v3.1.0 milestone Mar 12, 2026
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: 4

🧹 Nitpick comments (3)
packages/wasm-dpp2/src/shielded/mod.rs (1)

28-33: Consider consistent validation style.

The length validation and conversion on lines 28-34 is correct, but expect("checked length above") could be replaced with unwrap() for consistency, since the length is already validated. This is a minor style preference.

♻️ Optional: use unwrap() after validation
     if bundle_commitment.len() != 32 {
         return Err(crate::error::WasmDppError::invalid_argument(&format!(
             "bundleCommitment must be exactly 32 bytes, got {}",
             bundle_commitment.len()
         )));
     }
-    let commitment: &[u8; 32] = bundle_commitment.try_into().expect("checked length above");
+    let commitment: &[u8; 32] = bundle_commitment.try_into().unwrap();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/wasm-dpp2/src/shielded/mod.rs` around lines 28 - 33, Replace the
post-validation call that uses expect("checked length above") with unwrap() for
stylistic consistency: after you validate bundle_commitment.len() != 32 and
return an error, use unwrap() when converting/creating the fixed-size array (the
same spot currently calling expect) so the code relies on the prior check and
matches the project's validation style (refer to the bundle_commitment length
check and the conversion site where expect("checked length above") is used).
packages/wasm-dpp2/src/shielded/shielded_transfer_transition.rs (1)

88-116: Add a round-trip test for this wasm-facing ABI.

toBytes/fromBytes plus the JS-visible getters are new public surface, and this PR explicitly ships without test updates. A small round-trip/golden test here would catch wire-format drift and wrong-variant regressions before they reach the SDK.

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

In `@packages/wasm-dpp2/src/shielded/shielded_transfer_transition.rs` around lines
88 - 116, Add a round-trip unit test exercising the wasm ABI: construct a
ShieldedTransferTransitionWasm instance, call to_bytes(), pass the bytes into
from_bytes() and assert the resulting ShieldedTransferTransitionWasm equals the
original; also include a JSON round-trip by calling to_json() and verifying the
serialized value round-trips (or matches expected golden JSON), and verify
to_state_transition() produces the expected StateTransition variant. Target the
wasm-facing symbols to_bytes, from_bytes, to_json, to_state_transition and
assert equality of the core inner StateTransition::ShieldedTransfer data to
catch wire-format or variant regressions.
packages/js-dash-sdk/src/SDK/Client/Platform/Platform.ts (1)

202-208: Consider a shared helper for the shielded broadcast path.

These five bindings fan out to near-identical modules today. Once you add the missing decoded-type guard or any future validation/logging tweak, you'll need to keep five copies in sync. A small helper that takes { expectedType, logPrefix } would make this surface much harder to drift.

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

In `@packages/js-dash-sdk/src/SDK/Client/Platform/Platform.ts` around lines 202 -
208, The five near-identical bindings under this.shielded (shield,
shieldedTransfer, unshield, shieldFromAssetLock, shieldedWithdrawal) duplicate
broadcast/validation logic; extract a small helper (e.g.,
createShieldedBinder(expectedType, logPrefix)) that returns a bound function
given a method reference and metadata, then replace the direct .bind(this) calls
with calls to that helper (pass the original method function like shieldMethod,
shieldedTransferMethod, unshieldMethod, shieldFromAssetLockMethod,
shieldedWithdrawalMethod and the appropriate expectedType/logPrefix) so shared
decoded-type guards, validation and logging live in one place.
🤖 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/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shield.ts`:
- Around line 24-31: After deserializing the transition with
dpp.stateTransition.createFromBuffer in shield(), add a type guard that checks
transition.getType() and ensure it matches the expected StateTransition type for
shield (e.g., ShieldedTransfer/Shield/ShieldFromAssetLock/ShieldedWithdrawal as
appropriate) before calling broadcastStateTransition(this, await transition,
...); if the type does not match, throw or return a clear error. Apply the same
guard/check (use .getType() on the result of
dpp.stateTransition.createFromBuffer) to all other shielded entrypoints so each
only accepts its intended StateTransition variant prior to calling
broadcastStateTransition.

In `@packages/js-dash-sdk/src/SDK/Client/Platform/Platform.ts`:
- Around line 37-41: The three new shielded module filenames use mixed/camel
casing; rename the files shieldFromAssetLock.ts, shieldedTransfer.ts, and
shieldedWithdrawal.ts to kebab-case (shield-from-asset-lock.ts,
shielded-transfer.ts, shielded-withdrawal.ts) and update all imports/exports
referencing them (e.g., the imports in Platform.ts: shieldFromAssetLockMethod,
shieldedTransferMethod, shieldedWithdrawalMethod) to use the new kebab-case
paths; also update any barrel/index exports and tests or references across the
repo to the new filenames so imports remain consistent.

In `@packages/wasm-dpp/src/state_transition/state_transition_factory.rs`:
- Around line 82-96: The Shield-related state transition variants
(StateTransition::Shield, ::ShieldedTransfer, ::Unshield, ::ShieldFromAssetLock,
::ShieldedWithdrawal) call serde_wasm_bindgen::to_value(&st) but fail to compile
because the Serialize impls are behind the rs-dpp "serde-conversion" feature;
fix this by enabling that feature for the dpp dependency in wasm-dpp's
Cargo.toml (add "serde-conversion" to the features list for dpp) so those types
derive Serialize and serde_wasm_bindgen::to_value(&st) will compile.

In `@packages/wasm-dpp2/src/shielded/mod.rs`:
- Around line 16-36: The doc comment for compute_platform_sighash_wasm
incorrectly states that extraData includes an amount for unshield and shielded
withdrawal transitions; update the comment to match the rs-dpp implementation by
removing references to amount and describing extraData as just the output
address bytes for unshield transitions and the output script bytes for shielded
withdrawal transitions (see the extra_sighash_data construction in unshield.rs
and shielded_withdrawal.rs for reference).

---

Nitpick comments:
In `@packages/js-dash-sdk/src/SDK/Client/Platform/Platform.ts`:
- Around line 202-208: The five near-identical bindings under this.shielded
(shield, shieldedTransfer, unshield, shieldFromAssetLock, shieldedWithdrawal)
duplicate broadcast/validation logic; extract a small helper (e.g.,
createShieldedBinder(expectedType, logPrefix)) that returns a bound function
given a method reference and metadata, then replace the direct .bind(this) calls
with calls to that helper (pass the original method function like shieldMethod,
shieldedTransferMethod, unshieldMethod, shieldFromAssetLockMethod,
shieldedWithdrawalMethod and the appropriate expectedType/logPrefix) so shared
decoded-type guards, validation and logging live in one place.

In `@packages/wasm-dpp2/src/shielded/mod.rs`:
- Around line 28-33: Replace the post-validation call that uses expect("checked
length above") with unwrap() for stylistic consistency: after you validate
bundle_commitment.len() != 32 and return an error, use unwrap() when
converting/creating the fixed-size array (the same spot currently calling
expect) so the code relies on the prior check and matches the project's
validation style (refer to the bundle_commitment length check and the conversion
site where expect("checked length above") is used).

In `@packages/wasm-dpp2/src/shielded/shielded_transfer_transition.rs`:
- Around line 88-116: Add a round-trip unit test exercising the wasm ABI:
construct a ShieldedTransferTransitionWasm instance, call to_bytes(), pass the
bytes into from_bytes() and assert the resulting ShieldedTransferTransitionWasm
equals the original; also include a JSON round-trip by calling to_json() and
verifying the serialized value round-trips (or matches expected golden JSON),
and verify to_state_transition() produces the expected StateTransition variant.
Target the wasm-facing symbols to_bytes, from_bytes, to_json,
to_state_transition and assert equality of the core inner
StateTransition::ShieldedTransfer data to catch wire-format or variant
regressions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2bdbcf86-45ca-47c6-ba00-fc5f4eeab635

📥 Commits

Reviewing files that changed from the base of the PR and between 037c387 and c5325c9.

📒 Files selected for processing (16)
  • packages/js-dash-sdk/src/SDK/Client/Platform/Platform.ts
  • packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shield.ts
  • packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shieldFromAssetLock.ts
  • packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shieldedTransfer.ts
  • packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shieldedWithdrawal.ts
  • packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/unshield.ts
  • packages/wasm-dpp/src/identity/state_transition/transition_types.rs
  • packages/wasm-dpp/src/state_transition/state_transition_factory.rs
  • packages/wasm-dpp2/src/lib.rs
  • packages/wasm-dpp2/src/shielded/mod.rs
  • packages/wasm-dpp2/src/shielded/shield_from_asset_lock_transition.rs
  • packages/wasm-dpp2/src/shielded/shield_transition.rs
  • packages/wasm-dpp2/src/shielded/shielded_transfer_transition.rs
  • packages/wasm-dpp2/src/shielded/shielded_withdrawal_transition.rs
  • packages/wasm-dpp2/src/shielded/unshield_transition.rs
  • packages/wasm-dpp2/src/state_transitions/base/state_transition.rs

QuantumExplorer and others added 2 commits March 13, 2026 01:50
js-dash-sdk uses wasm-dpp (not wasm-dpp2), so shielded bindings there
belong in a separate effort. This PR focuses on wasm-sdk + wasm-dpp2 only.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds 10 query methods to WasmSdk for the shielded pool:
- getShieldedPoolState / WithProofInfo — total shielded balance
- getShieldedEncryptedNotes / WithProofInfo — paginated encrypted notes
- getShieldedAnchors / WithProofInfo — valid spend anchors
- getMostRecentShieldedAnchor / WithProofInfo — latest anchor
- getShieldedNullifiers / WithProofInfo — nullifier spent status

Also adds ShieldedEncryptedNoteWasm and ShieldedNullifierStatusWasm
wrapper types with TypeScript interface declarations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@QuantumExplorer QuantumExplorer changed the title feat(wasm-dpp2,js-sdk): add shielded pool WASM bindings and JS SDK methods feat(wasm-dpp2,wasm-sdk): add shielded pool WASM bindings and query methods Mar 12, 2026
Replace todo!() panics for shielded proof result variants with proper
WASM wrapper types:
- VerifiedAssetLockConsumed (status + credit values)
- VerifiedShieldedNullifiers (nullifier → isSpent map)
- VerifiedShieldedNullifiersWithAddressInfos
- VerifiedShieldedNullifiersWithWithdrawalDocument

This enables broadcasting shielded state transitions through wasm-sdk
without panicking on proof verification results.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@QuantumExplorer QuantumExplorer changed the title feat(wasm-dpp2,wasm-sdk): add shielded pool WASM bindings and query methods feat(wasm-sdk): add shielded pool WASM bindings and query methods Mar 12, 2026
QuantumExplorer and others added 2 commits March 13, 2026 02:05
The doc comment incorrectly stated that extraData includes amount for
unshield and shielded withdrawal transitions. The actual rs-dpp
implementation only uses the address/script bytes without amount.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix clippy::needless_borrows_for_generic_args — `&format!()` → `format!()`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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