taler-typescript-core

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

commit fb87b6b5ef97d0e461b232b1ae6c0ca968fdc216
parent aaa79dd33b884d362d6ec39b17baf1efb6f88b5b
Author: Florian Dold <florian@dold.me>
Date:   Tue,  2 Jun 2026 01:46:54 +0200

Revert "wallet-core: subtract prospective coin selections from available balance"

This reverts commit aaa79dd33b884d362d6ec39b17baf1efb6f88b5b.

Diffstat:
Mpackages/taler-wallet-core/src/balance.ts | 125+++++++++++++++++--------------------------------------------------------------
Mpackages/taler-wallet-core/src/db.ts | 6------
Mpackages/taler-wallet-core/src/pay-merchant.ts | 21---------------------
3 files changed, 26 insertions(+), 126 deletions(-)

diff --git a/packages/taler-wallet-core/src/balance.ts b/packages/taler-wallet-core/src/balance.ts @@ -110,8 +110,7 @@ const logger = new Logger("operations/balance.ts"); interface WalletBalance { scopeInfo: ScopeInfo; - availablePos: AmountJson; - availableNeg: AmountJson; + available: AmountJson; pendingIncoming: AmountJson; pendingOutgoing: AmountJson; flagIncomingKyc: boolean; @@ -211,8 +210,7 @@ class BalancesStore { const zero = Amounts.zeroOfCurrency(currency); b = this.balanceStore[balanceKey] = { scopeInfo, - availablePos: zero, - availableNeg: zero, + available: zero, pendingIncoming: zero, pendingOutgoing: zero, flagIncomingConfirmation: false, @@ -263,16 +261,7 @@ class BalancesStore { amount: AmountLike, ): Promise<void> { const b = await this.initBalance(currency, exchangeBaseUrl); - b.availablePos = Amounts.add(b.availablePos, amount).amount; - } - - async subAvailable( - currency: string, - exchangeBaseUrl: string, - amount: AmountLike, - ): Promise<void> { - const b = await this.initBalance(currency, exchangeBaseUrl); - b.availableNeg = Amounts.sub(b.availableNeg, amount).amount; + b.available = Amounts.add(b.available, amount).amount; } async addPendingIncoming( @@ -389,9 +378,7 @@ class BalancesStore { } balancesResponse.balances.push({ scopeInfo: v.scopeInfo, - available: Amounts.stringify( - Amounts.sub(v.availablePos, v.availableNeg).amount, - ), + available: Amounts.stringify(v.available), pendingIncoming: Amounts.stringify(v.pendingIncoming), pendingOutgoing: Amounts.stringify(v.pendingOutgoing), flags, @@ -584,28 +571,14 @@ export async function getBalancesInsideTransaction( await tx.peerPushDebit.indexes.byStatus .iter(keyRangeActive) .forEachAsync(async (ppdRecord) => { - const currency = Amounts.currencyOf(ppdRecord.amount); switch (ppdRecord.status) { - case PeerPushDebitStatus.PendingCreatePurse: - case PeerPushDebitStatus.SuspendedCreatePurse: { - if (ppdRecord.coinSel == null) { - await balanceStore.subAvailable( - currency, - ppdRecord.exchangeBaseUrl, - ppdRecord.totalCost, - ); - } - await balanceStore.addPendingOutgoing( - currency, - ppdRecord.exchangeBaseUrl, - ppdRecord.totalCost, - ); - break; - } case PeerPushDebitStatus.AbortingDeletePurse: case PeerPushDebitStatus.SuspendedAbortingDeletePurse: case PeerPushDebitStatus.PendingReady: - case PeerPushDebitStatus.SuspendedReady: { + case PeerPushDebitStatus.SuspendedReady: + case PeerPushDebitStatus.PendingCreatePurse: + case PeerPushDebitStatus.SuspendedCreatePurse: { + const currency = Amounts.currencyOf(ppdRecord.amount); await balanceStore.addPendingOutgoing( currency, ppdRecord.exchangeBaseUrl, @@ -681,27 +654,12 @@ export async function getBalancesInsideTransaction( await tx.peerPullDebit.indexes.byStatus .iter(keyRangeActive) .forEachAsync(async (rec) => { - const currency = Amounts.currencyOf(rec.amount); - switch (rec.status) { - case PeerPullDebitRecordStatus.PendingDeposit: - case PeerPullDebitRecordStatus.SuspendedDeposit: - // We're on a prospective coin selection, - // thus the amount of this transaction gets - // deducted from the available amount. - if (rec.coinSel == null) { - await balanceStore.subAvailable( - currency, - rec.exchangeBaseUrl, - rec.totalCostEstimated, - ); - } - break; - } switch (rec.status) { case PeerPullDebitRecordStatus.PendingDeposit: - case PeerPullDebitRecordStatus.SuspendedDeposit: case PeerPullDebitRecordStatus.AbortingRefresh: - case PeerPullDebitRecordStatus.SuspendedAbortingRefresh: { + case PeerPullDebitRecordStatus.SuspendedAbortingRefresh: + case PeerPullDebitRecordStatus.SuspendedDeposit: + const currency = Amounts.currencyOf(rec.amount); const amount = rec.coinSel?.totalCost ?? rec.amount; await balanceStore.addPendingOutgoing( currency, @@ -709,7 +667,6 @@ export async function getBalancesInsideTransaction( amount, ); break; - } } }); @@ -719,38 +676,23 @@ export async function getBalancesInsideTransaction( switch (rec.purchaseStatus) { case PurchaseStatus.SuspendedPaying: case PurchaseStatus.PendingPaying: - // We're on a prospective coin selection, - // thus the amount of this transaction gets - // deducted from the available amount. - if ( - rec.payInfo && - !rec.payInfo.payCoinSelection && - rec.payInfo.prospectivePayCoinSelection - ) { - const currency = Amounts.currencyOf(rec.payInfo.totalPayCost); - for (const pr of rec.payInfo.prospectivePayCoinSelection) - await balanceStore.subAvailable( - currency, - pr.contribution, - pr.exchangeBaseUrl, - ); + if (!rec.payInfo || !rec.payInfo.payCoinSelection?.coinPubs) { + break; } - if (rec.payInfo && rec.payInfo.payCoinSelection?.coinPubs) { - // FIXME: This is pretty slow, cache? - const currency = Amounts.currencyOf(rec.payInfo.totalPayCost); - const sel = rec.payInfo.payCoinSelection; - for (let i = 0; i < sel.coinPubs.length; i++) { - const coinPub = sel.coinPubs[i]; - const coinRec = await tx.coins.get(coinPub); - if (!coinRec) { - continue; - } - await balanceStore.addPendingOutgoing( - currency, - coinRec.exchangeBaseUrl, - sel.coinContributions[i], - ); + // FIXME: This is pretty slow, cache? + const currency = Amounts.currencyOf(rec.payInfo.totalPayCost); + const sel = rec.payInfo.payCoinSelection; + for (let i = 0; i < sel.coinPubs.length; i++) { + const coinPub = sel.coinPubs[i]; + const coinRec = await tx.coins.get(coinPub); + if (!coinRec) { + continue; } + await balanceStore.addPendingOutgoing( + currency, + coinRec.exchangeBaseUrl, + sel.coinContributions[i], + ); } } }); @@ -772,21 +714,6 @@ export async function getBalancesInsideTransaction( case DepositOperationStatus.SuspendedDepositKyc: case DepositOperationStatus.SuspendedDepositKycAuth: await balanceStore.setFlagOutgoingKyc(currency, e); - if (dgRecord.payCoinSelection == null) { - // We're on a prospective coin selection, - // thus the amount of this transaction gets - // deducted from the available amount. - const perExchange = dgRecord.infoPerExchange; - if (perExchange) { - for (const [e, v] of Object.entries(perExchange)) { - await balanceStore.subAvailable( - currency, - e, - v.amountEffective, - ); - } - } - } } switch (dgRecord.operationStatus) { case DepositOperationStatus.SuspendedAggregateKyc: diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts @@ -1516,7 +1516,6 @@ export interface PurchasePayInfo { * Undefined if payment is blocked by a pending refund. */ payCoinSelection?: DbCoinSelection; - /** * Undefined if payment is blocked by a pending refund. */ @@ -1524,11 +1523,6 @@ export interface PurchasePayInfo { payTokenSelection?: DbTokenSelection; - prospectivePayCoinSelection?: { - exchangeBaseUrl: string; - contribution: AmountString; - }[]; - /** * Token signatures from merchant. */ diff --git a/packages/taler-wallet-core/src/pay-merchant.ts b/packages/taler-wallet-core/src/pay-merchant.ts @@ -86,7 +86,6 @@ import { PreparePayResult, PreparePayResultType, PreparePayTemplateRequest, - ProspectivePayCoinSelection, randomBytes, RefreshReason, RefundInfoShort, @@ -1524,23 +1523,6 @@ function setCoinSel(rec: PurchaseRecord, coinSel: PayCoinSelection): void { rec.exchanges.sort(); } -function setProspectiveCoinSel( - rec: PurchaseRecord, - coinSel: ProspectivePayCoinSelection, -): void { - checkLogicInvariant(!!rec.payInfo); - rec.payInfo.prospectivePayCoinSelection = coinSel.prospectiveCoins.map( - (x) => ({ - contribution: x.contribution, - exchangeBaseUrl: x.exchangeBaseUrl, - }), - ); - rec.exchanges = [ - ...new Set(coinSel.prospectiveCoins.map((x) => x.exchangeBaseUrl)), - ]; - rec.exchanges.sort(); -} - async function reselectCoinsTx( tx: WalletIndexedDbTransaction, ctx: PayMerchantTransactionContext, @@ -2953,9 +2935,6 @@ export async function confirmPay( if (selectCoinsResult.type === "success") { setCoinSel(p, selectCoinsResult.coinSel); } - if (selectCoinsResult.type === "prospective") { - setProspectiveCoinSel(p, selectCoinsResult.result); - } p.lastSessionId = sessionId; p.timestampAccept = timestampPreciseToDb(TalerPreciseTimestamp.now()); p.purchaseStatus = PurchaseStatus.PendingPaying;