commit 9075c508a4de3d8d25d7629d2c6ad6b6be19b111
parent b61c9c1bebc7db7b3d9a06a7e847e8e7277f367f
Author: Marc Stibane <marc@taler.net>
Date: Fri, 14 Aug 2026 19:51:23 +0200
AI: fix unsufficient
Diffstat:
2 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/TalerWallet1/Views/Actions/Peer2peer/SendAmountView.swift b/TalerWallet1/Views/Actions/Peer2peer/SendAmountView.swift
@@ -108,6 +108,11 @@ struct SendAmountView: View {
switch walletError {
case .walletCoreError(let wError):
if wError?.code == 7027 {
+ if let details = wError?.insufficientBalanceDetails {
+ symLog.log(details.causeHint?.localizedCause(amount.currencyStr))
+ }
+ // TODO: [10.2] AmountInputV ignores the insufficient flag,
+ // so neither this verdict nor its localized cause is shown
return ComputeFeeResult.insufficient()
}
default: break
@@ -126,7 +131,7 @@ struct SendAmountView: View {
if let available = try? await model.getMaxPeerPushDebitAmount(scope, viewHandles: true) {
amountAvailable = available
} else {
- amountAvailable = Amount.zero(currency: scope.currency)
+ amountAvailable = balance.available
}
}
diff --git a/TalerWallet1/Views/HelperViews/AmountInputV.swift b/TalerWallet1/Views/HelperViews/AmountInputV.swift
@@ -55,6 +55,7 @@ struct AmountInputV: View {
@State private var feeAmount: Amount? = nil
@State private var feeStr = (EMPTYSTRING, EMPTYSTRING)
@State private var numCoins: Int?
+ @State private var coreInsufficient: Bool = false // wallet-core's own verdict
struct Flags {
let insufficient: Bool
@@ -63,6 +64,12 @@ struct AmountInputV: View {
func checkAvailable(_ coinData: CoinData) -> Flags {
let isZero = amountToTransfer.isZero
+ // wallet-core's verdict is authoritative and comes first: it accounts for fees,
+ // age restrictions, per-exchange limits and pending refreshes, none of which a
+ // local `amountToTransfer > amountAvailable` can see.
+ if coreInsufficient {
+ return Flags(insufficient: true, disabled: true)
+ }
if !amountAvailable.isZero {
do {
let insufficient: Bool
@@ -82,7 +89,11 @@ struct AmountInputV: View {
symLog.log("❗️Cannot compare amountAvailable.\(amountAvailable.currencyStr) to amountToTransfer.\(amountToTransfer.currencyStr))")
}
}
- return Flags(insufficient: false, disabled: isZero)
+ // No usable local bound (an incoming amount, or a caller that never sets
+ // amountAvailable — see PayTemplateScan.swift:36). Deliberately NOT failing closed
+ // here: those callers still get the wallet-core verdict above, and failing closed
+ // would permanently disable a pay-template that has no availability to compare to.
+ return Flags(insufficient: false, disabled: isZero || coinData.invalid || coinData.tooMany)
}
var body: some View {
@@ -119,10 +130,12 @@ struct AmountInputV: View {
if let result: ComputeFeeResult = await computeFee(amountToTransfer) {
symLog.log("computeFee() finished")
feeStr = result.feeStr
-// insufficient = result.insufficient // TODO: insufficient
+ coreInsufficient = result.insufficient
feeAmount = result.feeAmount
numCoins = result.numCoins
} else {
+ // No verdict this round - keep the previous one rather than silently
+ // treating an unanswered question as "you can afford it".
symLog.log("computeFee() failed ❗️") // \(error)")
}
}