aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core/src/util/coinSelection.test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-core/src/util/coinSelection.test.ts')
-rw-r--r--packages/taler-wallet-core/src/util/coinSelection.test.ts614
1 files changed, 471 insertions, 143 deletions
diff --git a/packages/taler-wallet-core/src/util/coinSelection.test.ts b/packages/taler-wallet-core/src/util/coinSelection.test.ts
index ab3b2c4f8..3073b69c7 100644
--- a/packages/taler-wallet-core/src/util/coinSelection.test.ts
+++ b/packages/taler-wallet-core/src/util/coinSelection.test.ts
@@ -13,13 +13,6 @@
You should have received a copy of the GNU General Public License along with
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import test, { ExecutionContext } from "ava";
-import {
- AmountMode,
- OperationType,
- calculatePlanFormAvailableCoins,
- selectCoinForOperation,
-} from "./coinSelection.js";
import {
AbsoluteTime,
AgeRestriction,
@@ -27,28 +20,31 @@ import {
Amounts,
Duration,
TransactionAmountMode,
- TransactionType,
} from "@gnu-taler/taler-util";
+import test, { ExecutionContext } from "ava";
+import {
+ CoinInfo,
+ convertDepositAmountForAvailableCoins,
+ convertWithdrawalAmountFromAvailableCoins,
+ getMaxDepositAmountForAvailableCoins,
+} from "./coinSelection.js";
-function expect(t: ExecutionContext, thing: any): any {
- return {
- deep: {
- equal: (another: any) => t.deepEqual(thing, another),
- equals: (another: any) => t.deepEqual(thing, another),
- },
+function makeCurrencyHelper(currency: string) {
+ return (sx: TemplateStringsArray, ...vx: any[]) => {
+ const s = String.raw({ raw: sx }, ...vx);
+ return Amounts.parseOrThrow(`${currency}:${s}`);
};
}
-function kudos(v: number): AmountJson {
- return Amounts.fromFloat(v, "KUDOS");
-}
+const kudos = makeCurrencyHelper("kudos");
-function defaultFeeConfig(value: AmountJson, totalAvailable: number) {
+function defaultFeeConfig(value: AmountJson, totalAvailable: number): CoinInfo {
return {
id: Amounts.stringify(value),
- denomDeposit: kudos(0.01),
- denomRefresh: kudos(0.01),
- denomWithdraw: kudos(0.01),
+ denomDeposit: kudos`0.01`,
+ denomRefresh: kudos`0.01`,
+ denomWithdraw: kudos`0.01`,
+ exchangeBaseUrl: "1",
duration: Duration.getForever(),
exchangePurse: undefined,
exchangeWire: undefined,
@@ -60,242 +56,574 @@ function defaultFeeConfig(value: AmountJson, totalAvailable: number) {
type Coin = [AmountJson, number];
/**
- * selectCoinForOperation test
+ * Making a deposit with effective amount
*
- * Test here should check that the correct coins are selected
*/
-test("get effective 2", (t) => {
+test("deposit effective 2", (t) => {
const coinList: Coin[] = [
- [kudos(2), 5],
- [kudos(5), 5],
+ [kudos`2`, 5],
+ [kudos`5`, 5],
];
- const result = selectCoinForOperation(
- OperationType.Credit,
- kudos(2),
- AmountMode.Net,
+ const result = convertDepositAmountForAvailableCoins(
{
list: coinList.map(([v, t]) => defaultFeeConfig(v, t)),
exchanges: {},
},
+ kudos`2`,
+ TransactionAmountMode.Effective,
);
- expect(t, result.coins).deep.equal(["KUDOS:2"]);
- t.assert(result.refresh === undefined);
+ t.is(Amounts.stringifyValue(result.effective), "2");
+ t.is(Amounts.stringifyValue(result.raw), "1.99");
});
-test("get raw 4", (t) => {
+test("deposit effective 10", (t) => {
const coinList: Coin[] = [
- [kudos(2), 5],
- [kudos(5), 5],
+ [kudos`2`, 5],
+ [kudos`5`, 5],
];
- const result = selectCoinForOperation(
- OperationType.Credit,
- kudos(4),
- AmountMode.Gross,
+ 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");
+});
- expect(t, result.coins).deep.equal(["KUDOS:2", "KUDOS:2"]);
- t.assert(result.refresh === undefined);
+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("get raw 25, diff with demo ", (t) => {
+test("deposit effective 40", (t) => {
const coinList: Coin[] = [
- [kudos(0.1), 0],
- [kudos(1), 0],
- [kudos(2), 0],
- [kudos(5), 0],
- [kudos(10), 0],
+ [kudos`2`, 5],
+ [kudos`5`, 5],
];
- const result = selectCoinForOperation(
- OperationType.Credit,
- kudos(25),
- AmountMode.Gross,
+ 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");
+});
- expect(t, result.coins).deep.equal(["KUDOS:10", "KUDOS:10", "KUDOS:5"]);
- t.assert(result.refresh === undefined);
+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");
});
-test("send effective 6", (t) => {
+/**
+ * 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],
+ [kudos`2`, 5],
+ [kudos`5`, 5],
];
- const result = selectCoinForOperation(
- OperationType.Debit,
- kudos(6),
- AmountMode.Gross,
+ const result = convertDepositAmountForAvailableCoins(
{
list: coinList.map(([v, t]) => defaultFeeConfig(v, t)),
exchanges: {},
},
+ kudos`1.99`,
+ TransactionAmountMode.Raw,
);
-
- expect(t, result.coins).deep.equal(["KUDOS:5"]);
- t.assert(result.refresh?.selected === "KUDOS:2");
+ t.is(Amounts.stringifyValue(result.effective), "2");
+ t.is(Amounts.stringifyValue(result.raw), "1.99");
});
-test("send raw 6", (t) => {
+test("deposit raw 9.98 (effective 10)", (t) => {
const coinList: Coin[] = [
- [kudos(2), 5],
- [kudos(5), 5],
+ [kudos`2`, 5],
+ [kudos`5`, 5],
];
- const result = selectCoinForOperation(
- OperationType.Debit,
- kudos(6),
- AmountMode.Gross,
+ 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");
+});
- expect(t, result.coins).deep.equal(["KUDOS:5"]);
- t.assert(result.refresh?.selected === "KUDOS:2");
+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("send raw 20 (not enough)", (t) => {
+test("deposit raw 34.9 (effective 40)", (t) => {
const coinList: Coin[] = [
- [kudos(2), 1],
- [kudos(5), 2],
+ [kudos`2`, 5],
+ [kudos`5`, 5],
];
- const result = selectCoinForOperation(
- OperationType.Debit,
- kudos(20),
- AmountMode.Gross,
+ 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");
+});
- expect(t, result.coins).deep.equal(["KUDOS:5", "KUDOS:5", "KUDOS:2"]);
- t.assert(result.refresh === undefined);
+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");
});
/**
- * calculatePlanFormAvailableCoins test
+ * Calculating the max amount possible to deposit
*
- * Test here should check that the plan summary for a transaction is correct
- * * effective amount
- * * raw amount
*/
-test("deposit effective 2 ", (t) => {
+test("deposit max 35", (t) => {
const coinList: Coin[] = [
- [kudos(2), 1],
- [kudos(5), 2],
+ [kudos`2`, 5],
+ [kudos`5`, 5],
];
- const result = calculatePlanFormAvailableCoins(
- TransactionType.Deposit,
- kudos(2),
- TransactionAmountMode.Effective,
+ 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(),
- wireFee: kudos(0.01),
- purseFee: kudos(0.01),
},
},
},
+ "KUDOS",
);
-
- t.deepEqual(result.rawAmount, "KUDOS:1.98");
- t.deepEqual(result.effectiveAmount, "KUDOS:2");
+ t.is(Amounts.stringifyValue(result.raw), "34.9");
+ t.is(Amounts.stringifyValue(result.effective), "35");
});
-test("deposit raw 2 ", (t) => {
+test("deposit max 35 with wirefee", (t) => {
const coinList: Coin[] = [
- [kudos(2), 1],
- [kudos(5), 2],
+ [kudos`2`, 5],
+ [kudos`5`, 5],
];
- const result = calculatePlanFormAvailableCoins(
- TransactionType.Deposit,
- kudos(2),
- TransactionAmountMode.Raw,
+ 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(),
- wireFee: kudos(0.01),
- purseFee: kudos(0.01),
},
},
},
+ "KUDOS",
);
-
- t.deepEqual(result.rawAmount, "KUDOS:2");
- t.deepEqual(result.effectiveAmount, "KUDOS:2.04");
+ t.is(Amounts.stringifyValue(result.raw), "33.9");
+ t.is(Amounts.stringifyValue(result.effective), "35");
});
-test("withdraw raw 21 ", (t) => {
+test("deposit max repeated denom", (t) => {
const coinList: Coin[] = [
- [kudos(2), 1],
- [kudos(5), 2],
+ [kudos`2`, 1],
+ [kudos`2`, 1],
+ [kudos`5`, 1],
];
- const result = calculatePlanFormAvailableCoins(
- TransactionType.Withdrawal,
- kudos(21),
- TransactionAmountMode.Raw,
+ 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(),
- wireFee: kudos(0.01),
- purseFee: kudos(0.01),
},
},
},
+ "KUDOS",
);
+ t.is(Amounts.stringifyValue(result.raw), "8.97");
+ t.is(Amounts.stringifyValue(result.effective), "9");
+});
- // denominations configuration is not suitable
- // for greedy algorithm
- t.deepEqual(result.rawAmount, "KUDOS:20");
- t.deepEqual(result.effectiveAmount, "KUDOS:19.96");
+/**
+ * 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 raw 25, diff with demo ", (t) => {
+test("withdraw effective 40", (t) => {
const coinList: Coin[] = [
- [kudos(0.1), 0],
- [kudos(1), 0],
- [kudos(2), 0],
- [kudos(5), 0],
- [kudos(10), 0],
+ [kudos`2`, 5],
+ [kudos`5`, 5],
];
- const result = calculatePlanFormAvailableCoins(
- TransactionType.Withdrawal,
- kudos(25),
+ 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: {
- "2": {
- creditDeadline: AbsoluteTime.never(),
- debitDeadline: AbsoluteTime.never(),
- wireFee: kudos(0.01),
- purseFee: kudos(0.01),
- },
- },
+ 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
- t.deepEqual(result.rawAmount, "KUDOS:25");
- // here demo report KUDOS:0.2 fee
- // t.deepEqual(result.effectiveAmount, "KUDOS:24.80");
- t.deepEqual(result.effectiveAmount, "KUDOS:24.97");
+ //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];
+ });
+}