View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0012104 | Taler | wallet (Android App) | public | 2026-11-11 02:01 | 2026-11-11 02:01 |
| 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 | minor | Reproducibility | have not tried |
| Status | new | Resolution | open | ||
| Summary | 0012104: Android: no warning before confirming a withdrawal that will need KYC or exceeds the exchange's limit (wallet-core's KYC preview ignored) | ||||
| Description | Scenario (same on all three, tripwire KUDOS exchange https://tripwire.taler.net:8445/, KYC above KUDOS 4 cumulated per originating bank account): a first bank-integrated withdrawal of KUDOS 3 completes; a second one of KUDOS 3 from the same bank account is opened in the wallet. What the user sees on the confirmation screen of the second withdrawal: - WebExtension: "This withdrawal, together with your recent withdrawals, may require identity verification at the exchange." (before-web-1.png). After confirming it does end in identity verification (before-web-2-outcome-kyc.png). - Android: amount and "Confirm withdrawal", no hint (before-android-1.png); after confirming: "This transaction would exceed a limit set by the payment service..." / "Complete KYC" (before-android-2-outcome-kyc.png). - iOS: amount, payment service and "Confirm Withdrawal", no hint (before-ios-1.png); after confirming: "Pending incoming ... Legitimization required" (before-ios-2-outcome-kyc.png). So on Android and iOS the user authorises the bank transfer first and only then learns that the money is held until they pass KYC. For an amount over the exchange's hard limit the web wallet disables Withdraw with "This withdrawal would exceed the exchange's withdrawal limit..."; Android and iOS let the user confirm. wallet-core already returns the preview in getWithdrawalDetailsForAmount: kycRequired, withdrawalKycStatus ("unknown" | "ok" | "kyc-required" | "hard-limit"), kycSoftLimit, kycHardLimit, balanceKyc (taler-util types-taler-wallet.ts WithdrawalKycPreview / WithdrawalDetailsForAmount; computed in taler-wallet-core withdraw.ts internalGetWithdrawalDetailsForAmount). The account-volume check needs the bank-integrated withdrawal's transactionId in the request, which the web wallet passes (wallet-webui routes/withdrawal-review-model.ts:22-34, used at :71-108; screens/WithdrawalReviewScreen.tsx:99-145). Android code (origin/master 4c483527): wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt:190-217 (WithdrawalDetailsForAmount decodes none of these fields), :421-427 (request without transactionId); withdraw/WithdrawalShowInfo.kt:199-361 (no hint, button not gated). Patch (android-withdraw-kyc-preview.patch): decode kycRequired and withdrawalKycStatus; for bank-integrated withdrawals pass the transactionId in getWithdrawalDetailsForAmount; show a WarningLabel ("This amount may require identity verification at the payment service." / "This withdrawal, together with your recent withdrawals, may require identity verification at the payment service." / for hard-limit "This withdrawal would exceed the payment service's withdrawal limit. Choose a smaller amount or try again later.") and disable "Confirm withdrawal" on hard-limit. Three new English strings (web wording, "payment service" for exchange as elsewhere in the app). The web's "Withdrawal limits could not be checked" note for status "unknown" is deliberately not copied: without a transactionId (manual withdrawals) the status is always "unknown". Verified: :wallet:assembleFdroidSim builds; after-android-1.png shows the hint for the same scenario (third withdrawal from the same account). Assisted by LLM | ||||
| Steps To Reproduce | 1. Withdraw KUDOS 3 from a bank account at https://tripwire.taler.net:8446/ into the wallet (exchange :8445) and let it complete. 2. Start a second KUDOS 3 withdrawal from the same bank account and open it in the wallet. 3. The confirmation screen gives no KYC hint; after confirming, the withdrawal waits for KYC. | ||||
| Tags | No tags attached. | ||||
| Attached Files | android-withdraw-kyc-preview.patch (4,788 bytes)
diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
index f2862adc..3fa5e6f7 100644
--- a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
@@ -214,7 +214,20 @@ data class WithdrawalDetailsForAmount(
* Scope info of the currency withdrawn.
*/
val scopeInfo: ScopeInfo,
-)
+
+ /**
+ * wallet-core's preview: this withdrawal will probably need KYC.
+ */
+ val kycRequired: Boolean? = null,
+
+ /**
+ * wallet-core's preview of the exchange's withdrawal rules for this bank account:
+ * "unknown", "ok", "kyc-required" or "hard-limit".
+ */
+ val withdrawalKycStatus: String? = null,
+) {
+ val exceedsHardLimit: Boolean get() = withdrawalKycStatus == "hard-limit"
+}
@Serializable
data class WithdrawExchangeResponse(
@@ -423,6 +436,10 @@ class WithdrawManager(
WithdrawalDetailsForAmount.serializer(),
progressToken = exchange.exchangeBaseUrl,
) {
+ // lets wallet-core check the bank account's recent withdrawals against the KYC rules
+ _withdrawStatus.value.let { status ->
+ if (status.talerWithdrawUri != null) status.transactionId?.let { put("transactionId", it) }
+ }
put("exchangeBaseUrl", exchange.exchangeBaseUrl)
put("amount", amount.toJSONString())
}.onError { error ->
diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawalShowInfo.kt b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawalShowInfo.kt
index 7bc37929..9ac73b2e 100644
--- a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawalShowInfo.kt
+++ b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawalShowInfo.kt
@@ -272,6 +272,24 @@ fun WithdrawalShowInfo(
)
}
+ status.amountInfo?.let { info ->
+ if (status.status == TosReviewRequired) return@let
+ val kycWarning = when {
+ info.exceedsHardLimit -> R.string.withdraw_kyc_hard_limit
+ info.withdrawalKycStatus == "kyc-required" -> R.string.withdraw_kyc_volume
+ info.kycRequired == true -> R.string.withdraw_kyc_may_be_required
+ else -> null
+ }
+ kycWarning?.let {
+ WarningLabel(
+ label = stringResource(it),
+ modifier = Modifier
+ .padding(16.dp)
+ .fillMaxWidth(),
+ )
+ }
+ }
+
if (exchange != null && selectedAmount.scope !is ScopeInfo.Exchange) {
TransactionInfoComposable(
label = stringResource(R.string.withdraw_exchange),
@@ -341,6 +359,7 @@ fun WithdrawalShowInfo(
modifier = Modifier
.systemBarsPaddingBottom(),
enabled = status.status != Updating
+ && status.amountInfo?.exceedsHardLimit != true
&& (status.isCashAcceptor
|| status.status == TosReviewRequired
|| status.selectedAmount?.isZero() == false),
diff --git a/wallet/src/main/res/values/strings.xml b/wallet/src/main/res/values/strings.xml
index 89750709..06423717 100644
--- a/wallet/src/main/res/values/strings.xml
+++ b/wallet/src/main/res/values/strings.xml
@@ -430,6 +430,9 @@ GNU Taler is immune to many types of fraud such as credit card data theft, phish
<string name="withdraw_manual_step_subject">Copy this code and paste it into the subject/purpose field (or “Message to recipient”) in your banking app or bank website:</string>
<string name="withdraw_restrict_age">Restrict usage to age</string>
<string name="withdraw_restrict_age_unrestricted">Unrestricted</string>
+ <string name="withdraw_kyc_may_be_required">This amount may require identity verification at the payment service.</string>
+ <string name="withdraw_kyc_volume">This withdrawal, together with your recent withdrawals, may require identity verification at the payment service.</string>
+ <string name="withdraw_kyc_hard_limit">This withdrawal would exceed the payment service\'s withdrawal limit. Choose a smaller amount or try again later.</string>
<string name="withdraw_review_terms">You must first accept the payment service\'s terms of service before you can withdraw electronic cash to your wallet.</string>
<string name="withdraw_subtitle">Select target bank account</string>
<string name="withdraw_title">Withdraw</string>
| ||||
| related to | 0012105 | new | iOS: no warning before confirming a withdrawal that will need KYC or exceeds the exchange's limit (wallet-core's KYC preview ignored) |
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2026-11-11 02:01 | bot-cg | New Issue | |
| 2026-11-11 02:01 | bot-cg | File Added: before-web-1.png | |
| 2026-11-11 02:01 | bot-cg | File Added: before-web-2-outcome-kyc.png | |
| 2026-11-11 02:01 | bot-cg | File Added: before-android-1.png | |
| 2026-11-11 02:01 | bot-cg | File Added: before-android-2-outcome-kyc.png | |
| 2026-11-11 02:01 | bot-cg | File Added: before-ios-1.png | |
| 2026-11-11 02:01 | bot-cg | File Added: before-ios-2-outcome-kyc.png | |
| 2026-11-11 02:01 | bot-cg | File Added: after-android-1.png | |
| 2026-11-11 02:01 | bot-cg | File Added: android-withdraw-kyc-preview.patch |