Skip to content

feat: add private payment requests - #1172

Open
ben-kaufman wants to merge 8 commits into
masterfrom
codex/paykit-payment-request-ui-android
Open

feat: add private payment requests#1172
ben-kaufman wants to merge 8 commits into
masterfrom
codex/paykit-payment-request-ui-android

Conversation

@ben-kaufman

@ben-kaufman ben-kaufman commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

This PR adds private Paykit Payment Requests to Bitkit.

Description

  1. Automatically opens incoming requests in the existing Send confirmation flow with the requesting contact, exact amount, and a Payment Request title.
  2. Keeps dismissed requests actionable through a bell, preview sheet, and full request history, with manual reopen and explicit rejection.
  3. Adds outgoing request creation from Receive for linked, saved contacts, including amount, note, expiry, queued delivery state, and sent history.
  4. Drops expired or remotely unavailable requests, keeps presentation state scoped to the active Pubky identity, and protects account changes, sheet transitions, and overlapping actions.
  5. Requires strict private resolution for requests: a consumed Private Payment List is never reused, another endpoint from that list is not attempted, and public details are never used as fallback while waiting for a newer list.
  6. Updates Paykit to 0.1.0-rc44 and adds local E2E homeserver configuration plus safe cold-start restoration for externally managed Pubky sessions.

The request payload itself remains SDK-backed and durable; Bitkit persists only encrypted, identity-scoped presentation suppression, not a duplicate request queue. Payment proofs and receipts remain out of scope.

Dependencies:

Preview

N/A — proof recordings were completed locally and are intentionally not attached to the PR.

QA Notes

Manual Tests

  • 1. Clean wallet → create Pubky profile → enable Paykit and Contact Payments → add the peer as a contact: private-capable request action appears once the Noise link is established.
  • 2. Peer creates a private request → Home: Payment Request opens automatically with the correct contact and amount.
  • 3. Payment Request → dismiss without rejecting → bell → request preview → Pay: the request remains queued, reopens, and pays successfully.
  • 4. Peer creates a second request after payment → Pay: a newer Private Payment List is used; the consumed list is not reused and no public fallback occurs.
  • 5. Receive → Send Payment Request → enter amount, note, and expiry → select linked contact → Send: request is queued once and appears in sent history.
  • 6. Incoming request → Reject: only that request becomes terminal and the private payment list is not consumed.
  • 7. Incoming request → dismiss → relaunch: request remains discoverable without automatically reopening again; expired requests disappear live.
  • 8. Cross-platform E2E: iOS creates two requests that Android receives and pays, and Android creates two requests that iOS receives and pays, on clean regtest state.

Automated Checks

  • PaykitPaymentRequestRepoTest.kt: covers mapping, eligibility, proposal delivery, rejection, expiry, identity-scoped presentation state, and action serialization.
  • PaykitSdkServiceTest.kt: covers exact identity enforcement and safe deferred session restoration.
  • AppViewModelSendFlowTest.kt: covers automatic/manual presentation, sheet transitions, identity changes, newer-list retry, strict private resolution, and payment lifecycle races.
  • PaymentRequestExpirationTest.kt: covers expiry selection and retained draft state.
  • SheetHostTest.kt: covers locked sheet dismissal and scrim input isolation during durable proposal creation.
  • Local verification passed: app compile, Android-test compile, complete dev unit suite, detekt, and git diff --check.
  • Both final cross-platform proof videos decoded end to end without errors.

Comment thread app/src/main/java/to/bitkit/services/PaykitSdkService.kt Fixed
Comment thread app/src/main/java/to/bitkit/services/PaykitSdkService.kt Fixed
Comment thread app/src/main/java/to/bitkit/services/PaykitSdkService.kt Fixed
Comment thread app/src/main/java/to/bitkit/services/PaykitSdkService.kt Fixed
Comment thread app/src/main/java/to/bitkit/services/PaykitSdkService.kt Fixed
Comment thread app/src/main/java/to/bitkit/services/PaykitSdkService.kt Fixed
@greptile-apps

greptile-apps Bot commented Aug 20, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds private Paykit payment-request creation, incoming request presentation and history, rejection, identity-scoped suppression, and stricter private endpoint handling. It also upgrades Paykit and adds local E2E homeserver and stale-session initialization support.

  • Adds incoming and outgoing payment-request repository state, SDK adapters, expiry, delivery, and presentation handling.
  • Adds request creation, preview/history, bell, and guarded sheet UI.
  • Adds identity-scoped encrypted presentation state and expanded lifecycle/race tests.

Confidence Score: 4/5

The identity-change creation race should be fixed before merging because it can create a request remotely while leaving the sender with no success or failure feedback.

A successful SDK proposal can be excluded from sentRequests after an identity generation change, and the ViewModel then suppresses the only callback that advances the creation flow.

Files Needing Attention: app/src/main/java/to/bitkit/repositories/PaykitPaymentRequestRepo.kt, app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt

Important Files Changed

Filename Overview
app/src/main/java/to/bitkit/repositories/PaykitPaymentRequestRepo.kt Adds identity-scoped incoming/outgoing request state, proposal and rejection operations, expiry, target eligibility, and presentation persistence; successful proposals can be omitted from local sent state after an identity race.
app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt Orchestrates request polling, automatic/manual presentation, retries, identity transitions, creation, and rejection; its conditional success callback can silently strand a completed proposal.
app/src/main/java/to/bitkit/services/PaykitSdkService.kt Adds payment-request SDK operations, capability discovery, exact identity checks, and stale-session initialization recovery.
app/src/main/java/to/bitkit/ui/screens/paymentrequests/CreatePaymentRequestScreen.kt Adds amount, note, expiry, recipient selection, and sent-state screens for outgoing requests.
app/src/main/java/to/bitkit/ui/screens/paymentrequests/PaymentRequestsScreen.kt Adds incoming preview and complete incoming/sent request history with pay and reject actions.
app/src/main/java/to/bitkit/ui/components/SheetHost.kt Adds sheet visibility callbacks and dismissal locking for durable request creation.
app/src/main/java/to/bitkit/repositories/PaykitPaymentRequestPresentationStore.kt Persists encrypted, identity-scoped sets of already presented request identifiers.

Sequence Diagram

sequenceDiagram
    participant UI as Receive UI
    participant VM as AppViewModel
    participant Repo as PaymentRequestRepo
    participant SDK as Paykit SDK
    participant Peer as Contact
    UI->>VM: createPaymentRequest(draft, target)
    VM->>Repo: propose(...)
    Repo->>SDK: proposePaymentRequest(...)
    SDK-->>Peer: queue private request
    Repo->>SDK: processPendingPrivateMessages()
    Repo-->>VM: "Result<PaymentRequest>"
    VM-->>UI: onCreated(request)
Loading

Reviews (1): Last reviewed commit: "feat: add private payment requests" | Re-trigger Greptile

Comment thread app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt Outdated
@ben-kaufman
ben-kaufman force-pushed the codex/paykit-payment-request-ui-android branch 2 times, most recently from ba7f745 to e8183a5 Compare August 20, 2026 10:41
ovitrif
ovitrif previously approved these changes Aug 20, 2026

@ovitrif ovitrif 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.

Looks good. Durably queued requests stay confirmed after an identity change, and a consumed private payment list is never reused or replaced by public details.

@ovitrif ovitrif added this to the 2.5.0 milestone Aug 20, 2026
@ben-kaufman
ben-kaufman requested a review from piotr-iohk August 21, 2026 01:08
@ben-kaufman
ben-kaufman force-pushed the codex/paykit-payment-request-ui-android branch from 5120677 to 7877465 Compare August 21, 2026 01:16
@ovitrif

ovitrif commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

Local Locks interoperability was verified with pubky/paykit-server#2 at 41cda2567226a690a012770017d5e7c1d49e2a2b.

Note this paykit-server needs to integrated into the bitkit-docker and e2e tests soonish 🙏🏻

cc. @jvsena42 @piotr-iohk

@piotr-iohk

Copy link
Copy Markdown
Collaborator

Local Locks interoperability was verified with pubky/paykit-server#2 at 41cda2567226a690a012770017d5e7c1d49e2a2b.

Note this paykit-server needs to integrated into the bitkit-docker and e2e tests soonish 🙏🏻

cc. @jvsena42 @piotr-iohk

As far as paykit-server it would be good to have a staging deployment since paykit e2e tests are run against our staging regtest and also using staging homeserver (as far as I understand that was the plan, see: #1084 (comment))

Server staging
The intended next server-side QA step is to deploy Paykit Server on staging once its runtime/listener composition is implemented. There is no staging endpoint yet, and that work is outside these mobile PRs.

@ben-kaufman
ben-kaufman force-pushed the codex/paykit-payment-request-ui-android branch from af0aaa4 to e2516e9 Compare August 21, 2026 16:19
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.

4 participants