Skip to content

feat(swift-sdk): fund identity creation from shielded balance - #3838

Merged
QuantumExplorer merged 1 commit into
v3.1-devfrom
claude/brave-elion-867b15
Jun 10, 2026
Merged

feat(swift-sdk): fund identity creation from shielded balance#3838
QuantumExplorer merged 1 commit into
v3.1-devfrom
claude/brave-elion-867b15

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented Jun 10, 2026

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

The Create Identity screen in SwiftExampleApp could not use the shielded (Orchard) balance as a funding origin, even though the Type-20 IdentityCreateFromShieldedPool state transition and its full stack (rs-dpp builder → platform-wallet op → FFI → Swift wrapper) already exist. This PR surfaces that path in the UI and closes a persistence gap in the Rust flow that would have left the newly created identity invisible to the app.

What was done?

Rust (platform-wallet)

  • identity_create_from_shielded_pool (operations.rs) now captures the SDK broadcast's StateTransitionProofResult and extracts the proof-verified Identity from VerifiedIdentityWithShieldedNullifiers, back-filling public_keys() from the submitted set if the result echoes them empty (same defensive pattern as register_from_addresses), and returns it alongside the derived id. An unexpected proof-result variant is warn-and-synthesize rather than an error, since the broadcast already succeeded.
  • PlatformWallet::shielded_identity_create_from_pool takes a new identity_index: u32 and, after a successful broadcast, registers the verified identity in the local IdentityManager via add_identity + persister — mirroring register_from_addresses Step 3 — so the host persister emits the IdentityChangeSet/IdentityKeysChangeSet that creates the app's PersistentIdentity row. Previously no other layer did this, so the shielded path never produced an identity row. A registration failure after a successful broadcast is logged and swallowed (the identity exists on chain; sync heals).

FFI / Swift SDK (marshal-only)

  • platform_wallet_manager_shielded_identity_create_from_pool gains identity_index: u32 (after account); shieldedIdentityCreateFromPool gains the matching identityIndex: UInt32 and passes it through.

SwiftExampleApp (CreateIdentityView)

  • New FundingSelection.shieldedBalance option: "Shielded Balance — X DASH" appears in the Funding Source picker when the selected wallet is the one bound to ShieldedService, the pool balance is positive, and a fallback platform address exists.
  • Type-20 spends a fixed denomination, so the free-form amount field is replaced by a denomination picker (0.1 / 0.3 / 0.5 / 1 DASH, mirrored from shielded_identity_create_denominations in rs-platform-version v8 with a source-of-truth doc pointer, filtered to denominations the pool covers). Footer explains the exact-equality fee model (fee metered FROM the denomination; excess returns as pool change).
  • The REQUIRED send_to_address_on_creation_failure (21 raw PlatformAddress bytes) is derived from the wallet's lowest-index Platform Payment address — the same (addressType, hash) pairing the address-funded path feeds the FFI.
  • Submission routes through the RegistrationCoordinator-hosted controller (like the Core-funded path) because the Halo 2 proof takes tens of seconds — the registration survives sheet dismissal and stays visible under Pending Registrations. The shared completion path patches the persisted row and marks the DIP-9 slot used.
  • DashPay-keys footer made path-aware so the "+N duffs asset-lock minimum" phrasing isn't shown for the shielded path.

How Has This Been Tested?

  • cargo check -p platform-wallet --all-features --all-targets and cargo check -p platform-wallet-ffi --all-features --all-targets — pass.
  • cargo fmt --all --check — clean.
  • ./build_ios.sh --target sim rebuilt the xcframework (regenerated header carries uint32_t identity_index) and SwiftExampleApp BUILD SUCCEEDED against it (iPhone 16 simulator).
  • No end-to-end shielded run: strategy/full-block harnesses don't build shielded transitions yet, and exercising the flow needs a devnet with a funded shielded pool.

Breaking Changes

None (not consensus-breaking). The FFI/Swift signature change to shielded_identity_create_from_pool is pre-release public-API churn.

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

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Shielded identity creation now allows explicit specification of which identity-registration slot to use (DIP-9 compliant).
    • Added denomination selection for shielded balance funding when creating identities.
    • Identity creation now returns comprehensive verification data for improved validation.
  • Refactor

    • Enhanced identity creation operations to support explicit slot assignment across wallet implementations.

Adds 'Shielded Balance' as a funding origin in CreateIdentityView, wired
to the existing Type-20 IdentityCreateFromShieldedPool stack. The UI
offers the option when the selected wallet is bound to ShieldedService
with a positive pool balance, replaces the free-form amount with the
versioned fixed-denomination picker, derives the required
creation-failure fallback address from the wallet's Platform Payment
account, and routes submission through the RegistrationCoordinator so
the Halo 2 proof survives sheet dismissal.

Also fixes a gap in the Rust path: the operation now extracts the
proof-verified Identity from the broadcast result and the manager
wrapper registers it in the local IdentityManager at the new
identity_index parameter (mirroring register_from_addresses), so the
host persister emits the identity row like every other registration
path. identity_index is threaded through the FFI and Swift wrapper.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@QuantumExplorer
QuantumExplorer requested a review from shumkov as a code owner June 10, 2026 09:24
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 422a7286-4d0e-436e-bc52-9426e336b70e

📥 Commits

Reviewing files that changed from the base of the PR and between bfa8f68 and 009b39f.

📒 Files selected for processing (5)
  • packages/rs-platform-wallet-ffi/src/shielded_send.rs
  • packages/rs-platform-wallet/src/wallet/platform_wallet.rs
  • packages/rs-platform-wallet/src/wallet/shielded/operations.rs
  • packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletManagerShieldedSync.swift
  • packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/CreateIdentityView.swift

📝 Walkthrough

Walkthrough

The PR adds support for explicit DIP-9 identity-slot selection during shielded pool identity creation. The Rust operations layer now returns both the proven identity ID and its verified struct. The wallet coordinates proof broadcast with subsequent local identity manager registration under scoped locking. The parameter is threaded through FFI and Swift SDK. The example app gains a shielded balance funding path with fixed denominations and fallback address handling.

Changes

Shielded Identity Registration Stack

Layer / File(s) Summary
Shielded operation return type enhancement
packages/rs-platform-wallet/src/wallet/shielded/operations.rs
identity_create_from_shielded_pool now returns (Identifier, Identity) instead of just the ID. Added imports for identity accessor traits. Snapshots submitted public keys before consumption. Extracts verified identity from SDK proof result, warns if derived and verified IDs differ, patches keys from snapshot when empty, and synthesizes identity for unexpected proof variants. Success returns the tuple.
Platform wallet identity registration
packages/rs-platform-wallet/src/wallet/platform_wallet.rs
Updated shielded_identity_create_from_pool to accept identity_index: u32. Scopes the read lock on shielded_keys before broadcast. After obtaining the identity tuple from the operation, acquires a wallet-manager write lock to call identity_manager.add_identity with the index. Registration failures are logged and ignored; function returns Ok(identity_id) after the broadcast.
FFI and Swift SDK parameter wiring
packages/rs-platform-wallet-ffi/src/shielded_send.rs, packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/PlatformWalletManagerShieldedSync.swift
FFI function platform_wallet_manager_shielded_identity_create_from_pool and Swift SDK method shieldedIdentityCreateFromPool both gain identity_index/identityIndex: UInt32 parameter. Documentation updated to describe DIP-9 slot semantics. Parameter is forwarded through FFI call chain.
Example app shielded funding state and UI
packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/CreateIdentityView.swift (state, pickers, footer)
View injects ShieldedService, adds fixed denomination constants, and introduces selectedDenomination state that resets when wallet or funding selection changes. Funding picker conditionally shows "Shielded Balance" row tied to FundingSelection.shieldedBalance. New denomination section filters affordable amounts, shows conditional picker or explanatory message. DashPay footer uses dashpayKeysCostNote to distinguish shielded vs asset-lock messaging.
Example app submission and helpers
packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/CreateIdentityView.swift (submission, validation, helpers)
Updated canSubmit adds shielded validation (availability, denomination required, balance coverage). Submit dispatch routes .shieldedBalance to new submitShieldedFunded implementation, which validates denomination, resolves fallback address bytes from Platform Payment account, starts coordinator registration, and invokes wallet manager with account 0 and fixed denomination. Helper functions compute fallback address and determine shielded option availability. FundingSelection gains shieldedBalance case.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Suggested labels

ready for final review

Suggested reviewers

  • shumkov
  • thepastaclaw

Poem

🐰 A shielded identity's a quest so grand,
With index slots we now command,
Swift proof and locks ensure each deed,
Then registration plants the seed!
From purple pool to Platform's keep, 🎩✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: exposing shielded balance funding for identity creation in SwiftExampleApp through a comprehensive Type-20 flow.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/brave-elion-867b15

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.

@QuantumExplorer QuantumExplorer left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Reviewed

@QuantumExplorer
QuantumExplorer merged commit 50393c0 into v3.1-dev Jun 10, 2026
19 checks passed
@QuantumExplorer
QuantumExplorer deleted the claude/brave-elion-867b15 branch June 10, 2026 09:33
@QuantumExplorer QuantumExplorer added this to the v4.0.0 milestone Jun 10, 2026
@codecov

codecov Bot commented Jun 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.04%. Comparing base (af5611e) to head (009b39f).
⚠️ Report is 5 commits behind head on v3.1-dev.

Additional details and impacted files
@@            Coverage Diff            @@
##           v3.1-dev    #3838   +/-   ##
=========================================
  Coverage     87.04%   87.04%           
=========================================
  Files          2677     2678    +1     
  Lines        329918   329994   +76     
=========================================
+ Hits         287182   287258   +76     
  Misses        42736    42736           
Components Coverage Δ
dpp 87.41% <ø> (ø)
drive 85.99% <ø> (ø)
drive-abci 89.29% <ø> (ø)
sdk ∅ <ø> (∅)
dapi-client ∅ <ø> (∅)
platform-version ∅ <ø> (∅)
platform-value 92.20% <ø> (ø)
platform-wallet ∅ <ø> (∅)
drive-proof-verifier 49.55% <ø> (ø)
🚀 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.

@github-actions

Copy link
Copy Markdown
Contributor

✅ DashSDKFFI.xcframework built for this PR.

SwiftPM (host the zip at a stable URL, then use):

.binaryTarget(
  name: "DashSDKFFI",
  url: "https://your.cdn.example/DashSDKFFI.xcframework.zip",
  checksum: "9d5fb4ffc15b21b706c0feb755106331e65a96d840944e28803cca18b0afd8c1"
)

Xcode manual integration:

  • Download 'DashSDKFFI.xcframework' artifact from the run link above.
  • Drag it into your app target (Frameworks, Libraries & Embedded Content) and set Embed & Sign.
  • If using the Swift wrapper package, point its binaryTarget to the xcframework location or add the package and place the xcframework at the expected path.

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