Skip to content

fix: correct usdt request and bridge feedback - #948

Open
ben-kaufman wants to merge 5 commits into
masterfrom
fix/usdt-payment-state-20261015
Open

ben-kaufman wants to merge 5 commits into
masterfrom
fix/usdt-payment-state-20261015

Conversation

@ben-kaufman

@ben-kaufman ben-kaufman commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Closes #949

Addresses the iOS equivalents of synonymdev/bitkit-android#1503 and synonymdev/bitkit-android#1504.

This PR corrects USDT request preparation styling and bridge status messages. Paired Android fixes: synonymdev/bitkit-android#1506.

Description

  • Use the USDT amount title for Paykit USDT sends, including localized screens, matching direct USDT Send.
  • Use USDT teal while preparing a USDT-only request and a neutral accent before a mixed request's method is selected.
  • Replace raw provider error codes in deposit details with existing localized support guidance; preserve technical values beside the readable status in copied diagnostics.
  • Keep the shared journeys aligned, including the valid fee-collection error observed when entering the full balance.

Out of Scope

  • Payment guard and receive-queue behavior already cover Android #1498 and #1502 on iOS; no production changes were needed for those paths.

Design

Payment requests · Bridge technical details

Preview

QA Notes

Journeys

  • J1 updated paykit-quoted-usdt.xml — USDT-only request preparation stays teal, opens Amount without an intermediate Bitcoin confirmation, and cannot submit before review; denomination switches restore the entered amount, with identical BTC equivalents expected only at an unchanged rate. USDT amount titles match direct Send, including in German; the smaller BTC figure is a wallet-rate equivalent. Changing Savings/Spending returns to Amount; its Back arrow closes the request instead of revisiting confirmation.
  • J2 updated usdt-bridge-details.xml — a receipt arriving during deposit details appears once after returning to the wallet.
  • J3 updated usdt-bridge-support.xml — bridge problems use readable messages; copied diagnostics retain readable and technical status.
  • J4 updated usdt-payment-links-and-scans.xml — full-balance preparation accepts either actionable fee or balance error without opening review.

Manual Tests

N/A

Automated Checks

  • added coverage in PaykitPaymentRequestServiceTests.swift — preparing USDT-only and mixed requests use their appropriate accent before wallet selection.
  • updated UsdtSupportDetailsTests.swift — copied transfer and deposit diagnostics include the readable status beside the technical value.
  • ran focused PaykitPaymentActivityTests.swift, UsdtWalletManagerTests.swift and SendConfirmationViewTests.swift coverage — existing payment ownership and deferred receipt behavior remain correct.

21 focused simulator tests passed for the initial fixes, including the preparation test. The follow-up amount-title correction passes Swift formatting, syntax, translation and XML checks. Its local focused simulator run was blocked before tests by missing dependency XCFrameworks; CI unit tests, integration tests, build and E2E passed at a08e4c1. The paired journey-only follow-up passes XML parsing and cross-platform parity checks. No funded mainnet payments were needed; the changed journeys remain listed for reviewer device verification.

@greptile-apps

greptile-apps Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] This PR appears safe to merge; no actionable issues were found.

Summary

This PR corrects request preparation colors and makes bridge status messages easier to read.

  • USDT payment requests use the right color while they prepare.
  • Bridge details pair readable support guidance with technical statuses.
  • USDT journey notes cover full-balance errors and repeat receipts.

No actionable issues found. Simulator tests and visual checks were not run in this Linux environment.

Reviews (1) · Last reviewed commit: "fix: correct usdt request and bridge fee..." · Reviewed by Greptile

ovi-reviewer[bot]

This comment was marked as outdated.

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

No findings. Uses USDT teal (or a neutral accent for a mixed request) while a payment request is being prepared, swaps the raw provider code in deposit details for the localized support note, and puts the readable status beside the technical one in copied diagnostics. Reviewed 5959c7a, full tier.

What I checked, and 4 candidates I ruled out

Read in full: the diff of SendConfirmationView.swift, UsdtDepositHistoryView.swift (the detail view and depositStatusText), UsdtSupportActions.swift, both test files
Call sites traced: accentColor, UsdtDepositDetail.statusText, statusCode, acceptedPaymentEndpointIdentifiers
CI: Run Tests still running at review time; Greptile green. Not built here: iOS does not build on Linux, so Run Tests is the gate for the new testPreparationUsesAcceptedMethodsBeforeWalletSelection.

Ruled out

  • Accent precedence: the new preparingRequest branch sits above hwSend.isActive, but the confirm actions are disabled while preparing (.disabled(preparingRequest != nil)), so no hardware or Lightning state can be live behind it.
  • Mixed-request match: Set(...) == [usdtArbitrum] is the same USDT-only test SubscriptionsView already uses, and the Set form also tolerates a duplicated identifier.
  • Attention note vs. status: statusText comes from depositStatusText, which returns usdt__deposit_needs_attention for every coded or unknown status, so the string comparison shows the note exactly when the status cell says "Needs attention". The code itself is still in the copied diagnostics (Status code: line).
  • Diagnostics regression: the raw status values stay in parentheses, and the updated tests assert both forms for a transfer and a deposit.

Merge confidence: 4/5, not built here and Run Tests had not finished when I looked.

Base automatically changed from feat/usdt-design-followup-20261015 to master October 15, 2026 21:57
ovi-reviewer[bot]

This comment was marked as outdated.

@ovi-reviewer

This comment has been minimized.

@ben-kaufman

Copy link
Copy Markdown
Contributor Author

Checked J1 on both platforms. The draft editor preserves the entered 10 USD and uses the current BTC/USD rate for each conversion. With controlled rates of 82,380 then 82,445 USD/BTC, both implementations produce 12,139 then 12,130 sats while returning to exactly 10 USD. Repeated switches at an unchanged rate keep the same satoshi amount. The conversion implementations are unchanged from master.

The journey expectation was too strict across a rate refresh. Corrected it and the paired README in f2e30b8 and synonymdev/bitkit-android#1506 (05482004d). No pricing behavior changed. Controlled-rate checks, Android amount tests, XML validation and platform formatting/lint checks passed; no new diagnostics. J2–J4 still require the fixtures/funding listed in your report.

@ovi-reviewer ovi-reviewer 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.

Suggestion: 👍 Approve

Reaudit: diff 2 files.
No new findings; the rest is in the review.
Twin: synonymdev/bitkit-android#1506 identical at 0548200

QA:
Tests running.
Test J1 failed at 5959c7a.
J2 not tested because the supplied USDT fixture is not provisioned; missing: controlled bridge history and receipt injection.
J3 not tested because it needs prepared bridge transfer and deposit history; missing: a working USDT provider fixture.
J4 not tested because the configured USDT service cannot be resolved and the isolated fixture is not provisioned; missing: USDT quotes and controlled full-balance state.

Replies:

@ben-kaufman: Checked J1 on both platforms. (comment)

@ben-kaufman I confirmed that the original USD amount is retained while the BTC equivalent uses the current rate. This clarifies the earlier J1 concern; the revised journey matches that behavior.


Reviewed by gpt-6.1-sol-medium via gh-pr-review-loop skill
Commands: @ovi-reviewer review · test · retest

Copy link
Copy Markdown
Contributor Author

Re J1: I checked the request routing on both iOS and Android. Both filter the resolved endpoints to the request’s accepted methods. With only USDT accepted, the selection logic chooses USDT even with zero USDT balance. A USD-denominated request that also accepts Bitcoin can initially select Bitcoin when the USDT balance cannot cover it.

I couldn’t establish the accepted methods or the exact incoming-request opening step from the recording. Could you include the request’s acceptedPaymentEndpointIdentifiers, its amount asset/conversion terms, whether USDT was enabled on the payer, and the steps from sending the request to opening it? Please omit keys and credentials. That will let us distinguish a routing defect from a mixed-method request or the request-creation amount editor. Existing selection tests pass, but that does not rule out a different UI path.

@ovi-reviewer

ovi-reviewer Bot commented Oct 15, 2026

Copy link
Copy Markdown

@ben-kaufman From the run at 5959c7a:

  • acceptedPaymentEndpointIdentifiers: not captured. The run recorded the UI steps and the device log, not the request payload, and the log does not print the accepted methods.
  • Amount: a USD request for 150,50 on the de_DE locale, made by journey action 8: deselect every receiving choice, select only USDT, enter 150,50 USD, pick an expiry, send. That step passed. No conversion terms were captured.
  • USDT on the payer: enabled through the intro sheet (action 1) on both wallets. Both wallets held 0 BTC and 0 USDT.
  • Opening: the payer's incoming request card and details showed 150,50 USD, and Pay in the details opened the Amount screen.

On that screen USDT was the only funding source offered, which matches your routing check. What failed is the screen itself: it was titled "Bitcoin Betrag" and showed a Bitcoin amount next to the dollar amount for a USDT-only request. So J1 points at the Amount screen's labels for a USDT-only request, not at routing.

J1.2x.mp4

@ovi-reviewer ovi-reviewer 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.

Verdict: ✅ All 5 device cases passed at f2e30b8; one LOW outside this change.

QA for f2e30b8:

Tested on two iOS 26.5 simulators (iPhone 17 Pro), regtest, with USDT on the bitkit-docker USDT fixture (local Arbitrum fork with simulated Orchestra and LayerZero).

✅ Test 1: J1 USDT-only request preparation and denomination switches

A 10 USD request accepting only USDT opened on the payer as Preparing with teal icons and a disabled teal swipe, then a locked Amount screen with USDT as the only source; Back closed it without a Bitcoin confirmation, reopening kept $10 and USDT, and on the requester 10 USD came back exactly after every BTC/USD switch (12,143 sats, then 12,145 after a rate refresh), consistent with @ben-kaufman's rate check.

case1-j1-requester-payer-2x.2x.mp4

✅ Test 2: J2 receipt during deposit details

A USDT transfer arriving while deposit details were open showed no sheet over them, celebrated once on return to the USDT wallet, and did not repeat after revisiting deposit details and waiting 105 s on the wallet.

case2-j2-2x.2x.mp4

✅ Test 3: J3 readable bridge messages and copied diagnostics

Deposits held with standing_route_unavailable or in provider_review showed Needs attention with the readable support note and no raw code, Copy Details gave Status: Needs attention (held) plus the code line, and an Orchestra transfer in attention copied Status: Bridge needs attention (bridgeNeedsAttention) with its references; both support forms opened prefilled and unsent.

case3-j3-2x.2x.mp4

✅ Test 4: J4 full-balance USDT send

Sending the whole 25 USDT balance to another owned wallet showed "Unable to pay the transaction fee in USDT. Try a smaller amount." with review closed, and 5 USDT reached review, closed without signing.

case4-j4-2x.2x.mp4

✅ Test 5: mixed Bitcoin and USDT request preparation

A USD request accepting Savings and USDT prepared in the neutral grey accent, neither orange nor teal, then opened on Savings with USDT still offered as a funding source.

case5-mixed-requester-payer-2x.2x.mp4

Findings:

  • LOW: in German, the Amount screen of a USDT-only request is titled "Bitcoin Betrag". SendAmountView uses wallet__send_amount, which is "Amount" in English but "Bitcoin Betrag" in de.lproj, while direct USDT Send uses usdt__amount. Routing offered only USDT, and the ₿ line above the dollar amount is the same secondary display direct USDT Send shows, so this is the label behind the earlier J1 report, not a routing defect. This PR does not change that string.

    case1-j1-payer-de-2x.2x.mp4

Copy link
Copy Markdown
Contributor Author

Thanks, that clarification identified the issue. Fixed in 9d04405: the Paykit USDT amount screen reused wallet__send_amount, whose German translation is “Bitcoin Betrag”. It now uses the existing usdt__amount title, matching direct USDT Send and Android. Until translated, this uses the existing English “Amount” fallback.

The smaller BTC figure stays: it is the wallet-rate equivalent in the shared USDT amount header, not a Bitcoin funding option. The paired journey now checks the title in German and makes that distinction explicit. Android already had the correct title, so #1506 only receives the matching journey clarification.

Swift formatting, syntax, translation validation and paired XML checks passed, with no new diagnostics. Independent review found no further issue. The local focused simulator run was blocked before tests by missing cached dependency XCFrameworks, including after attempting cache recovery. Previous-head unit/integration CI passed; updated-head CI is starting. The provider-dependent J2–J4 checks remain blocked by the reported fixture setup.

@ovi-reviewer

ovi-reviewer Bot commented Oct 16, 2026

Copy link
Copy Markdown

@ben-kaufman J2, J3 and J4 are no longer blocked: all five cases passed on device at f2e30b8 against the USDT fixture, with recordings in the test results. Its one LOW, the German "Bitcoin Betrag" title, is the label 9d04405 fixes; that review went up seconds after your push, so it predates the fix.

@ovi-reviewer ovi-reviewer 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.

Verdict: ✅ Approve: no findings in the delta, and both cases it reaches passed at a08e4c1.

The PR moved to 37749e5 after this run; these results are for a08e4c1.

Findings: none. In 9d04405 the Amount title reads the same app.paykitUsesUsdt flag as the rest of the USDT layout, flips back in selectFundingSource and is cleared by resetSendState, so a Bitcoin send does not inherit the USDT title. The other screens of a Paykit USDT payment use neutral strings.

QA for a08e4c1:

Tested on two iOS 26.5 simulators (iPhone 17 Pro), regtest, with USDT on the bitkit-docker USDT fixture.

Test 1: J1 USDT-only request Amount screen ✅ Titled "Amount" in English and German, reached straight from Preparing.

A 10 USD request accepting only USDT came back to exactly 10 USD after four BTC/USD switches on the requester, at 12,232 sats each time. On the payer it showed Preparing with teal icons and a spinning teal swipe knob, then Amount with USDT the only source, $10 locked (its keypad keys are not tap targets) and ₿ 12,197 as the rate line. In every recorded frame of the three openings, the last Preparing frame is followed directly by Amount: no Bitcoin confirmation, zero BTC or enabled swipe in between. Back closed the sheet to Home, and reopening kept $10 and USDT. With the payer in German the screen read "Amount" and "VERFÜGBAR", the same title direct USDT Send shows in German.

case1-j1-requester-payer-2x.2x.mp4

Test 2: mixed request and plain contact send ✅ Neutral preparing accent; the title follows the selected source.

In German, a 10 USD request accepting Savings and USDT prepared with a grey knob and grey icons, then opened Amount on Sparkonto titled "Bitcoin Betrag" (₿ 12,166). Selecting USDT changed it to "Amount" with the USDT layout ($10), and selecting Sparkonto again restored "Bitcoin Betrag" with ₿ 12,166. A plain Pay to the contact opened on USDT as "Amount", read "Bitcoin Betrag" on Sparkonto and "Amount" again on USDT. Closed without paying.

case2-mixed-and-contact-requester-payer-2x.2x.mp4

Not repeated, passed at f2e30b8 in the test results, whose code no later commit touches:

  • J2 receipt during deposit details.
  • J3 readable bridge messages and copied diagnostics.
  • J4 full-balance USDT send: the fee-collection error it showed still meets the widened journey in a08e4c1.

Covered: the delta f2e30b8..a08e4c1. The wording changes in journeys/README.md, journeys/usdt-payment-links-and-scans.xml and the changelog had no device case. 37749e5, pushed during this run, changes only journeys/paykit-quoted-usdt.xml and is not covered here.

Twin: synonymdev/bitkit-android#1506 has identical journey lines at fec209b. It also replaces the prepared route atomically for the same "Preparing changes directly to Amount" check; iOS meets that check without a code change (Test 1).

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.

bug: usdt request and bridge screens show bitcoin styling and raw codes

2 participants