commit c164ffa9fde655f845787c7c6622f36a830cd20e
parent 20b8855efedcbe4b5544b36576b306247fd89158
Author: Florian Dold <dold@taler.net>
Date: Thu, 23 Jul 2026 01:00:54 +0200
wallet: retry and cancel withdrawal-group network requests
Diffstat:
1 file changed, 25 insertions(+), 11 deletions(-)
diff --git a/packages/taler-wallet-core/src/withdraw.ts b/packages/taler-wallet-core/src/withdraw.ts
@@ -168,6 +168,7 @@ import {
ReadyExchangeSummary,
checkIncomingAmountLegalUnderKycBalanceThreshold,
fetchFreshExchange,
+ fetchFreshExchangeWithRetryNow,
getExchangeDetailsInTx,
getExchangePaytoUri,
getPreferredExchangeForCurrency,
@@ -185,7 +186,10 @@ import {
isKycOperationDue,
runKycCheckAlgo,
} from "./kyc.js";
-import { runWithMaybeProgressContext } from "./progress.js";
+import {
+ runWithMaybeProgressContext,
+ runWithProgressRetries,
+} from "./progress.js";
import {
constructTransactionIdentifier,
isUnsuccessfulTransaction,
@@ -2902,7 +2906,11 @@ async function getWithdrawalDetailsForBankInfo(
try {
// If the exchange entry doesn't exist yet,
// it'll be created as an ephemeral entry.
- await fetchFreshExchange(wex, info.exchange);
+ //
+ // noBail: false even under a progress context, since this is best-effort
+ // (other exchanges might be available); we must not block here waiting on
+ // a bank-suggested exchange that is broken/offline.
+ await fetchFreshExchange(wex, info.exchange, { noBail: false });
} catch (e) {
// We still continued if it failed, as other exchanges might be available.
// We don't want to fail if the bank-suggested exchange is broken/offline.
@@ -2965,7 +2973,11 @@ export async function getWithdrawalDetailsForUri(
talerWithdrawUri: string,
): Promise<WithdrawUriInfoResponse> {
logger.trace(`getting withdrawal details for URI ${talerWithdrawUri}`);
- const info = await getBankWithdrawalInfo(wex.http, talerWithdrawUri);
+ // Retried under a progress context: the bank integration API is the network
+ // hop most likely to be slow or briefly unavailable here.
+ const info = await runWithProgressRetries(wex, () =>
+ getBankWithdrawalInfo(wex.http, talerWithdrawUri),
+ );
logger.trace(`got bank info`);
return getWithdrawalDetailsForBankInfo(wex, info);
}
@@ -3625,9 +3637,10 @@ export async function prepareBankIntegratedWithdrawal(
`creating withdrawal with externalConfirmation=${externalConfirmation}`,
);
- const withdrawInfo = await getBankWithdrawalInfo(
- wex.http,
- req.talerWithdrawUri,
+ // Retried under a progress context: the bank integration API is the network
+ // hop most likely to be slow or briefly unavailable here.
+ const withdrawInfo = await runWithProgressRetries(wex, () =>
+ getBankWithdrawalInfo(wex.http, req.talerWithdrawUri),
);
const info = await getWithdrawalDetailsForBankInfo(wex, withdrawInfo);
@@ -3772,7 +3785,7 @@ export async function confirmWithdrawal(
instructedCurrency = withdrawalGroup.wgInfo.bankInfo.currency;
}
- const exchange = await fetchFreshExchange(wex, selectedExchange);
+ const exchange = await fetchFreshExchangeWithRetryNow(wex, selectedExchange);
requireExchangeTosAcceptedOrThrow(wex, exchange);
if (req.amount && checkWithdrawalHardLimitExceeded(exchange, req.amount)) {
@@ -3791,9 +3804,10 @@ export async function confirmWithdrawal(
withdrawalGroup.wgInfo.bankInfo.wireTypes === undefined ||
withdrawalGroup.wgInfo.bankInfo.currency === undefined
) {
- const withdrawInfo = await getBankWithdrawalInfo(
- wex.http,
- talerWithdrawUri,
+ // Retried under a progress context, like the other bank integration
+ // queries in this file.
+ const withdrawInfo = await runWithProgressRetries(wex, () =>
+ getBankWithdrawalInfo(wex.http, talerWithdrawUri),
);
bankWireTypes = withdrawInfo.wireTypes;
bankCurrency = withdrawInfo.currency;
@@ -4231,7 +4245,7 @@ export async function createManualWithdrawal(
): Promise<AcceptManualWithdrawalResult> {
const { exchangeBaseUrl } = req;
const amount = Amounts.parseOrThrow(req.amount);
- const exchange = await fetchFreshExchange(wex, exchangeBaseUrl);
+ const exchange = await fetchFreshExchangeWithRetryNow(wex, exchangeBaseUrl);
if (exchange.currency != amount.currency) {
throw Error(