diff options
author | Florian Dold <florian@dold.me> | 2023-05-24 12:54:07 +0200 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2023-05-24 12:54:07 +0200 |
commit | ea953f2b772b07780b94daecdefde6cd253a7e90 (patch) | |
tree | 7d2e5b36d224a3d2b07ece0a4b39d2e7607e3df9 /packages/taler-util | |
parent | da87ce41a6b6a6b66af7b99098e015e74ae27b67 (diff) | |
download | wallet-core-ea953f2b772b07780b94daecdefde6cd253a7e90.tar.xz |
wallet-core: use division for withdrawal coin selection
Diffstat (limited to 'packages/taler-util')
-rw-r--r-- | packages/taler-util/src/amounts.test.ts | 10 | ||||
-rw-r--r-- | packages/taler-util/src/amounts.ts | 28 |
2 files changed, 38 insertions, 0 deletions
diff --git a/packages/taler-util/src/amounts.test.ts b/packages/taler-util/src/amounts.test.ts index 064023e2d..644b8bdb4 100644 --- a/packages/taler-util/src/amounts.test.ts +++ b/packages/taler-util/src/amounts.test.ts @@ -138,3 +138,13 @@ test("amount multiplication", (t) => { t.is(Amounts.stringify(Amounts.mult(sAmt("EUR:1.11"), 4).amount), "EUR:4.44"); t.is(Amounts.stringify(Amounts.mult(sAmt("EUR:1.11"), 5).amount), "EUR:5.55"); }); + + + +test("amount division", (t) => { + t.is(Amounts.divmod("EUR:5", "EUR:1").quotient, 5); + t.is(Amounts.stringify(Amounts.divmod("EUR:5", "EUR:1").remainder), "EUR:0"); + + t.is(Amounts.divmod("EUR:5", "EUR:2").quotient, 2); + t.is(Amounts.stringify(Amounts.divmod("EUR:5", "EUR:2").remainder), "EUR:1"); +}); diff --git a/packages/taler-util/src/amounts.ts b/packages/taler-util/src/amounts.ts index d4e798030..a998c8f63 100644 --- a/packages/taler-util/src/amounts.ts +++ b/packages/taler-util/src/amounts.ts @@ -95,6 +95,11 @@ export interface Result { */ export type AmountLike = AmountString | AmountJson; +export interface DivmodResult { + quotient: number; + remainder: AmountJson; +} + /** * Helper class for dealing with amounts. */ @@ -135,6 +140,29 @@ export class Amounts { return amt; } + static divmod(a1: AmountLike, a2: AmountLike): DivmodResult { + const am1 = Amounts.jsonifyAmount(a1); + const am2 = Amounts.jsonifyAmount(a2); + if (am1.currency != am2.currency) { + throw Error(`incompatible currency (${am1.currency} vs${am2.currency})`); + } + + const x1 = BigInt(am1.value) * BigInt(amountFractionalBase) + BigInt(am1.fraction); + const x2 = BigInt(am2.value) * BigInt(amountFractionalBase) + BigInt(am2.fraction); + + const quotient = x1 / x2; + const remainderScaled = x1 % x2; + + return { + quotient: Number(quotient), + remainder: { + currency: am1.currency, + value: Number(remainderScaled / BigInt(amountFractionalBase)), + fraction: Number(remainderScaled % BigInt(amountFractionalBase)) + } + } + } + static sum(amounts: AmountLike[]): Result { if (amounts.length <= 0) { throw Error("can't sum zero amounts"); |