taler-typescript-core

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

commit d2883bf078f190067d7cfd8e5e91db0273c151eb
parent 80cdacbd4cb85846d332cf5f29d3278f18d9fa38
Author: Florian Dold <dold@taler.net>
Date:   Thu, 20 Aug 2026 19:06:45 +0200

wallet-core: refresh value recovered by recoup-refresh

Diffstat:
Apackages/taler-wallet-core/src/recoup.test.ts | 32++++++++++++++++++++++++++++++++
Mpackages/taler-wallet-core/src/recoup.ts | 35++++++++++++++++++++++++++++++-----
2 files changed, 62 insertions(+), 5 deletions(-)

diff --git a/packages/taler-wallet-core/src/recoup.test.ts b/packages/taler-wallet-core/src/recoup.test.ts @@ -0,0 +1,32 @@ +/* + This file is part of GNU Taler + (C) 2026 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +import assert from "node:assert"; +import { test } from "node:test"; +import { WalletRecoupGroup } from "./db-common.js"; +import { scheduleRecoupRefresh } from "./recoup.js"; + +test("recoup-refresh schedules and aggregates value on the old coin", () => { + const group = { scheduleRefreshCoins: [] } as unknown as WalletRecoupGroup; + + scheduleRecoupRefresh(group, "old-coin", "TESTKUDOS:2"); + scheduleRecoupRefresh(group, "old-coin", "TESTKUDOS:3"); + scheduleRecoupRefresh(group, "another-old-coin", "TESTKUDOS:1"); + + assert.deepStrictEqual(group.scheduleRefreshCoins, [ + { coinPub: "old-coin", amount: "TESTKUDOS:5" }, + { coinPub: "another-old-coin", amount: "TESTKUDOS:1" }, + ]); +}); diff --git a/packages/taler-wallet-core/src/recoup.ts b/packages/taler-wallet-core/src/recoup.ts @@ -25,6 +25,7 @@ * Imports. */ import { + AmountLike, Amounts, CoinStatus, Logger, @@ -184,17 +185,41 @@ async function recoupRefreshCoin( `no revoked denom for coin, hash ${revokedCoin.denomPubHash}`, ); revokedCoin.status = CoinStatus.Dormant; - // FIXME: Schedule recoup for the sum of refreshes, based on the coin event history. - // recoupGroup.scheduleRefreshCoins.push({ - // coinPub: oldCoin.coinPub, - // amount: Amounts.stringify(refreshAmount), - // }); + scheduleRecoupRefresh( + recoupGroup, + oldCoin.coinPub, + revokedCoinDenom.value, + ); await tx.upsertCoin(revokedCoin); await tx.upsertCoin(oldCoin); await putGroupAsFinished(wex, tx, recoupGroup, coinIdx); }); } +export function scheduleRecoupRefresh( + recoupGroup: WalletRecoupGroup, + oldCoinPub: string, + recoveredAmount: AmountLike, +): void { + const existingIndex = recoupGroup.scheduleRefreshCoins.findIndex( + (x) => x.coinPub === oldCoinPub, + ); + if (existingIndex >= 0) { + const existing = recoupGroup.scheduleRefreshCoins[existingIndex]; + recoupGroup.scheduleRefreshCoins[existingIndex] = { + ...existing, + amount: Amounts.stringify( + Amounts.add(existing.amount, recoveredAmount).amount, + ), + }; + return; + } + recoupGroup.scheduleRefreshCoins.push({ + coinPub: oldCoinPub, + amount: Amounts.stringify(recoveredAmount), + }); +} + export async function recoupWithdrawCoin( wex: WalletExecutionContext, recoupGroupId: string,