feat(wasm-sdk): add shielded pool WASM bindings and query methods#3235
feat(wasm-sdk): add shielded pool WASM bindings and query methods#3235QuantumExplorer wants to merge 6 commits intov3.1-devfrom
Conversation
…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>
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the 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 configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughThis 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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
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. Comment |
There was a problem hiding this comment.
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 withunwrap()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/fromBytesplus 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
📒 Files selected for processing (16)
packages/js-dash-sdk/src/SDK/Client/Platform/Platform.tspackages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shield.tspackages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shieldFromAssetLock.tspackages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shieldedTransfer.tspackages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shieldedWithdrawal.tspackages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/unshield.tspackages/wasm-dpp/src/identity/state_transition/transition_types.rspackages/wasm-dpp/src/state_transition/state_transition_factory.rspackages/wasm-dpp2/src/lib.rspackages/wasm-dpp2/src/shielded/mod.rspackages/wasm-dpp2/src/shielded/shield_from_asset_lock_transition.rspackages/wasm-dpp2/src/shielded/shield_transition.rspackages/wasm-dpp2/src/shielded/shielded_transfer_transition.rspackages/wasm-dpp2/src/shielded/shielded_withdrawal_transition.rspackages/wasm-dpp2/src/shielded/unshield_transition.rspackages/wasm-dpp2/src/state_transitions/base/state_transition.rs
packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shield.ts
Outdated
Show resolved
Hide resolved
packages/wasm-dpp/src/state_transition/state_transition_factory.rs
Outdated
Show resolved
Hide resolved
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>
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>
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>
Issue being fixed or feature implemented
Adds the WASM/JS layer for shielded pool functionality in
wasm-dpp2andwasm-sdk.What was done?
wasm-dpp2: Shielded state transition wrappers
ShieldTransitionWasm— shield (deposit) with inputs, actions, amount, proof, binding signatureShieldFromAssetLockTransitionWasm— shield from asset lock with proof verificationShieldedTransferTransitionWasm— private transfer between shielded addressesUnshieldTransitionWasm— withdraw from shielded pool to transparent addressShieldedWithdrawalTransitionWasm— withdraw from shielded pool to core chaincomputePlatformSighashutility function exposed to JStoBytes/fromBytes/toJSON/toObject/toStateTransition/getModifiedDataIdstodo!()panics inStateTransitionWasmfor shielded variants with proper handlingwasm-sdk: Shielded pool query methods
getShieldedPoolState— total shielded pool balance (BigInt)getShieldedEncryptedNotes(startIndex, count)— paginated encrypted notesgetShieldedAnchors— valid anchors for Orchard spend proofsgetMostRecentShieldedAnchor— latest 32-byte anchorgetShieldedNullifiers(nullifiers)— check nullifier spent/unspent statusWithProofInfovariants returningProofMetadataResponse<T>ShieldedEncryptedNoteWasmandShieldedNullifierStatusWasmwrapper types with TypeScript interfacesHow 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
🤖 Generated with Claude Code