feat!: managed identity top-up from asset lock (iOS + shared FFI)#4093
Conversation
Add two managed FFI exports for topping up an existing identity from a Core asset lock, both delegating to the upstream orchestrator IdentityWallet::top_up_identity_with_funding (funding resolution, IS->CL fallback, balance persist -- no reimplementation): - platform_wallet_top_up_identity_with_funding_signer (AssetLockFunding::FromWalletBalance) builds and broadcasts a new lock from the wallet's balance. - platform_wallet_topup_identity_with_existing_asset_lock_signer (AssetLockFunding::FromExistingAssetLock) consumes an already-tracked lock -- the crash-recovery path for a top-up interrupted between Core confirmation and Platform submission. The IdentityTopUp transition is signed entirely by the asset lock's Core-side key (no identity-key signer), so both take only a MnemonicResolver core signer. Guard the sub-floor funds trap: an amount between dust and Platform's processing-start minimum (50000 duffs) builds a real lock Core accepts but Platform rejects, stranding the funds. The funding export rejects amount_duffs < MIN_TOP_UP_DUFFS before any broadcast. Add null-pointer + sub-floor guard unit tests for both exports, and the design spec under docs/ios-managed-topup/. Refs #4092 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
dash_sdk_identity_topup_with_instant_lock (+ _and_wait) required the caller to build an InstantSend proof and pass a raw 32-byte asset-lock private key across FFI into a non-zeroizable Swift Data. The managed platform_wallet_top_up_identity_with_funding_signer path supersedes it (key material stays behind the Keychain resolver, never crossing FFI as plaintext) and the app has zero callers. Delete the rs-sdk-ffi exports (topup.rs and its re-exports) and the Swift identityTopUp / topUpIdentity wrappers. The rs-sdk TopUpIdentity trait is kept -- the managed orchestrator uses it. Refs #4092 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add ManagedPlatformWallet.topUpIdentityWithFunding and resumeTopUpWithAssetLock, mirroring the registration funding/resume pair, over the new managed FFI exports. Implement the example-app executeIdentityTopUp handler (previously a notImplemented stub) and a new executeIdentityTopUpResume recovery handler, with catalog + menu entries. The amount is Core-side duffs; the UI gates on the same 50000-duff floor the FFI enforces so a sub-floor amount never reaches the network. The resume handler reverses the display-order txid to wire order (matching OutPointFFI, as CreateIdentityView.parseOutPointHex does) and classifies the opaque "already consumed" rejection into a friendly message. Refs #4092 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 53 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds managed identity top-up and resume flows through Rust FFI, Swift SDK APIs, and the example app, while removing obsolete instant-lock top-up APIs. ChangesManaged identity top-up
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant TransitionDetailView
participant ManagedPlatformWallet
participant PlatformWalletFFI
participant IdentityWallet
participant PersistentIdentity
TransitionDetailView->>ManagedPlatformWallet: submit funded or resume top-up
ManagedPlatformWallet->>PlatformWalletFFI: call signer-based top-up export
PlatformWalletFFI->>IdentityWallet: create or consume asset lock
IdentityWallet-->>PlatformWalletFFI: return updated balance
PlatformWalletFFI-->>ManagedPlatformWallet: return FFI result and balance
ManagedPlatformWallet-->>TransitionDetailView: return balance
TransitionDetailView->>PersistentIdentity: persist updated balance
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
|
🔍 Review in progress — actively reviewing now (commit f449142) |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
packages/rs-platform-wallet-ffi/src/identity_top_up.rs (1)
144-154: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueFunds-safety floor is duplicated across the FFI boundary.
MIN_TOP_UP_DUFFS(Rust) andminTopUpDuffs(Swift) both hardcode50_000independently; the Swift copy already documents that it's meant to mirror the Rust value, so a future change to either side risks silent drift.
packages/rs-platform-wallet-ffi/src/identity_top_up.rs#L144-L154: keep as the source of truth; optionally expose it via a small FFI getter (e.g.platform_wallet_min_top_up_duffs()) so Swift can read it instead of re-declaring the literal.packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/TransitionDetailView.swift#L614-L619: if the getter above is added, replace the hardcoded50_000with a value fetched from the FFI at startup/first use.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/rs-platform-wallet-ffi/src/identity_top_up.rs` around lines 144 - 154, Keep MIN_TOP_UP_DUFFS in identity_top_up.rs as the sole source of truth and expose it through a small FFI getter such as platform_wallet_min_top_up_duffs(). In packages/rs-platform-wallet-ffi/src/identity_top_up.rs:144-154, add the getter using MIN_TOP_UP_DUFFS; in packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/TransitionDetailView.swift:614-619, replace the hardcoded minTopUpDuffs value with the getter result at startup or first use.packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/TransitionDetailView.swift (1)
614-650: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAmount floor is only enforced reactively, not gated in the UI.
Per the PR's design doc, the sub-floor amount should disable submit + show a "minimum…" hint proactively; here it's only caught by a
guardafter the user taps Execute. Funds are already safe (the guard runs before any FFI/broadcast call), so this is a UX-completeness gap versus the documented intent rather than a correctness bug.Consider surfacing
Self.minTopUpDuffsinisButtonEnabled/as inline helper text for theamountfield so the constraint is visible before submission, mirroringCreateIdentityView.currentMinFundingDuffs.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/TransitionDetailView.swift` around lines 614 - 650, The minTopUpDuffs constraint is enforced only after submission instead of proactively in the UI. Update isButtonEnabled and the amount-field presentation in TransitionDetailView to disable Execute and show inline minimum-amount guidance when the parsed amount is below Self.minTopUpDuffs, mirroring CreateIdentityView.currentMinFundingDuffs while preserving executeIdentityTopUp’s validation guard.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/TransitionDetailView.swift`:
- Around line 671-723: Add a confirmation gate to the generic transition
execution flow before invoking executeIdentityTopUpResume and
wallet.resumeTopUpWithAssetLock. Present the selected identity and asset-lock
outpoint (txid and vout), require explicit user confirmation, and only then
perform the resume; canceling must leave the transition untouched.
---
Nitpick comments:
In `@packages/rs-platform-wallet-ffi/src/identity_top_up.rs`:
- Around line 144-154: Keep MIN_TOP_UP_DUFFS in identity_top_up.rs as the sole
source of truth and expose it through a small FFI getter such as
platform_wallet_min_top_up_duffs(). In
packages/rs-platform-wallet-ffi/src/identity_top_up.rs:144-154, add the getter
using MIN_TOP_UP_DUFFS; in
packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/TransitionDetailView.swift:614-619,
replace the hardcoded minTopUpDuffs value with the getter result at startup or
first use.
In
`@packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/TransitionDetailView.swift`:
- Around line 614-650: The minTopUpDuffs constraint is enforced only after
submission instead of proactively in the UI. Update isButtonEnabled and the
amount-field presentation in TransitionDetailView to disable Execute and show
inline minimum-amount guidance when the parsed amount is below
Self.minTopUpDuffs, mirroring CreateIdentityView.currentMinFundingDuffs while
preserving executeIdentityTopUp’s validation guard.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7ee2df99-41b4-418d-b42e-714cf968c8db
📒 Files selected for processing (10)
docs/ios-managed-topup/SPEC.mdpackages/rs-platform-wallet-ffi/src/identity_registration_funded_with_signer.rspackages/rs-platform-wallet-ffi/src/identity_top_up.rspackages/rs-sdk-ffi/src/identity/mod.rspackages/rs-sdk-ffi/src/identity/topup.rspackages/swift-sdk/Sources/SwiftDashSDK/FFI/StateTransitionExtensions.swiftpackages/swift-sdk/Sources/SwiftDashSDK/Models/StateTransitionDefinitions.swiftpackages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ManagedPlatformWallet.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/TransitionCategoryView.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/TransitionDetailView.swift
💤 Files with no reviewable changes (3)
- packages/rs-sdk-ffi/src/identity/topup.rs
- packages/rs-sdk-ffi/src/identity/mod.rs
- packages/swift-sdk/Sources/SwiftDashSDK/FFI/StateTransitionExtensions.swift
thepastaclaw
left a comment
There was a problem hiding this comment.
Code Review
Two thin FFI exports for managed identity top-up (new-lock and resume-from-existing-lock) are wired correctly into iOS, but the sub-floor amount guard (MIN_TOP_UP_DUFFS = 50_000) is 500 duffs short of the actual consensus minimum at the currently active protocol version, letting a real Core asset lock be broadcast and then permanently stranded by Platform. The resume-from-tracked-lock flow also skips the confirmation step the PR's own spec document mandates before irreversibly crediting an identity. A minor defensive-coding inconsistency (missing zero-sentinel on one of two new sibling FFI exports) was independently flagged by both Claude lanes.
Source (experiment sonnet-primary-opus-quarter-sample-20260710, cohort sonnet_primary, bucket 3): reviewers codex/general=gpt-5.6-sol(completed_parseable_output_with_nonzero_wrapper_exit); sonnet5/general=claude-sonnet-5(completed); codex/ffi-engineer=gpt-5.6-sol(completed); sonnet5/ffi-engineer=claude-sonnet-5(completed); verifier=verifier-sonnet5-4093-1783776297=claude-sonnet-5; orchestrator=openai/gpt-5.6-sol reasoning=high (orchestration-only, not a reviewer/verifier).
🔴 2 blocking | 🟡 1 suggestion(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/rs-platform-wallet-ffi/src/identity_top_up.rs`:
- [BLOCKING] packages/rs-platform-wallet-ffi/src/identity_top_up.rs:154: MIN_TOP_UP_DUFFS is 500 duffs below the actual consensus floor at the active protocol version, allowing broadcast locks that Platform will strand
`MIN_TOP_UP_DUFFS = 50_000` only accounts for `required_asset_lock_duff_balance_for_processing_start_for_identity_top_up` (the v0 fee calculation). But `IdentityTopUpTransition::calculate_min_required_fee` dispatches on `platform_version.dpp.state_transitions.identities.calculate_min_required_fee_on_identity_top_up_transition`, and the currently active/latest protocol versions (v11, v12 — both wired to `STATE_TRANSITION_VERSIONS_V3`) set this to `1`, selecting `calculate_min_required_fee_v1`. That path adds `identity_topup_base_cost` (500,000 credits = 500 duffs at `CREDITS_PER_DUFF = 1000`) on top of the asset-lock floor: `base_cost.saturating_add(asset_lock_base_cost)` = 50,500,000 credits = 50,500 duffs. This is enforced on-chain in `rs-drive-abci/.../identity_top_up/transform_into_action/v0/mod.rs:59` via `required_balance = self.calculate_min_required_fee(...)`, which the asset-lock proof value is checked against.
Amounts from 50,000–50,499 duffs pass this FFI guard and the identical Swift mirror at `TransitionDetailView.swift:619`, build and broadcast a real Core transaction spending real UTXOs, and are then rejected by Platform for insufficient asset-lock balance — permanently stranding the funds in a lock that can never complete the top-up. This is exactly the funds-safety scenario the guard's own doc comment (lines 145-153) says it exists to prevent. Notably, the PR's own `docs/ios-managed-topup/SPEC.md:216-217` cites the same `v3.rs:21` file for the 50,000 floor but misses that the same file's `calculate_min_required_fee_on_identity_top_up_transition: 1` (line 31) switches the active calculation to include the base cost.
- [SUGGESTION] packages/rs-platform-wallet-ffi/src/identity_top_up.rs:201-209: out_new_balance has no zero-sentinel before fallible work, unlike its sibling added in the same PR
`platform_wallet_top_up_identity_with_funding_signer` never writes a sentinel to `*out_new_balance` before the fallible `amount_duffs` guard, `block_on_worker` call, or `unwrap_result_or_return!`. If any of those return early, `out_new_balance` is left at whatever the caller's stack held. Its direct sibling added in this same PR, `platform_wallet_topup_identity_with_existing_asset_lock_signer` (`identity_registration_funded_with_signer.rs:282-283`), explicitly writes `*out_new_balance = 0;` right after the null checks with the comment "FFI-safe sentinel before any fallible work" — showing the pattern is known and applied elsewhere in this PR, just not here. This is a public `extern "C"` export whose own safety doc only requires `out_new_balance` to be "writable", not pre-zeroed, so a caller that reads it without checking the return code first sees defined `0` from one export and garbage from the other. Currently masked because the only Swift caller local-initializes `newBalance = 0` and never reads it after a thrown error.
In `packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/TransitionDetailView.swift`:
- [BLOCKING] packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/TransitionDetailView.swift:688-702: Resume-from-tracked-lock executes immediately with no confirmation, contradicting the PR's own spec
`executeIdentityTopUpResume` parses the outpoint and calls `wallet.resumeTopUpWithAssetLock` immediately with no confirmation step. A tracked asset lock isn't bound to a specific identity — any self-owned identity can consume it — and this screen lets the user pick an arbitrary identity via `selectedIdentityId` and fire the resume in one action. `docs/ios-managed-topup/SPEC.md:174-183` (added in this same PR) explicitly calls this out: \"Add a confirmation step ('top up identity X with lock Y?') before invoking — resume directs a tracked lock at whatever identity is selected... a stray lock could still land on the wrong self-owned identity, which is not undoable.\" No confirmation UI exists anywhere in `TransitionDetailView.swift` or `TransitionCategoryView.swift` for this flow — the implementation doesn't follow its own design doc on a funds-safety point.
- MIN_TOP_UP_DUFFS 50000 -> 50500. The active v1 fee calc (IdentityTopUpTransition::calculate_min_required_fee_v1) adds identity_topup_base_cost (500000 credits = 500 duffs) on top of the 50000-duff asset-lock floor, so the real consensus minimum is 50500 duffs (enforced on-chain by tx_out_credit_value < required_balance). Amounts 50000-50499 previously passed the guard, built and broadcast a real Core lock, and were then stranded by Platform -- the exact funds-safety trap the guard exists to prevent. Bumped in the FFI const, the Swift UI gate, the catalog help, and the spec. - Add the `*out_new_balance = 0` sentinel before fallible work in the funding export, matching its FromExistingAssetLock sibling, so an early-return leaves a defined value. - Gate the example-app resume flow behind a confirmation dialog summarizing the target identity + outpoint. A tracked asset lock is not bound to an identity; resume directs it at whatever identity is selected, and a stray lock landing on the wrong self-owned identity is not undoable. Addresses PR #4093 review (thepastaclaw, CodeRabbit). Refs #4092 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
Prior Reconciliation: All 3 prior findings are FIXED and independently verified against source at head 24328aacc0a80019386fff760ad3d81200a15e68. MIN_TOP_UP_DUFFS is now 50_500 duffs, which is mathematically correct against the actual consensus formula (identity_topup_base_cost 500_000 credits + required_asset_lock_duff_balance_for_processing_start_for_identity_top_up 50_000 duffs × CREDITS_PER_DUFF 1000 = 50,500,000 credits = 50,500 duffs), mirrored correctly in the Swift minTopUpDuffs constant, UI help text, and SPEC.md. The resume-from-tracked-lock flow now gates on a .confirmationDialog before firing. out_new_balance gets a zero sentinel before fallible work in the funding-signer export, matching its sibling. Carried-Forward Prior Findings: None. New Findings In Latest Delta: None. Additional Cumulative Findings: None — only the 4 expected files changed since the prior review, and all four agent lanes converge with no disagreement.
Source: (experiment sonnet-primary-opus-quarter-sample-20260710, cohort sonnet_primary, bucket 3, trigger new_push, prior head 4e74559): reviewers codex/general=gpt-5.6-sol(completed); sonnet5/general=claude-sonnet-5(completed); codex/ffi-engineer=gpt-5.6-sol(completed); sonnet5/ffi-engineer=claude-sonnet-5(completed); verifier=verifier-sonnet5-4093-1783778586=claude-sonnet-5; orchestrator=openai/gpt-5.6-sol reasoning=high (orchestration-only, not a reviewer/verifier).
Remove docs/ios-managed-topup/SPEC.md — it was the research/review design doc, not intended to ship in the repo. Net effect on the PR: the spec is no longer added (add + remove cancels in the base...head diff). Refs #4092 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ID-13 ("Top up identity, builder path") was marked retired/notImplemented
stub. This feature un-retires it: the builder path now runs a managed
Core-funded top-up (executeIdentityTopUp -> topUpIdentityWithFunding ->
platform_wallet_top_up_identity_with_funding_signer), building a new Core
asset lock from wallet balance -- distinct from ID-05/ID-06, which spend
already-funded Platform addresses. Flip it to 🧪 (builder-reachable),
Tier=Common, and note the 50,500-duff floor and the removed raw-key path.
Add ID-16 for the crash-recovery resume flow (executeIdentityTopUpResume
-> resumeTopUpWithAssetLock ->
platform_wallet_topup_identity_with_existing_asset_lock_signer), incl. the
confirmation dialog and the clean-failure behavior for
untracked/consumed/foreign outpoints. Extend the §6 Identity span to
ID-01..16.
Funded e2e for both is not yet run (testnet UAT pending) -- noted in the
rows, not claimed as verified.
Refs #4092
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## v4.1-dev #4093 +/- ##
============================================
+ Coverage 87.40% 87.42% +0.02%
============================================
Files 2639 2643 +4
Lines 333066 333632 +566
============================================
+ Hits 291103 291684 +581
+ Misses 41963 41948 -15
🚀 New features to boost your workflow:
|
…nd-example-app Conflicts: Cargo.lock (theirs + re-resolve) and identity_top_up.rs (base #4093's rework — MIN_TOP_UP_DUFFS floor, out_new_balance sentinel, guard tests — supersedes the branch's older zero-guard). Breaking-FFI adaptations for the Android JNI/Kotlin side: - #4093/#4126: shielded identity-create/transfer/unshield/withdraw gained a mnemonic_resolver_handle param — threaded through the JNI exports, FundingNative externs, and PlatformWalletManager; the transfer/unshield/withdraw trio now runs under teardownGate.op (they borrow the manager's resolver, so the round-46 ungated rationale no longer holds). - #4127 typed provider keys: the pool-entry write trampoline forwards exactly public_key_len meaningful bytes (blob self-describing by length: 33 ECDSA / 48 BLS / 32 EdDSA); the load path rebuilds the 48-byte slot + key_type_tag from the stored blob length. No Kotlin bridge/descriptor change needed. - AccountSpecFFI lost derived_platform_node_keys(+count) (moved into the typed core-address rows) — the round-42 null-init is dropped. - #4126 Orchard viewing keys: the three new vtable slots are None — binds keep resolving the seed via the mnemonic resolver (the documented fallback); the seedless-bind persistence port is tracked as a follow-up. Verified: cargo fmt, JNI check (shielded), workspace clippy --all-features -D warnings, platform-wallet-ffi lib tests (170), gradle :sdk+:app tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Issue being fixed or feature implemented
Closes #4092. Converges identity top-up from a Core asset lock onto a single managed path shared by iOS and Android, and wires it on iOS (previously unimplemented — the example-app
executeIdentityTopUpwas anotImplementedstub).There were three fragmented top-up paths at different layers, none shared (see #4092). The correct "from asset lock" abstraction is the managed orchestrator
IdentityWallet::top_up_identity_with_funding, which is already onv4.1-devand does the full lifecycle (build/resolve the lock, IS→CL fallback, retries, persist balance). The only missing pieces were the thin FFI exports over it and the iOS wiring.What was done?
Shared FFI (
rs-platform-wallet-ffi) — two managed exports, both thin delegates to the upstream orchestrator (no reimplementation), giving top-up the same register+resume symmetry registration already has:platform_wallet_top_up_identity_with_funding_signer(FromWalletBalance) — build a new lock from wallet balance. Extracted from feat(sdk): add Kotlin SDK and KotlinExampleApp (Android port of SwiftExampleApp) #3999.platform_wallet_topup_identity_with_existing_asset_lock_signer(FromExistingAssetLock) — consume an already-tracked lock; the crash-recovery path for a top-up interrupted between Core confirmation and Platform submission. Extracted from the DIP-15 branch.The
IdentityTopUptransition is signed entirely by the asset lock's Core-side key (no identity-key signer), so both take only aMnemonicResolvercore signer — key material never crosses FFI as plaintext.Sub-floor funds guard — an amount between dust and Platform's processing-start minimum (
50000duffs) builds a real lock Core accepts but Platform rejects, stranding funds. Enforced in both the export (MIN_TOP_UP_DUFFS) and the iOS UI gate (defense in depth).iOS (
swift-sdk) —ManagedPlatformWallet.topUpIdentityWithFunding+resumeTopUpWithAssetLock; example-appexecuteIdentityTopUp(now implemented) +executeIdentityTopUpResume, with catalog/menu entries. Resume reverses display-order txid → wire order and classifies the opaque "already consumed" rejection.Retired the raw-key primitive — deleted
dash_sdk_identity_topup_with_instant_lock(+_and_wait) and its SwiftidentityTopUp/topUpIdentitywrappers (zero app callers; the managed path supersedes it and avoids a raw 32-byte private key crossing FFI into non-zeroizable SwiftData).Follow-ups
TopUpFromCoreViewwith a funding-account picker + auto-detection of tracked stuck locks (this PR ships an explicit-outpoint resume entry for the QA app).How Has This Been Tested?
cargo check+cargo clippyclean onplatform-wallet-ffiandrs-sdk-ffi.0andMIN-1) rejection for the funding export../build_ios.sh --target simregenerates the cbindgen header (new symbols present, retired symbols gone); SwiftExampleApp builds against it.Breaking Changes
Removes the FFI export
dash_sdk_identity_topup_with_instant_lock(and..._and_wait) fromrs-sdk-ffi, and the public Swift SDK methodsSDK.topUpIdentity(...)/identityTopUp(...). Any external consumer linking those symbols must migrate to the managedplatform_wallet_top_up_identity_with_funding_signer/ManagedPlatformWallet.topUpIdentityWithFunding. No in-repo callers.Checklist:
For repository code-owners and collaborators only
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Changes