Dark Mode

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

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

Open
QuantumExplorer wants to merge 18 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 18 commits intov3.1-devfrom
feat/zk-wasm-js-bindings

Conversation

Copy link
Member

QuantumExplorer commented Mar 12, 2026 *
edited by coderabbitai bot
Loading

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
  • 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

Summary by CodeRabbit

  • New Features

    • Added full support for shielded transitions (shield, unshield, shielded transfer, shielded withdrawal) with JS/WASM bindings and serialization.
    • Added shielded pool queries (pool state, encrypted notes, anchors, nullifier status) and proof-info variants.
    • Expanded proof-result types for shielded proof verification and SDK exports for shielded query types.
  • Bug Fixes

    • Improved error handling for shielded transition operations.

...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
QuantumExplorer requested a review from shumkov as a code owner March 12, 2026 17:55
Copy link
Contributor

coderabbitai bot commented Mar 12, 2026 *
edited
Loading

Walkthrough

Walkthrough

Adds a new shielded module and WASM bindings: five shielded state-transition wrappers, shielded proof-result types, helper functions, and wallet/query APIs to expose shielded pool state, anchors, encrypted notes, and nullifier statuses (with proof-info variants) to JavaScript via wasm-bindgen.

Changes

Cohort / File(s) Summary
Shielded Module Entry & Re-exports
packages/wasm-dpp2/src/lib.rs, packages/wasm-dpp2/src/shielded/mod.rs
Added public shielded module, re-exports of shielded transition WASM types, and compute_platform_sighash_wasm with input validation (bundle_commitment must be 32 bytes).
Shielded Transition Wrappers
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
Introduced five wasm_bindgen wrapper types (ShieldFromAssetLockTransitionWasm, ShieldTransitionWasm, ShieldedTransferTransitionWasm, ShieldedWithdrawalTransitionWasm, UnshieldTransitionWasm) with getters for cryptographic fields, serialization (toBytes/fromBytes/toJson/toObject), conversions to StateTransitionWasm, and impl_wasm_type_info / From conversions.
Proof Result: Shielded Extraction
packages/wasm-dpp2/src/state_transitions/proof_result.rs, packages/wasm-dpp2/src/state_transitions/proof_result_shielded.rs
Extracted shielded proof-result types into proof_result_shielded.rs, added VerifiedAssetLockConsumed/VerifiedShieldedNullifiers variants, implemented build_nullifier_map, moved shielded WASM wrappers into new module, and expanded convert_proof_result to handle new variants and map constructions.
State Transition Error Handling
packages/wasm-dpp2/src/state_transitions/base/state_transition.rs
Replaced todo!/panic branches for shielded transitions with explicit invalid_argument errors for setters (setOwnerId, setIdentityContractNonce, setIdentityNonce) and return None for owner/identity getters on ShieldedWithdrawal.
WASM SDK Query Surface
packages/wasm-sdk/src/lib.rs, packages/wasm-sdk/src/queries/mod.rs, packages/wasm-sdk/src/queries/shielded.rs
Added queries::shielded module and public re-exports (ShieldedEncryptedNoteWasm, ShieldedNullifierStatusWasm). Extended WasmSdk with async methods for shielded pool state, anchors, encrypted notes, nullifier statuses, and proof-info variants (getShieldedPoolState*, getShieldedEncryptedNotes*, getShieldedAnchors*, getMostRecentShieldedAnchor*, getShieldedNullifiers*).

Sequence Diagram(s)

sequenceDiagram
actor JS as JavaScript Client
participant WASM as WASM Lib (wasm-dpp2)
participant DPP as DPP Core (Rust)
participant Crypto as Crypto Libs

JS->>WASM: construct ShieldTransitionWasm / call getters
WASM->>DPP: build ShieldTransition::V0 (fields, actions)
WASM->>Crypto: validate proof/anchor/binding_signature
Crypto-->>WASM: validation result
WASM->>DPP: serialize via PlatformSerializable -> bytes
WASM-->>JS: return bytes / StateTransitionWasm
Loading
sequenceDiagram
actor JS as JavaScript Client
participant SDK as WASM SDK (wasm-sdk)
participant Drive as Drive Backend
participant Verifier as Proof Verifier

JS->>SDK: getShieldedNullifiersWithProofInfo(nullifiers)
SDK->>Drive: request nullifier statuses + proof metadata
Drive-->>SDK: statuses + proof
SDK->>Verifier: verify proof
Verifier-->>SDK: verification result
SDK->>SDK: build nullifier_map, convert to ShieldedNullifierStatusWasm, assemble ProofMetadataResponseWasm
SDK-->>JS: return ProofMetadataResponseWasm
Loading

Estimated code review effort

4 (Complex) | ~50 minutes

Poem

I hopped through bindings, bytes, and proofs today,
I wrapped the shielded paths so JS can play,
Nullifiers counted, anchors kept tight,
Wasm bridges the fields, by moon and by light,
A rabbit's small cheer for private-data flight.

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 title 'feat(wasm-sdk): add shielded pool WASM bindings and query methods' clearly and specifically describes the primary changes: adding WASM bindings and query methods for shielded pools to the wasm-sdk package.
Docstring Coverage Passed Docstring coverage is 100.00% 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/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 bot added this to the v3.1.0 milestone Mar 12, 2026
coderabbitai bot reviewed Mar 12, 2026
Copy link
Contributor

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_transiti on.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/ShieldedWithdraw al 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.

i 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
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
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
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
Fix clippy::needless_borrows_for_generic_args -- `&format!()` - `format!()`.

Co-Authored-By: Claude Opus 4.6
shumkov requested changes Mar 13, 2026
shumkov requested changes Mar 13, 2026
- Use null instead of undefined for absent values in shielded queries
- Add unchecked_return_type to getMostRecentShieldedAnchor
- Add constructor, TypeScript types, and impl_wasm_conversions_serde
macro to ShieldFromAssetLockTransitionWasm
- Extract shielded proof result types into separate module

Co-Authored-By: Claude Opus 4.6
coderabbitai bot reviewed Mar 13, 2026
Copy link
Contributor

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: 1

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-sdk/src/queries/shielded.rs`:
- Around line 175-185: The current nullifier_arrays mapping in functions using
`nullifiers.iter()` and `Uint8Array::new(&n)` (the `nullifier_arrays`
construction and the similar block at the second occurrence) silently truncates
or zero-pads inputs; change this to validate that `Uint8Array::length()` (or the
vector length produced by `to_vec()`) is exactly 32 and return an error
(propagate an Err/JsValue back to the caller) when length != 32 instead of using
`len().min(32)` and copying/padding; update both the `nullifier_arrays` mapping
and the analogous block at the other occurrence so invalid-length inputs are
rejected with a clear error message identifying the offending nullifier.

i Review info
Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 482ab228-743d-48c4-a268-2e18dfc07964

Commits

Reviewing files that changed from the base of the PR and between c5325c9 and 5d4ee20.

Files selected for processing (8)
  • packages/wasm-dpp2/src/shielded/mod.rs
  • packages/wasm-dpp2/src/shielded/shield_from_asset_lock_transition.rs
  • packages/wasm-dpp2/src/state_transitions/mod.rs
  • packages/wasm-dpp2/src/state_transitions/proof_result.rs
  • packages/wasm-dpp2/src/state_transitions/proof_result_shielded.rs
  • packages/wasm-sdk/src/lib.rs
  • packages/wasm-sdk/src/queries/mod.rs
  • packages/wasm-sdk/src/queries/shielded.rs
Files skipped from review as they are similar to previous changes (2)
  • packages/wasm-dpp2/src/shielded/shield_from_asset_lock_transition.rs
  • packages/wasm-dpp2/src/shielded/mod.rs

QuantumExplorer and others added 2 commits March 13, 2026 12:47
Instead of silently truncating/padding, return an InvalidArgument
error when a nullifier Uint8Array is not exactly 32 bytes.

Co-Authored-By: Claude Opus 4.6
coderabbitai bot reviewed Mar 13, 2026
Copy link
Contributor

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: 1

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-sdk/src/queries/shielded.rs`:
- Around line 175-190: The code uses Uint8Array::new(&n) which silently coerces
numeric JS values into zero-filled arrays; update the nullifier parsing (the
nullifiers -> nullifier_arrays mapping where Uint8Array::new(&n) is called) to
first dyn_into::() the JsValue `n` and return a
WasmSdkError::invalid_argument if the cast fails, then call to_vec(), check
length == 32, copy into [u8;32], and propagate errors; apply the same
dyn_into-based validation to the second nullifier-parsing block referenced in
the review so both locations reject non-Uint8Array inputs instead of coercing
numbers.

i Review info
Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a0485101-3553-4505-8ff4-25940161772c

Commits

Reviewing files that changed from the base of the PR and between 5d4ee20 and a87c6ad.

Files selected for processing (1)
  • packages/wasm-sdk/src/queries/shielded.rs

thepastaclaw suggested changes Mar 16, 2026
Copy link
Collaborator

thepastaclaw left a comment

Choose a reason for hiding this comment

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

Code Review

This PR adds WASM/JS bindings for shielded pool state transitions and query methods. The code follows established wrapper patterns and is structurally sound. The main concern is an inconsistency where getShieldedPoolState silently maps a missing pool to BigInt(0) while its WithProofInfo variant correctly returns null, which would cause different observable behavior depending on which API a consumer uses. Test coverage for this security-critical surface is also absent.

1 blocking | 3 suggestion(s)

Prompt for all review comments with AI agents ` to `Vec<[u8; 32]>` with 32-byte validation) is copy-pasted identically between `get_shielded_nullifiers` (lines 175-189) and `get_shielded_nullifiers_with_proof_info` (lines 327-341). Extract to a shared helper to avoid the two copies drifting apart. Additionally, `Uint8Array::new(&n)` doesn't type-check its argument -- if a non-Uint8Array value is passed, it may silently produce a zero-length array rather than erroring. Using `n.dyn_into::()` would provide a clearer error message. In `packages/wasm-dpp2/src/shielded/shield_transition.rs`: - [SUGGESTION] lines 1-156: Four shielded transition wrappers lack JS constructors (intentional?) `ShieldFromAssetLockTransitionWasm` has a `#[wasm_bindgen(constructor)]` plus `impl_wasm_conversions_serde!` for `fromObject`/`fromJSON`, but `ShieldTransitionWasm`, `ShieldedTransferTransitionWasm`, `UnshieldTransitionWasm`, and `ShieldedWithdrawalTransitionWasm` can only be constructed via `fromBytes()`. This is likely intentional since ZK-proof-based transitions are built in Rust (where the proof is generated), not from plain JS objects. If so, a brief doc comment noting that `fromBytes` is the intended construction path would prevent confusion. If JS construction is eventually needed, the `Serialize`/`Deserialize` derives are missing from these four types (they'd need to be added for serde-based constructors to work).">These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/wasm-sdk/src/queries/shielded.rs`:
- [BLOCKING] lines 99-100: Inconsistent None-handling: getShieldedPoolState returns 0 but WithProofInfo variant returns null
`get_shielded_pool_state` coerces `None` to `BigInt(0)` via `unwrap_or(0)` (line 99), while `get_shielded_pool_state_with_proof_info` (line 222) maps `None` to `JsValue::NULL`. This means the non-proof variant silently conflates "pool doesn't exist" with "pool has zero balance", while the proof variant correctly distinguishes the two. A JS consumer switching between APIs would observe different semantics for the same underlying state. The `WithProofInfo` behavior (returning null) is correct -- the non-proof variant should match.
- [SUGGESTION] lines 1-362: No tests for any of the new shielded query methods or transition wrappers
This PR adds 5 state transition wrapper types, 1 utility function (`computePlatformSighash`), 5 query methods, 5 `WithProofInfo` query variants, and 4 new proof result types -- all without corresponding tests. The inconsistency flagged above (None - 0 vs None - null) is exactly the kind of behavioral bug that a test comparing both API variants would catch. Given that this is security-critical shielded pool functionality, at minimum serialization roundtrip tests for the transition wrappers and mock-based tests for the query methods would provide important coverage.
- [SUGGESTION] lines 175-189: Duplicated nullifier parsing and validation logic
The nullifier parsing block (convert JS `Array` to `Vec<[u8; 32]>` with 32-byte validation) is copy-pasted identically between `get_shielded_nullifiers` (lines 175-189) and `get_shielded_nullifiers_with_proof_info` (lines 327-341). Extract to a shared helper to avoid the two copies drifting apart.

Additionally, `Uint8Array::new(&n)` doesn't type-check its argument -- if a non-Uint8Array value is passed, it may silently produce a zero-length array rather than erroring. Using `n.dyn_into::()` would provide a clearer error message.

In `packages/wasm-dpp2/src/shielded/shield_transition.rs`:
- [SUGGESTION] lines 1-156: Four shielded transition wrappers lack JS constructors (intentional?)
`ShieldFromAssetLockTransitionWasm` has a `#[wasm_bindgen(constructor)]` plus `impl_wasm_conversions_serde!` for `fromObject`/`fromJSON`, but `ShieldTransitionWasm`, `ShieldedTransferTransitionWasm`, `UnshieldTransitionWasm`, and `ShieldedWithdrawalTransitionWasm` can only be constructed via `fromBytes()`. This is likely intentional since ZK-proof-based transitions are built in Rust (where the proof is generated), not from plain JS objects. If so, a brief doc comment noting that `fromBytes` is the intended construction path would prevent confusion. If JS construction is eventually needed, the `Serialize`/`Deserialize` derives are missing from these four types (they'd need to be added for serde-based constructors to work).

QuantumExplorer and others added 2 commits March 16, 2026 15:46
Address shumkov, thepastaclaw, and CodeRabbit review comments:

Shielded transition wrappers (wasm-dpp2):
- Add Serialize/Deserialize derives, TypeScript interface declarations,
extern "C" typed JS/JSON types, constructors, and impl_wasm_conversions_serde
macro to ShieldTransition, ShieldedTransferTransition,
ShieldedWithdrawalTransition, and UnshieldTransition (matching the
pattern already used by ShieldFromAssetLockTransition)

Shielded queries (wasm-sdk):
- Change JsValue::NULL to JsValue::UNDEFINED for missing values (JS
convention: missing = undefined, explicit empty = null)
- Fix getShieldedPoolState to return undefined for None instead of
BigInt(0), making None-handling consistent with WithProofInfo variant
- Add unchecked_return_type annotations for TypeScript ("bigint | undefined",
"Uint8Array | undefined")
- Extract duplicated nullifier parsing into parse_nullifiers() helper

Co-Authored-By: Claude Opus 4.6 (1M context)
shumkov requested changes Mar 16, 2026
Address ivan's review comments on shielded transition TS types:
- Change $version to $formatVersion in all interfaces
- Use AssetLockProofObject/JSON instead of generic object
- Define SerializedOrchardAction interface with typed fields
- Define FeeStrategyStepObject, AddressWitnessObject types
- Use proper types for inputs, feeStrategy, inputWitnesses
- Fix JSON byte fields: number[] - string (base64-encoded)
- Use typed arrays for actions instead of Array

Co-Authored-By: Claude Opus 4.6 (1M context)
Copy link

codecov bot commented Mar 16, 2026 *
edited
Loading

Codecov Report

All modified and coverable lines are covered by tests.
Project coverage is 75.87%. Comparing base (2fb112c) to head (c6a2b3f).
Report is 1 commits behind head on v3.1-dev.

Additional details and impacted files
@@ Coverage Diff @@
## v3.1-dev #3235 +/- ##
=========================================
Coverage 75.87% 75.87%
=========================================
Files 2912 2912
Lines 283860 283860
=========================================
Hits 215375 215375
Misses 68485 68485
Components Coverage D
dpp 65.71% (o)
drive 81.64% (o)
drive-abci 85.99% (o)
sdk 31.25% (o)
dapi-client 79.06% (o)
platform-version ()
platform-value 58.46% (o)
platform-wallet 60.40% (o)
drive-proof-verifier 48.00% (o)
New features to boost your workflow:
  • Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

SerializedOrchardActionJSON had byte fields as number[] but they should
be string (base64-encoded) to match the JSON serialization convention.

Co-Authored-By: Claude Opus 4.6 (1M context)
shumkov requested changes Mar 16, 2026
JSON cannot represent BigInt natively -- serde serializes u64 values as
numbers (when they fit in f64) or strings (when they exceed 2^53).
Update all JSON TypeScript interfaces to use `number | string` for
u64 fields: valueBalance, amount, unshieldingAmount.

The Object interfaces keep `bigint` since wasm_bindgen maps u64 to
BigInt directly. The u64 getters are already correct -- wasm_bindgen
automatically returns BigInt to JS.

Co-Authored-By: Claude Opus 4.6 (1M context)
thepastaclaw suggested changes Mar 16, 2026
Copy link
Collaborator

thepastaclaw left a comment

Choose a reason for hiding this comment

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

Code Review

This incremental push addresses all four prior findings: None-undefined consistency, duplicated nullifier parsing, missing constructors, and macro usage. The changes are well-structured. Two remaining issues: the TypeScript interfaces declare $formatVersion but the Rust shielded enums use serde(tag = "$version"), creating a mismatch; and the FeeStrategyStepObject interface shape doesn't match the actual externally-tagged serde output.

Reviewed commit: 7f216ec

1 blocking | 2 suggestion(s)

Prompt for all review comments with AI agents ` instead of `Map`. The JSON interface already correctly uses `Record`.">These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/wasm-dpp2/src/shielded/shield_transition.rs`:
- [BLOCKING] line 68: TS interfaces declare `$formatVersion` but Rust enums serialize `$version`
All five shielded transition Rust enums (`ShieldTransition`, `ShieldedTransferTransition`, etc.) use `serde(tag = "$version")`, while every other versioned type in the codebase uses `serde(tag = "$formatVersion")`. The new TypeScript interfaces all declare `$formatVersion: string`, which doesn't match the actual serialization output (`$version`). This means:
- Objects from `toObject()`/`toJSON()` will have a `$version` key, not `$formatVersion`
- JS consumers constructing objects per the interface will use `$formatVersion`, causing deserialization failures

Either rename the Rust tag to `$formatVersion` for consistency, or update all TS interfaces to use `$version`.
- [SUGGESTION] lines 15-18: `FeeStrategyStepObject` doesn't match actual serde shape
`AddressFundsFeeStrategyStep` is an externally-tagged enum with `rename_all = "camelCase"`, so it serializes as `{ "deductFromInput": 0 }` or `{ "reduceOutput": 1 }`. The TS interface declares `{ type: string; index: number }`, which is a different shape entirely. JS consumers following the interface will construct objects the deserializer rejects.
- [SUGGESTION] line 69: `inputs` typed as `Map` but serialization emits a plain object
The `toObject` path uses `serialize_maps_as_objects(true)`, so `inputs` (a Rust `BTreeMap`) is emitted as a plain JS object with string keys, not a JS `Map`. The Object interface should use `Record` instead of `Map`. The JSON interface already correctly uses `Record`.

shumkov requested changes Mar 16, 2026
QuantumExplorer and others added 2 commits March 16, 2026 17:39
Replace untyped JsValue parameter with the corresponding typed
*ObjectJs extern type in all 5 shielded transition constructors.
This provides TypeScript type checking at the call site.

Co-Authored-By: Claude Opus 4.6 (1M context)
- Change $formatVersion back to $version (serde uses tag = "$version")
- Fix FeeStrategyStepObject to externally-tagged union type matching
serde's camelCase enum output: { deductFromInput: n } | { reduceOutput: n }
- Fix inputs from Map<> to Record since serialize_maps_as_objects
emits plain JS objects, not Maps

Co-Authored-By: Claude Opus 4.6 (1M context)
Copy link
Collaborator

thepastaclaw left a comment

Choose a reason for hiding this comment

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

Code Review

Incremental push with 4 commits fixing TypeScript type definitions to match actual serde output. All changes are in wasm-dpp2 TS custom sections: $formatVersion - $version (matching Rust serde(tag = "$version")), byte fields in JSON variants corrected from number[] to base64 string, u64 values widened to number | string, Map - Record, and FeeStrategyStepObject changed from flat interface to externally-tagged union matching the Rust enum. All five constructors now accept typed parameters. No logic changes, no new issues.

Reviewed commit: 2db3796

shumkov requested changes Mar 16, 2026
shumkov requested changes Mar 17, 2026
QuantumExplorer and others added 2 commits March 17, 2026 14:11
Address ivan's review feedback:

- Change $version to $formatVersion in all 10 TS interfaces (Object
and JSON) across all 5 shielded transition files
- Add ShieldFromAssetLockTransitionOptions interface that accepts
AssetLockProof as a WASM instance type (not a plain JS object)
- Constructor now extracts assetLockProof via try_from_options and
deserializes remaining fields via serde

Co-Authored-By: Claude Opus 4.6 (1M context)
thepastaclaw suggested changes Mar 17, 2026
Copy link
Collaborator

thepastaclaw left a comment

Choose a reason for hiding this comment

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

Code Review

The incremental push (a87c6ad - c6a2b3f) addresses all 4 prior review findings well: constructors added for all 5 shielded transitions, undefined replaces inconsistent 0/null, and nullifier parsing was deduplicated. However, the TS interfaces now declare $formatVersion while the Rust serde tags still use $version -- this will break every constructor and make toObject/toJSON output mismatched. The ShieldFromAssetLock constructor also silently accepts missing required fields via #[serde(default)].

Reviewed commit: c6a2b3f

1 blocking | 2 suggestion(s) | 1 nitpick(s)

Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/wasm-dpp2/src/shielded/shield_transition.rs`:
- [BLOCKING] line 68: TS interfaces declare `$formatVersion` but Rust serde tag is `$version` -- breaks constructors and output types
All 5 shielded transition Rust enums (`ShieldTransition`, `ShieldFromAssetLockTransition`, `ShieldedTransferTransition`, `ShieldedWithdrawalTransition`, `UnshieldTransition`) use `#[serde(tag = "$version")]`, but the TS Object/JSON interfaces in this delta were changed to `$formatVersion`.

**Impact on constructors:** The 4 constructors using `serde_wasm_bindgen::from_value()` require `{"$version": "0", ...}` as the serde discriminant. A JS caller following the TS types will pass `{"$formatVersion": "0", ...}` - deserialization fails with a missing-tag error.

**Impact on output:** `toObject()`/`toJSON()` serialize through serde and produce `{"$version": "0", ...}`, but the TS return types declare `$formatVersion`. TypeScript consumers accessing `obj.$formatVersion` will get `undefined`.

The rest of the codebase (Identity, DataContract, address-based transitions) already uses `serde(tag = "$formatVersion")`. The 5 shielded enums are inconsistent -- update the Rust serde tags in `packages/rs-dpp/src/state_transition/state_transitions/shie lded/*/mod.rs` to `serde(tag = "$formatVersion")`.

In `packages/wasm-dpp2/src/shielded/shield_from_asset_lock_transition.rs`:
- [SUGGESTION] lines 14-29: `#[serde(default)]` on all fields silently accepts missing required cryptographic fields
Every field in `ShieldFromAssetLockTransitionSimpleFields` has `#[serde(default)]`, which means the constructor silently succeeds with empty vectors and zero values if the JS caller omits `actions`, `proof`, `bindingSignature`, etc. While `anchor` and `binding_signature` are validated for correct length downstream (32 and 64 bytes respectively), the other fields -- `actions`, `proof`, `value_balance`, `signature` -- will silently default to empty/zero.

This creates a confusing failure mode: instead of getting a clear "missing field" error at the WASM boundary, a JS caller omitting required fields gets a structurally valid but logically broken transition that will fail much later during validation.

Consider removing `#[serde(default)]` from fields that are truly required (actions, proof, binding_signature, signature), or at minimum adding explicit emptiness checks after deserialization.

In `packages/wasm-sdk/src/queries/shielded.rs`:
- [SUGGESTION] lines 92-93: `Uint8Array::new(&n)` polymorphic behavior may allocate attacker-chosen buffers
`parse_nullifiers()` calls `Uint8Array::new(&n)` on each array element. In JS, `new Uint8Array(number)` creates a *new* zero-filled buffer of that length. If a caller passes `[4294967295]` (a plain number instead of a Uint8Array), this would attempt to allocate a 4GB buffer.

The 32-byte length check on the next line catches this eventually, but only after the allocation completes. Consider using `Uint8Array::new(&n.dyn_into::().map_err(...)?)` or checking `n.is_instance_of::()` first to reject non-Uint8Array inputs early.

* ShieldTransition serialized as a plain object.
*/
export interface ShieldTransitionObject {
$formatVersion: string;
Copy link
Collaborator

thepastaclaw Mar 17, 2026

Choose a reason for hiding this comment

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

Blocking: TS interfaces declare $formatVersion but Rust serde tag is $version -- breaks constructors and output types

All 5 shielded transition Rust enums (ShieldTransition, ShieldFromAssetLockTransition, ShieldedTransferTransition, ShieldedWithdrawalTransition, UnshieldTransition) use #[serde(tag = "$version")], but the TS Object/JSON interfaces in this delta were changed to $formatVersion.

Impact on constructors: The 4 constructors using serde_wasm_bindgen::from_value() require {"$version": "0", ...} as the serde discriminant. A JS caller following the TS types will pass {"$formatVersion": "0", ...} - deserialization fails with a missing-tag error.

Impact on output: toObject()/toJSON() serialize through serde and produce {"$version": "0", ...}, but the TS return types declare $formatVersion. TypeScript consumers accessing obj.$formatVersion will get undefined.

The rest of the codebase (Identity, DataContract, address-based transitions) already uses serde(tag = "$formatVersion"). The 5 shielded enums are inconsistent -- update the Rust serde tags in packages/rs-dpp/src/state_transition/state_transitions/shielded/*/mod.rs to serde(tag = "$formatVersion").

source: ['claude', 'codex']

Fix this with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/wasm-dpp2/src/shielded/shield_transition.rs`:
- [BLOCKING] line 68: TS interfaces declare `$formatVersion` but Rust serde tag is `$version` -- breaks constructors and output types
All 5 shielded transition Rust enums (`ShieldTransition`, `ShieldFromAssetLockTransition`, `ShieldedTransferTransition`, `ShieldedWithdrawalTransition`, `UnshieldTransition`) use `#[serde(tag = "$version")]`, but the TS Object/JSON interfaces in this delta were changed to `$formatVersion`.

**Impact on constructors:** The 4 constructors using `serde_wasm_bindgen::from_value()` require `{"$version": "0", ...}` as the serde discriminant. A JS caller following the TS types will pass `{"$formatVersion": "0", ...}` - deserialization fails with a missing-tag error.

**Impact on output:** `toObject()`/`toJSON()` serialize through serde and produce `{"$version": "0", ...}`, but the TS return types declare `$formatVersion`. TypeScript consumers accessing `obj.$formatVersion` will get `undefined`.

The rest of the codebase (Identity, DataContract, address-based transitions) already uses `serde(tag = "$formatVersion")`. The 5 shielded enums are inconsistent -- update the Rust serde tags in `packages/rs-dpp/src/state_transition/state_transitions/shie lded/*/mod.rs` to `serde(tag = "$formatVersion")`.

Comment on lines +14 to +29
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct ShieldFromAssetLockTransitionSimpleFields {
#[serde(default)]
actions: Vec,
#[serde(default)]
value_balance: u64,
#[serde(default)]
anchor: Vec,
#[serde(default)]
proof: Vec,
#[serde(default)]
binding_signature: Vec,
#[serde(default)]
signature: Vec,
}
Copy link
Collaborator

thepastaclaw Mar 17, 2026

Choose a reason for hiding this comment

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

Suggestion: #[serde(default)] on all fields silently accepts missing required cryptographic fields

Every field in ShieldFromAssetLockTransitionSimpleFields has #[serde(default)], which means the constructor silently succeeds with empty vectors and zero values if the JS caller omits actions, proof, bindingSignature, etc. While anchor and binding_signature are validated for correct length downstream (32 and 64 bytes respectively), the other fields -- actions, proof, value_balance, signature -- will silently default to empty/zero.

This creates a confusing failure mode: instead of getting a clear "missing field" error at the WASM boundary, a JS caller omitting required fields gets a structurally valid but logically broken transition that will fail much later during validation.

Consider removing #[serde(default)] from fields that are truly required (actions, proof, binding_signature, signature), or at minimum adding explicit emptiness checks after deserialization.

source: ['claude', 'codex']

Fix this with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/wasm-dpp2/src/shielded/shield_from_asset_lock_transition.rs`:
- [SUGGESTION] lines 14-29: `#[serde(default)]` on all fields silently accepts missing required cryptographic fields
Every field in `ShieldFromAssetLockTransitionSimpleFields` has `#[serde(default)]`, which means the constructor silently succeeds with empty vectors and zero values if the JS caller omits `actions`, `proof`, `bindingSignature`, etc. While `anchor` and `binding_signature` are validated for correct length downstream (32 and 64 bytes respectively), the other fields -- `actions`, `proof`, `value_balance`, `signature` -- will silently default to empty/zero.

This creates a confusing failure mode: instead of getting a clear "missing field" error at the WASM boundary, a JS caller omitting required fields gets a structurally valid but logically broken transition that will fail much later during validation.

Consider removing `#[serde(default)]` from fields that are truly required (actions, proof, binding_signature, signature), or at minimum adding explicit emptiness checks after deserialization.

Comment on lines +92 to +93
let uint8_arr = Uint8Array::new(&n);
let bytes = uint8_arr.to_vec();
Copy link
Collaborator

thepastaclaw Mar 17, 2026

Choose a reason for hiding this comment

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

Suggestion: Uint8Array::new(&n) polymorphic behavior may allocate attacker-chosen buffers

parse_nullifiers() calls Uint8Array::new(&n) on each array element. In JS, new Uint8Array(number) creates a new zero-filled buffer of that length. If a caller passes [4294967295] (a plain number instead of a Uint8Array), this would attempt to allocate a 4GB buffer.

The 32-byte length check on the next line catches this eventually, but only after the allocation completes. Consider using Uint8Array::new(&n.dyn_into::().map_err(...)?) or checking n.is_instance_of::() first to reject non-Uint8Array inputs early.

source: ['claude', 'codex']

Fix this with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/wasm-sdk/src/queries/shielded.rs`:
- [SUGGESTION] lines 92-93: `Uint8Array::new(&n)` polymorphic behavior may allocate attacker-chosen buffers
`parse_nullifiers()` calls `Uint8Array::new(&n)` on each array element. In JS, `new Uint8Array(number)` creates a *new* zero-filled buffer of that length. If a caller passes `[4294967295]` (a plain number instead of a Uint8Array), this would attempt to allocate a 4GB buffer.

The 32-byte length check on the next line catches this eventually, but only after the allocation completes. Consider using `Uint8Array::new(&n.dyn_into::().map_err(...)?)` or checking `n.is_instance_of::()` first to reject non-Uint8Array inputs early.

Comment on lines +15 to +17
export interface UnshieldTransitionObject {
$formatVersion: string;
outputAddress: object;
Copy link
Collaborator

thepastaclaw Mar 17, 2026

Choose a reason for hiding this comment

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

Nitpick: outputAddress typed as bare object -- inconsistent with rest of PR

All other complex types in this iteration received properly typed TS interfaces (SerializedOrchardAction, AssetLockProofObject, FeeStrategyStepObject, AddressWitnessObject), but outputAddress in both UnshieldTransitionObject and UnshieldTransitionJSON is still object. Consider adding a PlatformAddressObject / PlatformAddressJSON interface for type safety consistency.

source: ['claude']

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

Reviewers

coderabbitai[bot] coderabbitai[bot] left review comments

shumkov shumkov requested changes

+1 more reviewer

thepastaclaw thepastaclaw requested changes

Reviewers whose approvals may not affect merge requirements

Requested changes must be addressed to merge this pull request.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

v3.1.0

Development

Successfully merging this pull request may close these issues.

3 participants