View Issue Details

IDProjectCategoryView StatusLast Update
0011983Talerwallet (iOS App)public2026-11-09 20:13
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
PrioritynormalSeverityminorReproducibilityhave not tried
Status newResolutionopen 
Summary0011983: Deposit: nothing bounds how long "Depositing..." waits -- the wallet-core channel has no deadline, and Abort dismisses the screen without cancelling
DescriptionNothing on the deposit path bounds how long the app will wait for
wallet-core. If the answer never comes, "Depositing..." spins for as long
as the user is prepared to look at it, and the one control on the screen
does not cancel anything.

**There is no deadline anywhere on the path.**

* `DepositAmountAction.startDeposit` (TalerWallet1/Views/Actions/Banking/
  DepositAmountAction.swift:78-93) sets `depositStarted = true` and awaits
  `model.createDepositGroup(...)` in a `Task` with no timeout.
* `WalletModel.sendRequest` (TalerWallet1/Model/WalletModel.swift:189-211)
  awaits and rethrows; it has no timeout.
* `WalletCore.sendFormattedRequest` (TalerWallet1/Backend/
  WalletCore.swift:626-629) is a bare
  `withCheckedThrowingContinuation`. If wallet-core never calls back, the
  continuation is never resumed and the `await` never returns. There is no
  deadline in the channel at all, for any operation.

**And `createDepositGroup` really does wait on the network.** In
wallet-core it calls `getExchangesForDeposit`
(taler-wallet-core/src/deposits.ts, inside `createDepositGroup`), so an
exchange that does not answer is enough to produce the state above.

**What the user is left with.** While `depositStarted` is true the view is
a `LoadingView("Depositing...")` with `navigationBarBackButtonHidden(true)`
and `interactiveDismissDisabled()` -- the back gesture and the back button
are both gone on purpose -- and a single "Abort" button whose action is
`dismissTop(stack.push())` (:109-118). That dismisses the screen. It does
not cancel the `Task`, does not cancel the wallet-core request, and says
nothing about what happened to the deposit. So the choices are: wait with
no stated limit, or leave with no answer.

**This is about a non-answer, not a swallowed error.** An error *does*
surface here: `createDepositGroup` is called with the default
`viewHandles: false`, so `sendRequest`'s catch calls `setError`
(WalletModel.swift:174-180) and the user gets an alert. That is the
difference from 11980, where wallet-core answered 7046 and the view
discarded it with `try?`. Here the complaint is the case wallet-core never
answers, which no amount of error handling reaches.

**Why 30 s is the right order of magnitude.** The exchange round trips
inside a deposit are the same ones a withdrawal makes, and on the harness's
own deployment a full bank-integrated withdrawal reaches `Done` in about
30 s end to end, of which 30 s is one deliberate `timeout_ms=30000` long
poll on `/reserves`. A deposit that has not answered in 30 s is not a slow
network.

**Not deposit-specific.** The missing deadline is in the shared channel,
so every operation inherits it. Deposit is where it shows worst because
this screen deliberately removes the exits; `withdraw` and the P2P screens
reach the same continuation.
Steps To Reproduce1. Fund a wallet (empty-wallet screen -> "Get demo cash", KUDOS 25) and add
   a bank account (Settings -> Bank Accounts -> +, any valid IBAN).
2. Make wallet-core's responses disappear, using the app's own dev
   experiment facility -- no proxy needed:

       xcrun simctl openurl booted \
         'taler://dev-experiment/start-tc?drop_resp=1'

3. Actions -> Deposit -> the account -> enter an amount -> "Deposit <amount>".

Observed: "Depositing..." with no back button, no swipe-to-dismiss and an
"Abort" button. It stays. Abort returns to the previous screen without
cancelling the operation or saying what became of it.

Expected: a deadline -- some tens of seconds -- after which the screen says
the deposit could not be confirmed and offers a retry; and an Abort that
cancels rather than just hides.

Found while measuring the harness's deterministic `deposit` scenario, whose
step budget for this tap was 240 s. That budget is now 30 s, and a new
scenario `deposit-no-response` performs exactly the three steps above and
asserts that something appears within it.
Additional InformationSuggested shape, smallest first:

1. A deadline at the call site, which needs no change to the channel:

       let result = try await withThrowingTaskGroup(of: DepositGroupResult?.self) { g in
           g.addTask { try await model.createDepositGroup(...) }
           g.addTask { try? await Task.sleep(nanoseconds: 30_000_000_000); return nil }
           let first = try await g.next()
           g.cancelAll()
           return first ?? nil
       }

   with `nil` rendered as "the deposit could not be confirmed" plus a retry.

2. Better, because every screen inherits it: a timeout in
   `WalletCore.sendFormattedRequest`, resuming the continuation with a
   timeout error when wallet-core has not answered within some per-operation
   budget. The budget cannot be one number for every operation -- a
   withdrawal's own long poll is 30 s by design -- so it would have to be a
   property of the request type.

3. Separately, "Abort" should cancel. It currently calls `dismissTop`, so
   the `Task` and the wallet-core operation both continue behind a screen
   the user has left.

Related: 11980 (same flow family, but there wallet-core answered and the
view dropped the answer), 11937 (loading states shown for operations that
finish in 21-50 ms -- the same `LoadingView`, the opposite end of the same
missing policy).
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 20:13bot-cgNew Issue