Skip to content

feat(swift-sdk): split build/broadcast with reservation release for BIP70-style deferred submission - #4322

Merged
QuantumExplorer merged 2 commits into
v4.2-devfrom
claude/frosty-feistel-30b724
Aug 6, 2026
Merged

feat(swift-sdk): split build/broadcast with reservation release for BIP70-style deferred submission#4322
QuantumExplorer merged 2 commits into
v4.2-devfrom
claude/frosty-feistel-30b724

Conversation

@QuantumExplorer

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

#4308 added the deferred BIP70/BIP270 send flow — finalize and sign now (reserving the funding UTXOs), hand the raw bytes to a merchant server, then broadcast on ack or release the reservation on a nack/abandonment — but exposed it Kotlin-only. The C exports (core_wallet_signed_payment_finalize / _broadcast / _release) and the Swift error arms (codes 34–36) were already in place; this PR adds the missing Swift bridge surface.

What was done?

Bridge-only per packages/swift-sdk/CLAUDE.md — marshal in, call FFI, marshal out; every lifecycle decision stays in Rust:

  • SignedCoreTransaction (CoreTransactionBuilder.swift): the ownership object modeled on Kotlin's ManagedPlatformWallet.SignedCoreTransaction. Carries txidHex / rawTxBytes / feeDuffs / reservationToken; OWNS the token and releases it exactly once via explicit close() or a deinit backstop, so an abandoned payment never strands its funding reservation until key-wallet's TTL. The native release is idempotent, so a close after broadcast/release is a harmless no-op. The release action is injectable (internal seam) so the unit test can count releases without registry introspection — the ARC-deterministic analog of Kotlin's countable NativeCleaner runnable.
  • CoreTransactionBuilder.finalizeSignedPayment: mirrors finalizeAtomic's shape (consumed guard, per-call MnemonicResolver, withExtendedLifetime); one atomic native select + reserve + sign + register. Frees the returned txid string and transaction on every path, copies the borrowed byte view before the free, and defensively releases a minted token if a post-success marshalling guard trips (mirroring the owner-guarded release Kotlin does, per feat(kotlin-sdk): split build/broadcast with reservation release for BIP70-style deferred submission #4185).
  • ManagedCoreWallet.broadcastSignedPayment(token:) (internal) and the public ManagedPlatformWallet surface: buildSignedPayment, broadcastSigned(token:) / broadcastSigned(_:), releaseReservation(token:) / releaseReservation(_:) — token and object-owning forms matching Kotlin, with the object forms holding the payment alive across the native call (withExtendedLifetime, the Swift analog of Kotlin's reachabilityFence) and disarming the backstop once the token is consumed.
  • Each wrapper's doc comment cites its Kotlin reference per the parity convention.
  • Parity manifest: new core.deferred_signed_payment capability (Swift + Kotlin sdk: supported), declaring the three shared FFI symbols and referencing the new Swift unit tests, feat(kotlin-sdk): split build/broadcast with reservation release for BIP70-style deferred submission #4308's Kotlin SignedCoreTransactionTest cases, and three shared signed_payment_registry.rs lifecycle tests. Summary regenerated with --write-summary.

How Has This Been Tested?

  • New hermetic SignedCoreTransactionTests (5 tests, all passing via swift test --filter SignedCoreTransactionTests against the rebuilt mac slice): ownership round-trip, close-exactly-once, deinit backstop, close-then-deinit no double release, and a real-seam smoke test that links core_wallet_signed_payment_release and asserts releasing an unknown token is a silent no-op.
  • Full swift build --build-tests + swift test pass in Swift 6 language mode against a freshly rebuilt DashSDKFFI.xcframework (regenerated cbindgen headers include the three new exports).
  • python3 scripts/check_sdk_parity_manifest.py --write-summary passes (24 capabilities).

Breaking Changes

None — additive surface only; the immediate send path is untouched.

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

🤖 Generated with Claude Code

…IP70-style deferred submission

Swift counterpart of the Kotlin-only deferred send flow from #4308. Bridge-only
wrappers over the existing core_wallet_signed_payment_finalize / _broadcast /
_release FFI exports:

- SignedCoreTransaction owns the reservation token: close() releases exactly
  once, deinit is the backstop, so an abandoned payment never strands its
  funding reservation until key-wallet's TTL.
- CoreTransactionBuilder.finalizeSignedPayment: one atomic native
  select + reserve + sign + register, with an owner-guarded defensive release
  on post-success marshalling guards.
- ManagedCoreWallet.broadcastSignedPayment and the ManagedPlatformWallet
  surface (buildSignedPayment / broadcastSigned / releaseReservation, token
  and object-owning forms) mirroring the Kotlin reference.
- Parity manifest capability core.deferred_signed_payment with Swift, Kotlin,
  and shared registry test references.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@QuantumExplorer, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 48 seconds

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 84702d42-3349-4f23-aa53-27430943bec8

📥 Commits

Reviewing files that changed from the base of the PR and between 438153d and e5e4c46.

📒 Files selected for processing (7)
  • docs/sdk/sdk-parity-manifest.json
  • packages/kotlin-sdk/PARITY_SUMMARY.md
  • packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/CoreWallet/CoreTransactionBuilder.swift
  • packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/CoreWallet/ManagedCoreWallet.swift
  • packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/ManagedPlatformWallet.swift
  • packages/swift-sdk/SwiftTests/SwiftDashSDKIntegrationTests/Core/DeferredSignedPaymentIntegrationTests.swift
  • packages/swift-sdk/SwiftTests/SwiftDashSDKTests/SignedCoreTransactionTests.swift

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added this to the v4.2.0 milestone Aug 6, 2026
@thepastaclaw

thepastaclaw commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

🔍 Review in progress — actively reviewing now (commit e5e4c46)
Stage: Opus review + final verification
ETA: complete ~15:35 UTC (median 21m across 30 recent reviews)
Running 19m · Last checked: 2026-08-06 15:30 UTC

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Final validation — Codex + Opus

The Swift bridge matches the native deferred-payment ownership and marshalling lifecycle, and no blocking defect was confirmed. The remaining in-scope suggestion is to exercise the finalize and broadcast C ABI from Swift, because the added tests currently stop above and below that host boundary.
Source: reviewer evidence — codex/gpt-5.6-sol and claude/claude-sonnet-5; final verifier — codex/gpt-5.6-sol (fallback for failed Sonnet verification). Orchestration-only, not reviewer evidence: openclaw-agent/cliproxy/gpt-5.6-sol.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — ffi-engineer (completed)
  • Verifier: gpt-5.6-sol — final-verifier (Opus verifier fallback)
  • Opus reviewers: claude-sonnet-5 — general (completed), claude-sonnet-5 — ffi-engineer (failed), claude-sonnet-5 — ffi-engineer (completed)

🟡 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/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/CoreWallet/CoreTransactionBuilder.swift`:
- [SUGGESTION] packages/swift-sdk/Sources/SwiftDashSDK/PlatformWallet/CoreWallet/CoreTransactionBuilder.swift:404-415: Exercise the finalize and broadcast FFI paths from Swift
  The new Swift tests instantiate `SignedCoreTransaction` directly and only reach the native release symbol with an unknown token. No test invokes `buildSignedPayment`/`finalizeSignedPayment` or `broadcastSigned`, so regressions in out-parameter ordering, copying the borrowed transaction bytes before `core_wallet_transaction_free`, txid ownership, error mapping, and the post-success token-reconciliation guards would not be detected at the C/Swift boundary. The shared Rust registry tests run below this boundary, while the ownership tests run above it. Extend the existing funded local-devnet Swift integration suite with build→broadcast and build→release paths, asserting the returned txid, raw bytes, fee, and token-consumption/release behavior.

… the integration suite

Review follow-up: the hermetic SignedCoreTransactionTests run above the C
boundary and the Rust signed_payment_registry tests below it, so out-parameter
marshalling, txid ownership, the borrowed-bytes copy, error-code mapping, and
reservation consume/release went unexercised at the host boundary.

DeferredSignedPaymentIntegrationTests (funded local-devnet suite, gated by
RUN_INTEGRATION_TESTS=1 like its siblings) adds:
- build -> broadcast: marshalled fields asserted per out param, broadcast txid
  must equal the finalize-computed txidHex, recipient credited after mining,
  double-broadcast throws the typed .reservationTokenConsumed arm, defensive
  release after consumption is a no-op.
- build -> release: a second build against the fully reserved wallet fails,
  release frees the inputs so the rebuild succeeds with a fresh token, and
  broadcasting the released token throws .reservationTokenConsumed.

Both registered as integration-kind verification for
core.deferred_signed_payment in the parity manifest.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@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 52df096 into v4.2-dev Aug 6, 2026
16 checks passed
@QuantumExplorer
QuantumExplorer deleted the claude/frosty-feistel-30b724 branch August 6, 2026 15:25
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.

2 participants