View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0012065 | Taler | wallet (iOS App) | public | 2026-11-11 01:20 | 2026-11-11 01:20 |
| Reporter | bot-cg [agent] | Assigned To | Resolution deadline | ||
| Implementer | Reviewer | ||||
| Release signed by | Deployed by | ||||
| Verifier | Communicator | CM_7 | |||
| Data protection authority notification required | No | ||||
| CSIRT notification required | No | ||||
| Estimated effort (hours) | Actual effort (hours) | 0 | |||
| Fast-track | No | ||||
| Work package | none | ||||
| Priority | normal | Severity | major | Reproducibility | have not tried |
| Status | new | Resolution | open | ||
| Summary | 0012065: iOS: bank-integrated withdrawal on a fresh wallet skips the ToS step; "Confirm Withdrawal" then fails with WALLET_EXCHANGE_TOS_NOT_ACCEPTED (stale exchange cache) | ||||
| Description | On a fresh wallet, a bank-integrated withdrawal (taler://withdraw/...) goes straight to "Confirm Withdrawal" without asking for the exchange's terms of service. Confirming then fails with "Internal core error / Error (WALLET_EXCHANGE_TOS_NOT_ACCEPTED)" and the withdrawal cannot continue from that screen. What the user sees (same URI from bank.demo.taler.net, fresh wallets, origin/master builds of 2026-11-11): - Android: amount and a "Terms of Service" button (before-android-1.png). - WebExtension: "Review and accept this exchange's terms of service before withdrawing." with "Review terms"; Withdraw is disabled (before-web-1.png). - iOS: amounts and "Confirm Withdrawal", no ToS step (before-ios-1.png). Tapping it: "Internal core error / Error (WALLET_EXCHANGE_TOS_NOT_ACCEPTED)" (before-ios-2.png). The same happens for an exchange that is not built in (tripwire.taler.net:8445, KUDOS): before-ios-3.png, before-ios-4.png. It is a race: in our runs it happened 3 times out of 3 on fresh wallets; the first run after a simulator/driver restart showed the ToS step (before-ios-0-race.png). Cause: - wallet-core reports tosStatus "missing-tos" for an exchange whose terms it has not downloaded yet (tosCurrentEtag == null; taler-wallet-core/src/common.ts:353-366). That is the state of a built-in or newly discovered exchange before its first update. - prepareBankIntegratedWithdrawal updates the bank's exchange (terms now known: "proposed") and emits ExchangeStateTransition notifications on the way. iOS handles each with Controller.updateExchange(for:state:) (Backend/WalletCore.swift:401-406, Controllers/Controller.swift:566-588), which calls exchange(for:); on a cache miss that fetches the entry and caches it (Controller.swift:543-556), possibly while it still says missing-tos. - WithdrawUriScan.viewDidLoad then takes the exchange from that cache via controller.checkCurrencyInfo(for:) (Views/Sheets/WithdrawBankIntegrated/WithdrawUriScan.swift:130-132; Controller.swift:599-611). If the later notification has not replaced the record yet, the stale missing-tos entry goes to WithdrawAcceptView, whose gate treats missingTos as "nothing to accept" (WithdrawAcceptView.swift:63-71, 119-132), so "Confirm Withdrawal" is offered and acceptBankIntegratedWithdrawal answers 7037. - Android asks wallet-core again after prepare (withdraw/WithdrawManager.kt:381-404 findExchangeByUrl -> getExchangeEntryByUrl, then TosReviewRequired at :434-438); the WebExtension gates on a live ListExchanges query (routes/App.tsx:3564-3568, routes/withdrawal-review-model.ts:54-65). This is the "second defect" suspected in the 2026-11-10 note on 0011934 (cached exchange record disagreeing with wallet-core). That note's patch (offer the ToS when 7037 arrives anyway) is complementary; this one prevents the wrong screen. Patch (ios-bank-withdrawal-tos.patch, against origin/master 674b7915): in WithdrawUriScan.viewDidLoad, keep checkCurrencyInfo (for the currency info) but use wallet-core's current entry, model.getExchangeByUrl(url:viewHandles:true), falling back to the cached one. One statement plus a comment. Verified: GNU_Taler Release build for the simulator (iOS 27.2); three fresh runs against the demo bank all showed the ToS step (after-ios-1.png); after accepting, "Confirm Withdrawal" (after-ios-2.png) leads to "Authorize at Bank" (after-ios-3.png). Same against tripwire :8445 (after-ios-4.png, after-ios-5.png, confirm -> "Authorize at Bank"). Side observation, not part of this report: on tripwire :8445 the confirm screen shows no amounts at all (before-ios-3.png, after-ios-5.png). Assisted by LLM | ||||
| Steps To Reproduce | 1. Fresh install / empty wallet. 2. Start a withdrawal on https://bank.demo.taler.net/ (any amount) and open the taler://withdraw/... link in the app. 3. Observe "Confirm Withdrawal" without a "Terms of Service" step; tap it. 4. "Internal core error / Error (WALLET_EXCHANGE_TOS_NOT_ACCEPTED)". (Automated: wc-stack withdraw-uri --amount KUDOS:5; wc-ios start --fresh; wc-ios uri <uri>.) | ||||
| Tags | No tags attached. | ||||
| Attached Files | ios-bank-withdrawal-tos.patch (1,225 bytes)
diff --git a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawUriScan.swift b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawUriScan.swift
index 559dad2a..fa3ebc7a 100755
--- a/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawUriScan.swift
+++ b/TalerWallet1/Views/Sheets/WithdrawBankIntegrated/WithdrawUriScan.swift
@@ -129,7 +129,11 @@ struct WithdrawUriScan: View {
if let baseUrl, let someExchange = try? await controller.checkCurrencyInfo(for: baseUrl) {
symLog.log("Info(for: \(baseUrl.trimURL) loaded")
- exchange = someExchange
+ // checkCurrencyInfo answers from the Controller's exchange cache, which can predate the
+ // exchange update prepareBankIntegratedWithdrawal just did: a built-in exchange whose ToS
+ // were never downloaded is listed as "missing-tos", and WithdrawAcceptView would then offer
+ // "Confirm Withdrawal" without the ToS step. Use wallet-core's current entry instead.
+ exchange = (try? await model.getExchangeByUrl(url: baseUrl, viewHandles: true)) ?? someExchange
} else {
exchangeError = true
}
| ||||
| related to | 0011934 | reviewing | Withdraw / Loading: expected wallet-core errors are titled "Internal core error" (e.g. 7054 withdrawal limit exceeded), with raw JSON as the body |
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2026-11-11 01:20 | bot-cg | New Issue | |
| 2026-11-11 01:20 | bot-cg | Relationship added | related to 0011934 |
| 2026-11-11 01:20 | bot-cg | File Added: before-android-1.png | |
| 2026-11-11 01:20 | bot-cg | File Added: before-web-1.png | |
| 2026-11-11 01:20 | bot-cg | File Added: before-ios-0-race.png | |
| 2026-11-11 01:20 | bot-cg | File Added: before-ios-1.png | |
| 2026-11-11 01:20 | bot-cg | File Added: before-ios-2.png | |
| 2026-11-11 01:20 | bot-cg | File Added: before-ios-3.png | |
| 2026-11-11 01:20 | bot-cg | File Added: before-ios-4.png | |
| 2026-11-11 01:20 | bot-cg | File Added: after-ios-1.png | |
| 2026-11-11 01:20 | bot-cg | File Added: after-ios-2.png | |
| 2026-11-11 01:20 | bot-cg | File Added: after-ios-3.png | |
| 2026-11-11 01:20 | bot-cg | File Added: after-ios-4.png | |
| 2026-11-11 01:20 | bot-cg | File Added: after-ios-5.png | |
| 2026-11-11 01:20 | bot-cg | File Added: ios-bank-withdrawal-tos.patch |