diff options
Diffstat (limited to 'packages/taler-wallet-core/src/util/coinSelection.test.ts')
-rw-r--r-- | packages/taler-wallet-core/src/util/coinSelection.test.ts | 742 |
1 files changed, 0 insertions, 742 deletions
diff --git a/packages/taler-wallet-core/src/util/coinSelection.test.ts b/packages/taler-wallet-core/src/util/coinSelection.test.ts index fddd217ea..b907eb160 100644 --- a/packages/taler-wallet-core/src/util/coinSelection.test.ts +++ b/packages/taler-wallet-core/src/util/coinSelection.test.ts @@ -22,746 +22,4 @@ import { TransactionAmountMode, } from "@gnu-taler/taler-util"; import test, { ExecutionContext } from "ava"; -import { - CoinInfo, - convertDepositAmountForAvailableCoins, - convertWithdrawalAmountFromAvailableCoins, - getMaxDepositAmountForAvailableCoins, -} from "./coinSelection.js"; - -function makeCurrencyHelper(currency: string) { - return (sx: TemplateStringsArray, ...vx: any[]) => { - const s = String.raw({ raw: sx }, ...vx); - return Amounts.parseOrThrow(`${currency}:${s}`); - }; -} - -const kudos = makeCurrencyHelper("kudos"); - -function defaultFeeConfig(value: AmountJson, totalAvailable: number): CoinInfo { - return { - id: Amounts.stringify(value), - denomDeposit: kudos`0.01`, - denomRefresh: kudos`0.01`, - denomWithdraw: kudos`0.01`, - exchangeBaseUrl: "1", - duration: Duration.getForever(), - exchangePurse: undefined, - exchangeWire: undefined, - maxAge: AgeRestriction.AGE_UNRESTRICTED, - totalAvailable, - value, - }; -} -type Coin = [AmountJson, number]; - -/** - * Making a deposit with effective amount - * - */ - -test("deposit effective 2", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertDepositAmountForAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`2`, - TransactionAmountMode.Effective, - ); - t.is(Amounts.stringifyValue(result.effective), "2"); - t.is(Amounts.stringifyValue(result.raw), "1.99"); -}); - -test("deposit effective 10", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertDepositAmountForAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`10`, - TransactionAmountMode.Effective, - ); - t.is(Amounts.stringifyValue(result.effective), "10"); - t.is(Amounts.stringifyValue(result.raw), "9.98"); -}); - -test("deposit effective 24", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertDepositAmountForAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`24`, - TransactionAmountMode.Effective, - ); - t.is(Amounts.stringifyValue(result.effective), "24"); - t.is(Amounts.stringifyValue(result.raw), "23.94"); -}); - -test("deposit effective 40", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertDepositAmountForAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`40`, - TransactionAmountMode.Effective, - ); - t.is(Amounts.stringifyValue(result.effective), "35"); - t.is(Amounts.stringifyValue(result.raw), "34.9"); -}); - -test("deposit with wire fee effective 2", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertDepositAmountForAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: { - one: { - wireFee: kudos`0.1`, - purseFee: kudos`0.00`, - creditDeadline: AbsoluteTime.never(), - debitDeadline: AbsoluteTime.never(), - }, - }, - }, - kudos`2`, - TransactionAmountMode.Effective, - ); - t.is(Amounts.stringifyValue(result.effective), "2"); - t.is(Amounts.stringifyValue(result.raw), "1.89"); -}); - -/** - * Making a deposit with raw amount, using the result from effective - * - */ - -test("deposit raw 1.99 (effective 2)", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertDepositAmountForAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`1.99`, - TransactionAmountMode.Raw, - ); - t.is(Amounts.stringifyValue(result.effective), "2"); - t.is(Amounts.stringifyValue(result.raw), "1.99"); -}); - -test("deposit raw 9.98 (effective 10)", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertDepositAmountForAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`9.98`, - TransactionAmountMode.Raw, - ); - t.is(Amounts.stringifyValue(result.effective), "10"); - t.is(Amounts.stringifyValue(result.raw), "9.98"); -}); - -test("deposit raw 23.94 (effective 24)", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertDepositAmountForAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`23.94`, - TransactionAmountMode.Raw, - ); - t.is(Amounts.stringifyValue(result.effective), "24"); - t.is(Amounts.stringifyValue(result.raw), "23.94"); -}); - -test("deposit raw 34.9 (effective 40)", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertDepositAmountForAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`34.9`, - TransactionAmountMode.Raw, - ); - t.is(Amounts.stringifyValue(result.effective), "35"); - t.is(Amounts.stringifyValue(result.raw), "34.9"); -}); - -test("deposit with wire fee raw 2", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertDepositAmountForAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: { - one: { - wireFee: kudos`0.1`, - purseFee: kudos`0.00`, - creditDeadline: AbsoluteTime.never(), - debitDeadline: AbsoluteTime.never(), - }, - }, - }, - kudos`2`, - TransactionAmountMode.Effective, - ); - t.is(Amounts.stringifyValue(result.effective), "2"); - t.is(Amounts.stringifyValue(result.raw), "1.89"); -}); - -/** - * Calculating the max amount possible to deposit - * - */ - -test("deposit max 35", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = getMaxDepositAmountForAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: { - "2": { - wireFee: kudos`0.00`, - purseFee: kudos`0.00`, - creditDeadline: AbsoluteTime.never(), - debitDeadline: AbsoluteTime.never(), - }, - }, - }, - "KUDOS", - ); - t.is(Amounts.stringifyValue(result.raw), "34.9"); - t.is(Amounts.stringifyValue(result.effective), "35"); -}); - -test("deposit max 35 with wirefee", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = getMaxDepositAmountForAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: { - "2": { - wireFee: kudos`1`, - purseFee: kudos`0.00`, - creditDeadline: AbsoluteTime.never(), - debitDeadline: AbsoluteTime.never(), - }, - }, - }, - "KUDOS", - ); - t.is(Amounts.stringifyValue(result.raw), "33.9"); - t.is(Amounts.stringifyValue(result.effective), "35"); -}); - -test("deposit max repeated denom", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 1], - [kudos`2`, 1], - [kudos`5`, 1], - ]; - const result = getMaxDepositAmountForAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: { - "2": { - wireFee: kudos`0.00`, - purseFee: kudos`0.00`, - creditDeadline: AbsoluteTime.never(), - debitDeadline: AbsoluteTime.never(), - }, - }, - }, - "KUDOS", - ); - t.is(Amounts.stringifyValue(result.raw), "8.97"); - t.is(Amounts.stringifyValue(result.effective), "9"); -}); - -/** - * Making a withdrawal with effective amount - * - */ - -test("withdraw effective 2", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertWithdrawalAmountFromAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`2`, - TransactionAmountMode.Effective, - ); - t.is(Amounts.stringifyValue(result.effective), "2"); - t.is(Amounts.stringifyValue(result.raw), "2.01"); -}); - -test("withdraw effective 10", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertWithdrawalAmountFromAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`10`, - TransactionAmountMode.Effective, - ); - t.is(Amounts.stringifyValue(result.effective), "10"); - t.is(Amounts.stringifyValue(result.raw), "10.02"); -}); - -test("withdraw effective 24", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertWithdrawalAmountFromAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`24`, - TransactionAmountMode.Effective, - ); - t.is(Amounts.stringifyValue(result.effective), "24"); - t.is(Amounts.stringifyValue(result.raw), "24.06"); -}); - -test("withdraw effective 40", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertWithdrawalAmountFromAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`40`, - TransactionAmountMode.Effective, - ); - t.is(Amounts.stringifyValue(result.effective), "40"); - t.is(Amounts.stringifyValue(result.raw), "40.08"); -}); - -/** - * Making a deposit with raw amount, using the result from effective - * - */ - -test("withdraw raw 2.01 (effective 2)", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertWithdrawalAmountFromAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`2.01`, - TransactionAmountMode.Raw, - ); - t.is(Amounts.stringifyValue(result.effective), "2"); - t.is(Amounts.stringifyValue(result.raw), "2.01"); -}); - -test("withdraw raw 10.02 (effective 10)", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertWithdrawalAmountFromAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`10.02`, - TransactionAmountMode.Raw, - ); - t.is(Amounts.stringifyValue(result.effective), "10"); - t.is(Amounts.stringifyValue(result.raw), "10.02"); -}); - -test("withdraw raw 24.06 (effective 24)", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertWithdrawalAmountFromAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`24.06`, - TransactionAmountMode.Raw, - ); - t.is(Amounts.stringifyValue(result.effective), "24"); - t.is(Amounts.stringifyValue(result.raw), "24.06"); -}); - -test("withdraw raw 40.08 (effective 40)", (t) => { - const coinList: Coin[] = [ - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertWithdrawalAmountFromAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`40.08`, - TransactionAmountMode.Raw, - ); - t.is(Amounts.stringifyValue(result.effective), "40"); - t.is(Amounts.stringifyValue(result.raw), "40.08"); -}); - -test("withdraw raw 25", (t) => { - const coinList: Coin[] = [ - [kudos`0.1`, 0], - [kudos`1`, 0], - [kudos`2`, 0], - [kudos`5`, 0], - ]; - const result = convertWithdrawalAmountFromAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`25`, - TransactionAmountMode.Raw, - ); - t.is(Amounts.stringifyValue(result.effective), "24.8"); - t.is(Amounts.stringifyValue(result.raw), "24.94"); -}); - -test("withdraw effective 24.8 (raw 25)", (t) => { - const coinList: Coin[] = [ - [kudos`0.1`, 0], - [kudos`1`, 0], - [kudos`2`, 0], - [kudos`5`, 0], - ]; - const result = convertWithdrawalAmountFromAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`24.8`, - TransactionAmountMode.Effective, - ); - t.is(Amounts.stringifyValue(result.effective), "24.8"); - t.is(Amounts.stringifyValue(result.raw), "24.94"); -}); - -/** - * Making a deposit with refresh - * - */ - -test("deposit with refresh: effective 3", (t) => { - const coinList: Coin[] = [ - [kudos`0.1`, 0], - [kudos`1`, 0], - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertDepositAmountForAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`3`, - TransactionAmountMode.Effective, - ); - t.is(Amounts.stringifyValue(result.effective), "3.1"); - t.is(Amounts.stringifyValue(result.raw), "2.98"); - expectDefined(t, result.refresh); - //FEES - //deposit 2 x 0.01 - //refresh 1 x 0.01 - //withdraw 9 x 0.01 - //----------------- - //op 0.12 - - //coins sent 2 x 2.0 - //coins recv 9 x 0.1 - //------------------- - //effective 3.10 - //raw 2.98 - t.is(Amounts.stringifyValue(result.refresh.selected.id), "2"); - t.deepEqual(asCoinList(result.refresh.coins), [[kudos`0.1`, 9]]); -}); - -test("deposit with refresh: raw 2.98 (effective 3)", (t) => { - const coinList: Coin[] = [ - [kudos`0.1`, 0], - [kudos`1`, 0], - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertDepositAmountForAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`2.98`, - TransactionAmountMode.Raw, - ); - t.is(Amounts.stringifyValue(result.effective), "3.2"); - t.is(Amounts.stringifyValue(result.raw), "3.09"); - expectDefined(t, result.refresh); - //FEES - //deposit 1 x 0.01 - //refresh 1 x 0.01 - //withdraw 8 x 0.01 - //----------------- - //op 0.10 - - //coins sent 1 x 2.0 - //coins recv 8 x 0.1 - //------------------- - //effective 3.20 - //raw 3.09 - t.is(Amounts.stringifyValue(result.refresh.selected.id), "2"); - t.deepEqual(asCoinList(result.refresh.coins), [[kudos`0.1`, 8]]); -}); - -test("deposit with refresh: effective 3.2 (raw 2.98)", (t) => { - const coinList: Coin[] = [ - [kudos`0.1`, 0], - [kudos`1`, 0], - [kudos`2`, 5], - [kudos`5`, 5], - ]; - const result = convertDepositAmountForAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`3.2`, - TransactionAmountMode.Effective, - ); - t.is(Amounts.stringifyValue(result.effective), "3.3"); - t.is(Amounts.stringifyValue(result.raw), "3.2"); - expectDefined(t, result.refresh); - //FEES - //deposit 2 x 0.01 - //refresh 1 x 0.01 - //withdraw 7 x 0.01 - //----------------- - //op 0.10 - - //coins sent 2 x 2.0 - //coins recv 7 x 0.1 - //------------------- - //effective 3.30 - //raw 3.20 - t.is(Amounts.stringifyValue(result.refresh.selected.id), "2"); - t.deepEqual(asCoinList(result.refresh.coins), [[kudos`0.1`, 7]]); -}); - -function expectDefined<T>( - t: ExecutionContext, - v: T | undefined, -): asserts v is T { - t.assert(v !== undefined); -} - -function asCoinList(v: { info: CoinInfo; size: number }[]): any { - return v.map((c) => { - return [c.info.value, c.size]; - }); -} - -/** - * regression tests - */ - -test("demo: withdraw raw 25", (t) => { - const coinList: Coin[] = [ - [kudos`0.1`, 0], - [kudos`1`, 0], - [kudos`2`, 0], - [kudos`5`, 0], - [kudos`10`, 0], - ]; - const result = convertWithdrawalAmountFromAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`25`, - TransactionAmountMode.Raw, - ); - t.is(Amounts.stringifyValue(result.effective), "24.8"); - t.is(Amounts.stringifyValue(result.raw), "24.92"); - // coins received - // 8 x 0.1 - // 2 x 0.2 - // 2 x 10.0 - // total effective 24.8 - // fee 12 x 0.01 = 0.12 - // total raw 24.92 - // left in reserve 25 - 24.92 == 0.08 - - //current wallet impl: hides the left in reserve fee - //shows fee = 0.2 -}); - -test("demo: deposit max after withdraw raw 25", (t) => { - const coinList: Coin[] = [ - [kudos`0.1`, 8], - [kudos`1`, 0], - [kudos`2`, 2], - [kudos`5`, 0], - [kudos`10`, 2], - ]; - const result = getMaxDepositAmountForAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: { - one: { - wireFee: kudos`0.01`, - purseFee: kudos`0.00`, - creditDeadline: AbsoluteTime.never(), - debitDeadline: AbsoluteTime.never(), - }, - }, - }, - "KUDOS", - ); - t.is(Amounts.stringifyValue(result.effective), "24.8"); - t.is(Amounts.stringifyValue(result.raw), "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: withdraw raw 13", (t) => { - const coinList: Coin[] = [ - [kudos`0.1`, 0], - [kudos`1`, 0], - [kudos`2`, 0], - [kudos`5`, 0], - [kudos`10`, 0], - ]; - const result = convertWithdrawalAmountFromAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: {}, - }, - kudos`13`, - TransactionAmountMode.Raw, - ); - t.is(Amounts.stringifyValue(result.effective), "12.8"); - t.is(Amounts.stringifyValue(result.raw), "12.9"); - // coins received - // 8 x 0.1 - // 1 x 0.2 - // 1 x 10.0 - // total effective 12.8 - // fee 10 x 0.01 = 0.10 - // total raw 12.9 - // left in reserve 13 - 12.9 == 0.1 - - //current wallet impl: hides the left in reserve fee - //shows fee = 0.2 -}); - -test("demo: deposit max after withdraw raw 13", (t) => { - const coinList: Coin[] = [ - [kudos`0.1`, 8], - [kudos`1`, 0], - [kudos`2`, 1], - [kudos`5`, 0], - [kudos`10`, 1], - ]; - const result = getMaxDepositAmountForAvailableCoins( - { - list: coinList.map(([v, t]) => defaultFeeConfig(v, t)), - exchanges: { - one: { - wireFee: kudos`0.01`, - purseFee: kudos`0.00`, - creditDeadline: AbsoluteTime.never(), - debitDeadline: AbsoluteTime.never(), - }, - }, - }, - "KUDOS", - ); - t.is(Amounts.stringifyValue(result.effective), "12.8"); - t.is(Amounts.stringifyValue(result.raw), "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 -}); |