Skip to content

fix: keep fixed paykit requests on confirmation with an asset switch - #1638

Open
ovitrif wants to merge 4 commits into
masterfrom
fix/paykit-fixed-request-asset-confirm
Open

ovitrif wants to merge 4 commits into
masterfrom
fix/paykit-fixed-request-asset-confirm

Conversation

@ovitrif

@ovitrif ovitrif commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #1623, closes #1630, closes #1631, closes #1632
Refs:

This PR keeps a fixed-amount payment request, such as a Pubky Market Shop order, on its confirmation step. On 3.0.1 and on master, a request whose payee offers both bitcoin and USDT opened a loading Payment Request screen, then moved to the Amount step on its own (#1623). From there, the USDT review showed a second Amount screen while the fee was quoted (#1632), sent the user back to Amount when the fee quote expired (#1630), and had a Pay From chip that did nothing (#1631). These issues share one cause: a request with a BTC/USDT choice had no confirmation step of its own, so the asset choice lived only on Amount.

Description

  • Opens a fixed request on the confirmation step of its preselected asset: bitcoin Confirm, or the USDT review. Before, openPaykitEndpoints took any request with a USDT option to Amount, because fix: confirm fixed Paykit requests directly #1581's direct confirmation (openBitcoinRequestConfirmation) stopped whenever usdtRecipient was set. Amount remains the fallback when the terms cannot be bound, for example with too little USDT, a missing rate or a Lightning amount below the minimum. Subscription periods keep their existing Amount review.
  • Makes Pay From on both confirmation steps switch between bitcoin (Savings or Spending) and USDT for a payment request; without a request, Pay From on a USDT review stays disabled as before. The switch rebinds the request's terms and replaces the current confirmation with the other asset's, so Back never returns to a confirmation bound to the other asset. A new swipe is always required.
  • Shows a loading confirmation (amount, request summary and a loading swipe) while the USDT fee is quoted, instead of the Amount page with a spinning Continue.
  • Replaces an expired USDT fee quote on the review itself, once per swipe, and shows "The fee quote expired and was updated. Check the fee and swipe again." Before, the expired quote dropped the review back to its Amount page. Declining a payment warning keeps the reviewed quote; the warning shows again on the next swipe.
  • Lets tapping the amount on the USDT review open Amount when the review is the first screen of the sheet, and close the sheet on back.

Out of Scope

Design

N/A — no design available. Reuses the existing Confirm, USDT review and Pay From chip; the USDT loading state follows the bitcoin Confirm's preparing placeholder.

Preview

Not captured: these screens need a live Paykit request with both bitcoin and USDT offered, which the local test environment cannot provide.

QA Notes

Journeys

N/A — not drivable; see Manual Tests.

Manual Tests

  • Open a fixed-amount Shop order request offering bitcoin and USDT, with USDT enabled → it opens on the confirmation of the preselected asset and never moves to Amount on its own — needs a live Pubky Market order, not in Capabilities
  • On that confirmation, tap Pay From → it switches between USDT and bitcoin confirmations; swipe pays with the chosen asset — same
  • On the USDT review, wait past the fee quote expiry, then swipe → the quote is replaced on the same screen with the notice, and a second swipe pays — same

Automated Checks

  • added AppViewModelSendFlowTest.kt — a fixed request switches asset on its confirmation instead of returning to Amount
  • added AppViewModelSendFlowTest.kt — a fixed USDT request without enough USDT opens Amount
  • added AppViewModelSendFlowTest.kt — a contact USDT review without a payment request keeps Pay From disabled
  • added UsdtViewModelTest.kt — an expired quote is replaced on review with the notice, at most once per swipe; other errors are left for the user
  • added UsdtViewModelTest.kt — declining a warning keeps the reviewed quote and warns again on the next swipe
  • updated AppViewModelSendFlowTest.kt — a fixed dollar request opens confirmation whether or not USDT is enabled; an automatic USDT request finishes preparation on its review

@ovitrif ovitrif self-assigned this Oct 20, 2026
@ovitrif
ovitrif requested review from a team, ben-kaufman and pwltr and removed request for a team October 20, 2026 23:24
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-20T23:28:38.007941Z 1568abb PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1568abb741

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@greptile-apps

greptile-apps Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 3/5

[Medium impact] The changes reach Android's Paykit payment-request confirmation flow.

Fix Back after asset switching and the endless loader after warning cancellation before merging.

Findings

  1. P1 Back restores the wrong confirmation ▶
  2. P1 Cancel leaves an endless loader ▶

Summary

Fixed payment requests now open on the selected asset's confirmation, support switching between bitcoin and USDT, and refresh expired USDT fee quotes in place.

  • Fixed Paykit requests open on confirmation for their selected asset.
  • USDT review stays on confirmation while quotes load or refresh.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    Request[Fixed payment request] --> Bind{Bind selected asset terms}
    Bind -->|Cannot bind| Amount[Amount]
    Bind -->|Bitcoin| BTC[Bitcoin confirmation]
    Bind -->|USDT| USDT[USDT review]
    BTC -->|Pay From: bind USDT| USDT
    USDT -->|Pay From: bind bitcoin| BTC
    USDT -->|Fee quote expired| Quote[Get replacement quote]
    Quote --> USDT
Loading

Reviews (1) · Last reviewed commit: "fix: keep fixed paykit requests on confi..." · Reviewed by Greptile

Comment thread app/src/main/java/to/bitkit/ui/sheets/SendSheet.kt
@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Regtest APK

Built from 17e1b0c (run).

Download bitkit-dev-debug universal APK (expires in 30 days).

@ovitrif

ovitrif commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator Author

Pushed a89d712: the automatic requote on an expired USDT fee now runs once per swipe instead of retrying without limit.

  • Answers the Codex finding on PaykitUsdtReview.kt, a requote loop when replacement quotes also expire.
  • A second expiry leaves the review on the expired error for the user's own retry; swiping again re-arms the requote.
  • New UsdtViewModelTest case for the repeat expiry; the USDT view model tests and detekt pass.

The two Greptile findings are being fixed next: Back after an asset switch and Cancel on the payment warning.

@ovitrif

ovitrif commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator Author

Pushed 14740ca: switching asset on a payment request now replaces the confirmation, and cancelling the payment warning keeps the reviewed quote.

  • Answers the Greptile finding Back restores the wrong confirmation: ShowPaykitConfirmation navigates with popUpTo the other asset's confirmation, so Back never lands on stale terms.
  • Answers the Greptile finding Cancel leaves an endless loader: the warning's Cancel calls dismissWarning(), which keeps the quote instead of resetting the review to its loading state.
  • New UsdtViewModelTest case for the cancel path; the USDT and send-flow unit tests and detekt pass, and the instrumented tests compile. The description is updated.

@talosmachina talosmachina left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

2 findings (2 P1). Keeps a fixed Paykit request on the confirmation of its preselected asset, adds a bitcoin/USDT switch on Pay From, a USDT loading confirmation and in-place requote of an expired quote. Reviewed 1568abb, full tier, reasoned from the code: per the repo's Bitkit rules the branch was not built here.

What I checked, and 4 candidates I ruled out

Read in full: PaykitUsdtReview.kt, UsdtViewModel.kt, the changed paths of UsdtSendContent.kt, SendSheet.kt and AppViewModel.kt (openPaykitEndpoints, openPaykitRequestConfirmation, bindUsdtRequestTerms, switchPaykitRequestAsset, onPaymentMethodSwitch, reviewPaykitAmount, onConfirmPay/proceedWithPayment, paymentProofPreparation, sendPaykitUsdt)
Call sites traced: SendEvent.PaymentMethodSwitch (Confirm and USDT review), SendEffect.ShowPaykitConfirmation, UsdtViewModel.edit/requote
CI: build-local green; build, lint, e2e and Greptile still pending at review time

Ruled out

  • Requote loop on a second expiry: requote only runs on usdt__error_expired with no quote, and a successful requote replaces the error with the notice, so it cannot spin.
  • Subscription periods routed to the new confirm: openPaykitRequestConfirmation returns early for billingPeriod != null with a USDT option.
  • USDT shown in fundingOptions with USDT disabled: availableFundingSources adds USDT only with a usdtRecipient, which openPaykitEndpoints sets only when USDT is enabled or a binding exists.
  • Cold reader: the stuck-loading finding stood (it rated it P2; I kept P1 because the screen has no way forward). The back-stack finding got no answer because the reader timed out, so that doubt stands.

Merge confidence: 2/5, two P1s on the new confirm paths.

Comment thread app/src/main/java/to/bitkit/ui/sheets/SendSheet.kt

@jvsena42 jvsena42 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Code scan at 14740ca: one LOW, inline with a failing test. Nothing above LOW. Reviewed as a funds change.

Checked and clean (amount, fee, PIN):

  • Terms bound early: they are bound before the review opens.
  • Rechecked before paying: validateQuote and authorizeUsdtExecution check the amount, terms, quote and validity again before executing. A switch during a send clears the reviewed amount, so the payment throws instead of going out.
  • Requote limits: a requote happens at most once per swipe. It resets the confirmed warnings and the PIN state, so both are asked again, and it never sends on its own.
  • Back can't reach stale terms: popUpTo replaces the other asset's confirmation.
  • Subscriptions: periods paid in USDT keep the Amount step.

Parity: iOS synonymdev/bitkit-ios#1014 is still open and keeps the Amount step when a real BTC/USDT choice exists. The PR's Out of Scope already notes the difference.

New UI: the loading state while the USDT quote runs has no Figma frame.

Device gate (partial): 14740ca — not run yet. Pending:

  • BTC/USDT fixed request: it lands on the preselected confirmation, the amount equals the terms, switching works both ways, and Back;
  • quote expiry: swipe, see the notice, warnings and PIN asked again, one payment;
  • Cancel on a warning returns the knob to the start;
  • the chip from the inline finding.

Device results will follow in a separate review.

Comment thread app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt Outdated
@ovitrif

ovitrif commented Oct 21, 2026

Copy link
Copy Markdown
Collaborator Author

Pushed 17e1b0c for @jvsena42's Pay From finding: on a USDT review without a payment request, Pay From stays disabled. Added the reviewer's test; AppViewModelSendFlowTest and detekt pass locally.

@ovitrif
ovitrif requested a review from jvsena42 October 21, 2026 13:01

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants