taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 8e213e9dd027da6f51f2bb7a23a0fa24fed84041
parent 0faa2624a4c8c98b9b6ea19ff15ce80de9f6b90c
Author: Florian Dold <florian@dold.me>
Date:   Sun,  3 Aug 2025 16:48:05 +0200

wallet-core: fix computation of viable exchanges for deposit when multiple exchanges are present for the same currency

Diffstat:
Mpackages/taler-wallet-core/src/balance.ts | 32+++++++++++++++++++++-----------
Mpackages/taler-wallet-core/src/deposits.ts | 10++++++++--
2 files changed, 29 insertions(+), 13 deletions(-)

diff --git a/packages/taler-wallet-core/src/balance.ts b/packages/taler-wallet-core/src/balance.ts @@ -51,6 +51,7 @@ */ import { GlobalIDB } from "@gnu-taler/idb-bridge"; import { + AllowedExchangeInfo, AmountJson, AmountLike, Amounts, @@ -103,19 +104,27 @@ interface WalletBalance { flagOutgoingKyc: boolean; } -/** - * Compute the available amount that the wallet expects to get - * out of a refresh group. - */ -function computeRefreshGroupAvailableAmount(r: RefreshGroupRecord): AmountJson { +function computeRefreshGroupAvailableAmountForExchanges( + r: RefreshGroupRecord, + restrictExchanges: AllowedExchangeInfo[] | undefined, +): AmountJson { // Don't count finished refreshes, since the refresh already resulted // in coins being added to the wallet. let available = Amounts.zeroOfCurrency(r.currency); if (r.timestampFinished) { return available; } - for (let i = 0; i < r.oldCoinPubs.length; i++) { - available = Amounts.add(available, r.expectedOutputPerCoin[i]).amount; + if (!r.infoPerExchange) { + return available; + } + for (const exch of Object.keys(r.infoPerExchange)) { + const pe = r.infoPerExchange[exch]; + if ( + restrictExchanges == null || + restrictExchanges.find((x) => x.exchangeBaseUrl === exch) != null + ) { + available = Amounts.add(available, pe.outputEffective).amount; + } } return available; } @@ -882,10 +891,11 @@ export async function getPaymentBalanceDetailsInTx( if (r.currency != req.currency) { return; } - d.balanceAvailable = Amounts.add( - d.balanceAvailable, - computeRefreshGroupAvailableAmount(r), - ).amount; + const balRefresh = computeRefreshGroupAvailableAmountForExchanges( + r, + req.restrictExchanges?.exchanges, + ); + d.balanceAvailable = Amounts.add(d.balanceAvailable, balRefresh).amount; }); return d; diff --git a/packages/taler-wallet-core/src/deposits.ts b/packages/taler-wallet-core/src/deposits.ts @@ -1983,12 +1983,18 @@ async function getExchangesForDeposit( wex: WalletExecutionContext, req: { restrictScope?: ScopeInfo; currency: string }, ): Promise<Exchange[]> { + logger.trace(`getting exchanges for deposit ${j2s(req)}`); const exchangeInfos: Exchange[] = []; await wex.db.runAllStoresReadOnlyTx({}, async (tx) => { const allExchanges = await tx.exchanges.iter().toArray(); for (const e of allExchanges) { const details = await getExchangeWireDetailsInTx(tx, e.baseUrl); - if (!details || req.currency !== details.currency) { + if (!details) { + logger.trace(`skipping ${e.baseUrl}, no details`); + continue; + } + if (req.currency !== details.currency) { + logger.trace(`skipping ${e.baseUrl}, currency mismatch`); continue; } if (req.restrictScope) { @@ -1998,7 +2004,7 @@ async function getExchangesForDeposit( req.restrictScope, ); if (!inScope) { - break; + continue; } } exchangeInfos.push({