feat: support incoming paykit requests - #637
Conversation
Greptile SummaryThis PR adds support for receiving and paying incoming Paykit requests. The main changes are:
Confidence Score: 4/5The backup migration and payment submission paths need fixes before merging.
PrivatePaykitService+Backup.swift, LnurlPayConfirm.swift, and SendConfirmationView.swift
|
| Filename | Overview |
|---|---|
| Bitkit/Services/PaykitPaymentRequestService.swift | Adds request parsing, synchronization, expiration handling, presentation deduplication, and acceptance state. |
| Bitkit/Services/PrivatePaykitService+Payments.swift | Adds private request resolution, public fallback rules, and consumed-version enforcement. |
| Bitkit/Services/PrivatePaykitService+Backup.swift | Wraps Paykit backup state in a new JSON shape without restoring the previous raw-string format. |
| Bitkit/Views/Wallets/Send/LnurlPayConfirm.swift | Accepts and consumes incoming requests before the LNURL invoice is fetched. |
| Bitkit/Views/Wallets/Send/SendConfirmationView.swift | Integrates request acceptance and consumption but can submit an embedded invoice amount that differs from the requested amount. |
| Bitkit/AppScene.swift | Adds active-scene polling and serialized request presentation through the send sheet. |
| Bitkit/Services/PubkyService.swift | Adapts the Paykit integration to separate public and private rc39 APIs and advertises request support. |
Sequence Diagram
sequenceDiagram
participant Peer as Paykit Peer
participant Manager as Request Manager
participant Resolver as Private Resolver
participant UI as Send Confirmation
participant Wallet
Peer->>Manager: Proposed payment request
Manager->>Resolver: Resolve endpoint for requested amount
Resolver-->>UI: Payment target and list version
UI->>Manager: Accept request
UI->>Resolver: Persist consumed version
UI->>Wallet: Fetch invoice and submit payment
Note over UI,Wallet: LNURL fetch currently happens after acceptance and consumption
Reviews (1): Last reviewed commit: "feat: support incoming paykit requests" | Re-trigger Greptile
990db23 to
e4a5c92
Compare
ae345b3 to
778f6d0
Compare
778f6d0 to
9dcc431
Compare
|
@ben-kaufman pls try to merge master into this PR branch before a new review pass is submitted, to avoid invalidating it 🙏🏻 |
|
Done @ovitrif |
jvsena42
left a comment
There was a problem hiding this comment.
Reviewed against the companion Android PR (synonymdev/bitkit-android#1098). The two implementations are impressively well-aligned on the layers that matter most — identical backoff constants (refresh [30,60,120]s, presentation retry [30,60,120,300]s), identical request-mapping rules, equivalent amount parsing despite very different implementations, matching network scoping, and the same canUsePublicPayment / WaitingForUpdatedPaymentList policy. The follow-up backoff commit also cleanly resolved the unbounded retry loop and the dead code from the previous round.
Seven divergences from Android remain, flagged inline as D1–D7. D1 is the one I'd block on: iOS and Android invert the accept/consume ordering, and the iOS order has a reachable state where the counterparty is told "accepted" but no payment is sent. D2 and D3 are follow-ups to the same backoff commit's intent; D4–D7 are alignment polish.
Verified on c4f32ae6: xcodebuild Debug (iPhone 16 Pro sim) BUILD SUCCEEDED, SwiftFormat clean on all changed files.
Not blocking, carried over from the previous round: no reject action and presentedRequestIds is in-memory only (so a non-expiring request re-presents on every app launch — same on Android, so it reads as a deliberate shared scope decision); beginSavedContactPayment can block a tap for ~12s across its retry loop; redundant wallet.sendAmountSats write at AppScene.swift:824 that SendSheet.onAppear immediately overwrites; and 15 hand-edited locale files where the repo convention is English-only plus a Transifex sync.
jvsena42
left a comment
There was a problem hiding this comment.
Round 3 — reviewed b380b328 against the previous round. Good progress: D1, D2, D3, D5, D6 are properly fixed, and the new tests target the actual behaviour rather than restating it (testPreparationConsumesBeforeAccepting asserting ordering from inside the consume closure is a nice touch, as is testDeferredRequestStopsAfterConfiguredRetries walking the full 30/60/120/300s ladder to the cap). The redundant wallet.sendAmountSats write in AppScene is gone too.
D7 is partially addressed — the re-entrancy flag moved into the manager as isPresentingRequests with presentRequests(_:), so the @State smell is resolved and covered by testPresentationOperationIsNotReentered; the resolve → claim → handleScannedData → route → markPresented loop itself still lives untested in AppScene. D4 (connectivity-triggered refresh) is not addressed.
Two new issues introduced by the refactor are flagged inline as N1 and N2. N1 is the one I'd want handled before merge: consolidating the accept/consume into prepareForPayment dropped a post-await guard that the manager structurally cannot replace.
Verified on b380b328: xcodebuild Debug (iPhone 16 Pro sim) BUILD SUCCEEDED, SwiftFormat clean on all 6 changed files. I could not run scripts/validate-translations.js locally (Cannot find module 'glob' — my environment, not this branch), so the new wallet__payment_request_mismatch key is unverified by that check; adding it to en.lproj only is the right call per repo convention.
jvsena42
left a comment
There was a problem hiding this comment.
utAck, implementation still not testable end-to-end
…eanup refactor: batch paykit contact cleanup
Description
This PR builds on #630 to support incoming Paykit payment requests:
0.1.0-rc39and uses its separate public and private payment resolution APIs.Payment proofs and receipts remain out of scope.
Linked Issues/Tasks
Screenshot / Video
N/A — the existing payment UI is reused, and no media is attached.
QA Notes
Manual Tests
Automated Checks
PaykitPaymentRequestServiceTests.swift: request mapping, expiry, lifecycle, consume-before-accept ordering, bounded presentation retry, preparation recovery, and presentation serialization.PrivatePaykitServiceTests.swift: consumed-list persistence and prevention of private payment-detail reuse.PublicPaykitServiceTests.swift: separate public payment endpoint parsing and resolution.git diff --checkpassed.