aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core/src/util/coinSelection.test.ts
diff options
context:
space:
mode:
authorÖzgür Kesim <oec-taler@kesim.org>2023-09-14 12:13:35 +0200
committerÖzgür Kesim <oec-taler@kesim.org>2023-09-14 12:13:35 +0200
commit35611f0bf9cf67638b171c2a300fab1797d3d8f0 (patch)
treed067d5d62ac2fd0d88b25d2c759cc2caa9485c00 /packages/taler-wallet-core/src/util/coinSelection.test.ts
parent64c19c8cde56699ab4aaf05a1ac6fea6a4e0e4ba (diff)
parenta5960665245c4ffb625dd16923019e8c62c20159 (diff)
Merge branch 'master' into age-withdraw
Diffstat (limited to 'packages/taler-wallet-core/src/util/coinSelection.test.ts')
-rw-r--r--packages/taler-wallet-core/src/util/coinSelection.test.ts156
1 files changed, 156 insertions, 0 deletions
diff --git a/packages/taler-wallet-core/src/util/coinSelection.test.ts b/packages/taler-wallet-core/src/util/coinSelection.test.ts
index b907eb160..2a322c4a9 100644
--- a/packages/taler-wallet-core/src/util/coinSelection.test.ts
+++ b/packages/taler-wallet-core/src/util/coinSelection.test.ts
@@ -17,9 +17,165 @@ import {
AbsoluteTime,
AgeRestriction,
AmountJson,
+ AmountString,
Amounts,
+ DenomKeyType,
Duration,
TransactionAmountMode,
} from "@gnu-taler/taler-util";
import test, { ExecutionContext } from "ava";
+import { AvailableDenom, testing_greedySelectPeer } from "./coinSelection.js"
+type Tester<T> = {
+ deep: {
+ equal(another: T): ReturnType<ExecutionContext["deepEqual"]>;
+ equals(another: T): ReturnType<ExecutionContext["deepEqual"]>;
+ }
+}
+
+function expect<T>(t: ExecutionContext, thing: T): Tester<T> {
+ return {
+ deep: {
+ equal: (another: T) => t.deepEqual(thing, another),
+ equals: (another: T) => t.deepEqual(thing, another),
+ },
+ };
+}
+
+const inTheDistantFuture = AbsoluteTime.toProtocolTimestamp(
+ AbsoluteTime.addDuration(AbsoluteTime.now(), Duration.fromSpec({ hours: 1 }))
+)
+const inThePast = AbsoluteTime.toProtocolTimestamp(
+ AbsoluteTime.subtractDuraction(AbsoluteTime.now(), Duration.fromSpec({ hours: 1 }))
+)
+
+test("should select the coin", (t) => {
+ const instructedAmount = Amounts.parseOrThrow("LOCAL:2")
+ const tally = {
+ amountAcc: Amounts.zeroOfCurrency(instructedAmount.currency),
+ depositFeesAcc: Amounts.zeroOfCurrency(instructedAmount.currency),
+ lastDepositFee: Amounts.zeroOfCurrency(instructedAmount.currency),
+ };
+ const coins = testing_greedySelectPeer(
+ createCandidates([{
+ amount: "LOCAL:10",
+ numAvailable: 5,
+ depositFee: "LOCAL:0.1",
+ fromExchange: "http://exchange.localhost/",
+ }]),
+ instructedAmount,
+ tally
+ );
+
+ expect(t, coins).deep.equal({
+ "hash0;32;http://exchange.localhost/": {
+ exchangeBaseUrl: "http://exchange.localhost/",
+ denomPubHash: "hash0",
+ maxAge: 32,
+ contributions: [Amounts.parseOrThrow("LOCAL:2")],
+ }
+ });
+
+ expect(t, tally).deep.equal({
+ amountAcc: Amounts.parseOrThrow("LOCAL:2"),
+ depositFeesAcc: Amounts.parseOrThrow("LOCAL:0.1"),
+ lastDepositFee: Amounts.parseOrThrow("LOCAL:0.1"),
+ });
+
+});
+
+test("should select 3 coins", (t) => {
+ const instructedAmount = Amounts.parseOrThrow("LOCAL:20")
+ const tally = {
+ amountAcc: Amounts.zeroOfCurrency(instructedAmount.currency),
+ depositFeesAcc: Amounts.zeroOfCurrency(instructedAmount.currency),
+ lastDepositFee: Amounts.zeroOfCurrency(instructedAmount.currency),
+ };
+ const coins = testing_greedySelectPeer(
+ createCandidates([{
+ amount: "LOCAL:10",
+ numAvailable: 5,
+ depositFee: "LOCAL:0.1",
+ fromExchange: "http://exchange.localhost/",
+ }]),
+ instructedAmount,
+ tally
+ );
+
+ expect(t, coins).deep.equal({
+ "hash0;32;http://exchange.localhost/": {
+ exchangeBaseUrl: "http://exchange.localhost/",
+ denomPubHash: "hash0",
+ maxAge: 32,
+ contributions: [
+ Amounts.parseOrThrow("LOCAL:9.9"),
+ Amounts.parseOrThrow("LOCAL:9.9"),
+ Amounts.parseOrThrow("LOCAL:0.2")
+ ],
+ }
+ });
+
+ expect(t, tally).deep.equal({
+ amountAcc: Amounts.parseOrThrow("LOCAL:20"),
+ depositFeesAcc: Amounts.parseOrThrow("LOCAL:0.3"),
+ lastDepositFee: Amounts.parseOrThrow("LOCAL:0.1"),
+ });
+
+});
+
+test("can't select since the instructed amount is too high", (t) => {
+ const instructedAmount = Amounts.parseOrThrow("LOCAL:60")
+ const tally = {
+ amountAcc: Amounts.zeroOfCurrency(instructedAmount.currency),
+ depositFeesAcc: Amounts.zeroOfCurrency(instructedAmount.currency),
+ lastDepositFee: Amounts.zeroOfCurrency(instructedAmount.currency),
+ };
+ const coins = testing_greedySelectPeer(
+ createCandidates([{
+ amount: "LOCAL:10",
+ numAvailable: 5,
+ depositFee: "LOCAL:0.1",
+ fromExchange: "http://exchange.localhost/",
+ }]),
+ instructedAmount,
+ tally
+ );
+
+ expect(t, coins).deep.equal(undefined);
+
+ expect(t, tally).deep.equal({
+ amountAcc: Amounts.parseOrThrow("LOCAL:49.5"),
+ depositFeesAcc: Amounts.parseOrThrow("LOCAL:0.5"),
+ lastDepositFee: Amounts.parseOrThrow("LOCAL:0.1"),
+ });
+
+});
+
+
+
+
+function createCandidates(ar: {amount: AmountString, depositFee: AmountString, numAvailable: number, fromExchange: string}[]): AvailableDenom[] {
+ return ar.map((r,idx) => {
+ return {
+ "denomPub": {
+ "age_mask": 0,
+ "cipher": DenomKeyType.Rsa,
+ "rsa_public_key": "PPP"
+ },
+ "denomPubHash": `hash${idx}`,
+ "value": r.amount,
+ "feeDeposit": r.depositFee,
+ "feeRefresh": "LOCAL:0",
+ "feeRefund": "LOCAL:0",
+ "feeWithdraw": "LOCAL:0",
+ "stampExpireDeposit": inTheDistantFuture,
+ "stampExpireLegal": inTheDistantFuture,
+ "stampExpireWithdraw": inTheDistantFuture,
+ "stampStart": inThePast,
+ "exchangeBaseUrl": r.fromExchange,
+ "numAvailable": r.numAvailable,
+ "maxAge": 32,
+
+ }
+ })
+}