diff options
Diffstat (limited to 'packages/taler-wallet-core/src/coinSelection.test.ts')
-rw-r--r-- | packages/taler-wallet-core/src/coinSelection.test.ts | 185 |
1 files changed, 179 insertions, 6 deletions
diff --git a/packages/taler-wallet-core/src/coinSelection.test.ts b/packages/taler-wallet-core/src/coinSelection.test.ts index c7cb2857e..4984552f8 100644 --- a/packages/taler-wallet-core/src/coinSelection.test.ts +++ b/packages/taler-wallet-core/src/coinSelection.test.ts @@ -15,17 +15,21 @@ */ import { AbsoluteTime, + AmountJson, AmountString, Amounts, DenomKeyType, + DenominationPubKey, Duration, + TalerProtocolTimestamp, j2s, } from "@gnu-taler/taler-util"; import test from "ava"; import { - AvailableDenom, + AvailableCoinsOfDenom, CoinSelectionTally, emptyTallyForPeerPayment, + testing_getMaxDepositAmountForAvailableCoins, testing_selectGreedy, } from "./coinSelection.js"; @@ -42,7 +46,9 @@ const inThePast = AbsoluteTime.toProtocolTimestamp( test("p2p: should select the coin", (t) => { const instructedAmount = Amounts.parseOrThrow("LOCAL:2"); - const tally = emptyTallyForPeerPayment(instructedAmount); + const tally = emptyTallyForPeerPayment({ + instructedAmount, + }); t.log(`tally before: ${j2s(tally)}`); const coins = testing_selectGreedy( { @@ -76,7 +82,9 @@ test("p2p: should select the coin", (t) => { test("p2p: should select 3 coins", (t) => { const instructedAmount = Amounts.parseOrThrow("LOCAL:20"); - const tally = emptyTallyForPeerPayment(instructedAmount); + const tally = emptyTallyForPeerPayment({ + instructedAmount, + }); const coins = testing_selectGreedy( { wireFeesPerExchange: {}, @@ -108,7 +116,9 @@ test("p2p: should select 3 coins", (t) => { test("p2p: can't select since the instructed amount is too high", (t) => { const instructedAmount = Amounts.parseOrThrow("LOCAL:60"); - const tally = emptyTallyForPeerPayment(instructedAmount); + const tally = emptyTallyForPeerPayment({ + instructedAmount, + }); const coins = testing_selectGreedy( { wireFeesPerExchange: {}, @@ -138,6 +148,7 @@ test("pay: select one coin to pay with fee", (t) => { customerWireFees: zero, wireFeeCoveredForExchange: new Set<string>(), lastDepositFee: zero, + totalDepositFees: zero, } satisfies CoinSelectionTally; const coins = testing_selectGreedy( { @@ -180,7 +191,7 @@ function createCandidates( numAvailable: number; fromExchange: string; }[], -): AvailableDenom[] { +): AvailableCoinsOfDenom[] { return ar.map((r, idx) => { return { denomPub: { @@ -269,7 +280,9 @@ test("p2p: regression STATER", (t) => { }, ]; const instructedAmount = Amounts.parseOrThrow("STATER:1"); - const tally = emptyTallyForPeerPayment(instructedAmount); + const tally = emptyTallyForPeerPayment({ + instructedAmount, + }); const res = testing_selectGreedy( { wireFeesPerExchange: {}, @@ -279,3 +292,163 @@ test("p2p: regression STATER", (t) => { ); t.assert(!!res); }); + +function makeCurrencyHelper(currency: string) { + return (sx: TemplateStringsArray, ...vx: any[]) => { + const s = String.raw({ raw: sx }, ...vx); + return Amounts.parseOrThrow(`${currency}:${s}`); + }; +} + +type TestCoin = [AmountJson, number]; + +const kudos = makeCurrencyHelper("kudos"); + +function defaultFeeConfig( + value: AmountJson, + totalAvailable: number, +): AvailableCoinsOfDenom { + return { + denomPub: undefined as any as DenominationPubKey, + denomPubHash: "123", + feeDeposit: `KUDOS:0.01`, + feeRefresh: `KUDOS:0.01`, + feeRefund: `KUDOS:0.01`, + feeWithdraw: `KUDOS:0.01`, + exchangeBaseUrl: "2", + maxAge: 0, + numAvailable: totalAvailable, + stampExpireDeposit: TalerProtocolTimestamp.never(), + stampExpireLegal: TalerProtocolTimestamp.never(), + stampExpireWithdraw: TalerProtocolTimestamp.never(), + stampStart: TalerProtocolTimestamp.never(), + value: Amounts.stringify(value), + }; +} + +test("deposit max 35", (t) => { + const coinList: TestCoin[] = [ + [kudos`2`, 5], + [kudos`5`, 5], + ]; + const result = testing_getMaxDepositAmountForAvailableCoins( + { + currency: "KUDOS", + }, + { + coinAvailability: coinList.map(([v, t]) => defaultFeeConfig(v, t)), + currentWireFeePerExchange: { + "2": kudos`0`, + }, + }, + ); + t.is(Amounts.stringifyValue(result.rawAmount), "34.9"); + t.is(Amounts.stringifyValue(result.effectiveAmount), "35"); +}); + +test("deposit max 35 with wirefee", (t) => { + const coinList: TestCoin[] = [ + [kudos`2`, 5], + [kudos`5`, 5], + ]; + const result = testing_getMaxDepositAmountForAvailableCoins( + { + currency: "KUDOS", + }, + { + coinAvailability: coinList.map(([v, t]) => defaultFeeConfig(v, t)), + currentWireFeePerExchange: { + "2": kudos`1`, + }, + }, + ); + t.is(Amounts.stringifyValue(result.rawAmount), "33.9"); + t.is(Amounts.stringifyValue(result.effectiveAmount), "35"); +}); + +test("deposit max repeated denom", (t) => { + const coinList: TestCoin[] = [ + [kudos`2`, 1], + [kudos`2`, 1], + [kudos`5`, 1], + ]; + const result = testing_getMaxDepositAmountForAvailableCoins( + { + currency: "KUDOS", + }, + { + coinAvailability: coinList.map(([v, t]) => defaultFeeConfig(v, t)), + currentWireFeePerExchange: { + "2": kudos`0`, + }, + }, + ); + t.is(Amounts.stringifyValue(result.rawAmount), "8.97"); + t.is(Amounts.stringifyValue(result.effectiveAmount), "9"); +}); + +test("demo: deposit max after withdraw raw 25", (t) => { + const coinList: TestCoin[] = [ + [kudos`0.1`, 8], + [kudos`1`, 0], + [kudos`2`, 2], + [kudos`5`, 0], + [kudos`10`, 2], + ]; + const result = testing_getMaxDepositAmountForAvailableCoins( + { + currency: "KUDOS", + }, + { + coinAvailability: coinList.map(([v, t]) => defaultFeeConfig(v, t)), + currentWireFeePerExchange: { + "2": kudos`0.01`, + }, + }, + ); + t.is(Amounts.stringifyValue(result.effectiveAmount), "24.8"); + t.is(Amounts.stringifyValue(result.rawAmount), "24.67"); + + // 8 x 0.1 + // 2 x 0.2 + // 2 x 10.0 + // total effective 24.8 + // deposit fee 12 x 0.01 = 0.12 + // wire fee 0.01 + // total raw: 24.8 - 0.13 = 24.67 + + // current wallet impl fee 0.14 +}); + +test("demo: deposit max after withdraw raw 13", (t) => { + const coinList: TestCoin[] = [ + [kudos`0.1`, 8], + [kudos`1`, 0], + [kudos`2`, 1], + [kudos`5`, 0], + [kudos`10`, 1], + ]; + const result = testing_getMaxDepositAmountForAvailableCoins( + { + currency: "KUDOS", + }, + { + coinAvailability: coinList.map(([v, t]) => defaultFeeConfig(v, t)), + currentWireFeePerExchange: { + "2": kudos`0.01`, + }, + }, + ); + t.is(Amounts.stringifyValue(result.effectiveAmount), "12.8"); + t.is(Amounts.stringifyValue(result.rawAmount), "12.69"); + + // 8 x 0.1 + // 1 x 0.2 + // 1 x 10.0 + // total effective 12.8 + // deposit fee 10 x 0.01 = 0.10 + // wire fee 0.01 + // total raw: 12.8 - 0.11 = 12.69 + + // current wallet impl fee 0.14 +}); |