taler-typescript-core

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

commit 880298110d53f7a053c8929e4627aac2dd346c94
parent 4d22292628163e1268ad1579150722c398d13e35
Author: Florian Dold <dold@taler.net>
Date:   Mon, 20 Jul 2026 13:58:59 +0200

util: report amount currency mismatch early

Diffstat:
Mpackages/taler-util/src/amounts.test.ts | 6++++++
Mpackages/taler-util/src/amounts.ts | 18++++++++++++------
2 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/packages/taler-util/src/amounts.test.ts b/packages/taler-util/src/amounts.test.ts @@ -46,6 +46,12 @@ test("amount addition (saturation)", (t) => { assert.ok(res.saturated); }); +test("Amounts.add validates all currencies even when the first argument already overflows", (t) => { + assert.throws(() => + Amounts.add(jAmt(amountMaxValue + 1, 0, "EUR"), jAmt(5, 0, "USD")), + ); +}); + test("amount subtraction (simple)", (t) => { const a1 = jAmt(2, 5, "EUR"); const a2 = jAmt(1, 0, "EUR"); diff --git a/packages/taler-util/src/amounts.ts b/packages/taler-util/src/amounts.ts @@ -343,6 +343,17 @@ export class Amounts { static add(first: AmountLike, ...rest: AmountLike[]): AmountResult { const firstJ = Amounts.jsonifyAmount(first); const currency = firstJ.currency; + + // Validate all currencies before any numeric accumulation/overflow + // check, so a mismatched currency in `rest` is always reported, even + // if the first argument alone would already saturate the result. + const restJ = rest.map((x) => Amounts.jsonifyAmount(x)); + for (const xJ of restJ) { + if (xJ.currency.toUpperCase() !== currency.toUpperCase()) { + throw Error(`Mismatched currency: ${xJ.currency} and ${currency}`); + } + } + let value = firstJ.value + Math.floor(firstJ.fraction / amountFractionalBase); if (value > amountMaxValue) { @@ -356,12 +367,7 @@ export class Amounts { }; } let fraction = firstJ.fraction % amountFractionalBase; - for (const x of rest) { - const xJ = Amounts.jsonifyAmount(x); - if (xJ.currency.toUpperCase() !== currency.toUpperCase()) { - throw Error(`Mismatched currency: ${xJ.currency} and ${currency}`); - } - + for (const xJ of restJ) { value = value + xJ.value +