View Issue Details

IDProjectCategoryView StatusLast Update
0011980Talerwallet (iOS App)public2026-11-09 12:40
Reporterbot-cg [agent] Assigned ToResolution deadline
ImplementerReviewer 
Release signed byDeployed by 
VerifierCommunicatorCM_7  
Data protection authority notification requiredNo  
CSIRT notification requiredNo  
Estimated effort (hours)Actual effort (hours)0 
Fast-trackNo
Work packagenone
PrioritynormalSeveritymajorReproducibilityalways
Status newResolutionopen 
Summary0011980: Authorize at Bank: a KYC-gated withdrawal reopened from its URI spins for ever -- wallet-core says why (7046, txState pending/kyc) and the app discards it with `try?`
DescriptionA withdrawal that has gone into `pending/kyc` leaves "Authorize at Bank"
spinning for ever, with no error, no explanation and no way forward --
while wallet-core has already said exactly what is wrong.

The sequence
------------
1. A bank-integrated withdrawal is started and reaches `pending/kyc`
   (the exchange wants a legitimization check).
2. The same `taler://withdraw/` URI is opened again -- the user taps the
   link in their banking app a second time, or the sheet is re-entered.
3. `WithdrawAcceptDone.viewDidLoad()` calls `acceptBankIntWithdrawal`
   unconditionally (`WithdrawAcceptDone.swift:29-45`). It is keyed on the
   URL and never asks whether a transaction for it already exists, or in
   what state.
4. wallet-core refuses, correctly:

       acceptBankIntegratedWithdrawal -> {
         "code": 7046,
         "hint": "Error (WALLET_REQUEST_TRANSACTION_STATE_UNSUPPORTED)",
         "message": "unable to confirm withdrawal in current state",
         "txState": { "major": "pending", "minor": "kyc" }
       }

5. The call site is `if let result = try? await ...`, so the error is
   discarded. `transactionId` stays nil.
6. `body` therefore takes its `else` branch (`:77-82`) and renders
   `LoadingView` -- a spinner -- with `.task { await viewDidLoad() }`
   attached to it, so it tries again and fails again.

The user is left on a screen headed "Authorize at Bank" showing a spinner
that will never resolve. The only control is Cancel. **The reason is in the
error payload the app threw away**: `txState.minor == "kyc"`.

How often
---------
Not a one-off. Three occurrences in one episode of `c2h-9` (e00012) and
again in `c2h-8` (e00008), across two separate two-hour campaign runs --
same fingerprint both times. It reproduces whenever a KYC-gated withdrawal
URI is opened twice.

Why it matters beyond this screen
---------------------------------
This is the same defect as 11914 seen from a third angle, and the worst
version of it so far: there the user had to drill three screens down to
find out what was wanted of them; here they are shown a spinner that
implies the app is working on it. A progress indicator for a state that
will never progress is worse than a blank screen.

Suggested fix
-------------
Two parts, and the first is the important one:

1. **Stop discarding the error.** `try?` at `:31` turns a precise,
   actionable wallet-core verdict into nil. Catch it, and render the
   failure instead of a spinner. (Same anti-pattern as 11975, where
   `Result.orUndefined` dropped a typed error.)
2. **7046 with `txState.minor == "kyc"` is not really an error**: it means
   the withdrawal exists and needs legitimization. The right response is to
   show that transaction -- which already renders the "Open legitimization
   website" button -- rather than to report a failure.

I have a patch for part 1 and will attach it once it is built; I would
rather not attach an unbuilt one. Part 2 needs the transaction id, which
the 7046 payload does not carry, so it needs either a lookup by URI or an
addition to the error -- a design call rather than a patch.

Found by the fuzzing harness; `runs/c2h-9/findings.json`, fingerprint
`f8b681cdce3c`.
TagsNo tags attached.

Required notifications

Address or linkRemarkAdded byNotifiedActions

Activities

There are no notes attached to this issue.

Issue History

Date ModifiedUsernameFieldChange
2026-11-09 12:40bot-cgNew Issue