2023-03-31 17:27:05 +02:00
|
|
|
/*
|
|
|
|
This file is part of GNU Taler
|
|
|
|
(C) 2022 Taler Systems S.A.
|
|
|
|
|
|
|
|
GNU Taler is free software; you can redistribute it and/or modify it under the
|
|
|
|
terms of the GNU General Public License as published by the Free Software
|
|
|
|
Foundation; either version 3, or (at your option) any later version.
|
|
|
|
|
|
|
|
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
|
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
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/>
|
|
|
|
*/
|
2023-06-15 18:07:31 +02:00
|
|
|
import {
|
|
|
|
AbsoluteTime,
|
|
|
|
AgeRestriction,
|
|
|
|
AmountJson,
|
|
|
|
Amounts,
|
|
|
|
Duration,
|
2023-06-16 14:40:45 +02:00
|
|
|
TransactionAmountMode,
|
2023-06-15 18:07:31 +02:00
|
|
|
} from "@gnu-taler/taler-util";
|
2023-06-20 19:30:02 +02:00
|
|
|
import test, { ExecutionContext } from "ava";
|
|
|
|
import {
|
|
|
|
CoinInfo,
|
|
|
|
convertDepositAmountForAvailableCoins,
|
|
|
|
convertWithdrawalAmountFromAvailableCoins,
|
|
|
|
getMaxDepositAmountForAvailableCoins,
|
|
|
|
} from "./coinSelection.js";
|
2023-03-31 17:27:05 +02:00
|
|
|
|
2023-06-20 19:30:02 +02:00
|
|
|
function makeCurrencyHelper(currency: string) {
|
|
|
|
return (sx: TemplateStringsArray, ...vx: any[]) => {
|
|
|
|
const s = String.raw({ raw: sx }, ...vx);
|
|
|
|
return Amounts.parseOrThrow(`${currency}:${s}`);
|
2023-03-31 17:27:05 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-06-20 19:30:02 +02:00
|
|
|
const kudos = makeCurrencyHelper("kudos");
|
2023-06-15 18:07:31 +02:00
|
|
|
|
2023-06-20 19:30:02 +02:00
|
|
|
function defaultFeeConfig(value: AmountJson, totalAvailable: number): CoinInfo {
|
2023-06-15 18:07:31 +02:00
|
|
|
return {
|
|
|
|
id: Amounts.stringify(value),
|
2023-06-20 19:30:02 +02:00
|
|
|
denomDeposit: kudos`0.01`,
|
|
|
|
denomRefresh: kudos`0.01`,
|
|
|
|
denomWithdraw: kudos`0.01`,
|
|
|
|
exchangeBaseUrl: "1",
|
2023-06-15 18:07:31 +02:00
|
|
|
duration: Duration.getForever(),
|
|
|
|
exchangePurse: undefined,
|
|
|
|
exchangeWire: undefined,
|
|
|
|
maxAge: AgeRestriction.AGE_UNRESTRICTED,
|
|
|
|
totalAvailable,
|
|
|
|
value,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
type Coin = [AmountJson, number];
|
|
|
|
|
|
|
|
/**
|
2023-06-20 19:30:02 +02:00
|
|
|
* Making a deposit with effective amount
|
2023-06-15 18:07:31 +02:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2023-06-20 19:30:02 +02:00
|
|
|
test("deposit effective 2", (t) => {
|
2023-06-15 18:07:31 +02:00
|
|
|
const coinList: Coin[] = [
|
2023-06-20 19:30:02 +02:00
|
|
|
[kudos`2`, 5],
|
|
|
|
[kudos`5`, 5],
|
2023-06-15 18:07:31 +02:00
|
|
|
];
|
2023-06-20 19:30:02 +02:00
|
|
|
const result = convertDepositAmountForAvailableCoins(
|
2023-06-16 14:40:45 +02:00
|
|
|
{
|
|
|
|
list: coinList.map(([v, t]) => defaultFeeConfig(v, t)),
|
|
|
|
exchanges: {},
|
|
|
|
},
|
2023-06-20 19:30:02 +02:00
|
|
|
kudos`2`,
|
|
|
|
TransactionAmountMode.Effective,
|
2023-06-16 14:40:45 +02:00
|
|
|
);
|
2023-06-20 19:30:02 +02:00
|
|
|
t.is(Amounts.stringifyValue(result.effective), "2");
|
|
|
|
t.is(Amounts.stringifyValue(result.raw), "1.99");
|
2023-06-15 18:07:31 +02:00
|
|
|
});
|
|
|
|
|
2023-06-20 19:30:02 +02:00
|
|
|
test("deposit effective 10", (t) => {
|
2023-06-15 18:07:31 +02:00
|
|
|
const coinList: Coin[] = [
|
2023-06-20 19:30:02 +02:00
|
|
|
[kudos`2`, 5],
|
|
|
|
[kudos`5`, 5],
|
2023-06-15 18:07:31 +02:00
|
|
|
];
|
2023-06-20 19:30:02 +02:00
|
|
|
const result = convertDepositAmountForAvailableCoins(
|
2023-06-16 14:40:45 +02:00
|
|
|
{
|
|
|
|
list: coinList.map(([v, t]) => defaultFeeConfig(v, t)),
|
|
|
|
exchanges: {},
|
|
|
|
},
|
2023-06-20 19:30:02 +02:00
|
|
|
kudos`10`,
|
|
|
|
TransactionAmountMode.Effective,
|
2023-06-16 14:40:45 +02:00
|
|
|
);
|
2023-06-20 19:30:02 +02:00
|
|
|
t.is(Amounts.stringifyValue(result.effective), "10");
|
|
|
|
t.is(Amounts.stringifyValue(result.raw), "9.98");
|
|
|
|
});
|
2023-06-15 18:07:31 +02:00
|
|
|
|
2023-06-20 19:30:02 +02:00
|
|
|
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");
|
2023-06-15 18:07:31 +02:00
|
|
|
});
|
|
|
|
|
2023-06-20 19:30:02 +02:00
|
|
|
test("deposit effective 40", (t) => {
|
2023-06-16 14:50:19 +02:00
|
|
|
const coinList: Coin[] = [
|
2023-06-20 19:30:02 +02:00
|
|
|
[kudos`2`, 5],
|
|
|
|
[kudos`5`, 5],
|
2023-06-16 14:50:19 +02:00
|
|
|
];
|
2023-06-20 19:30:02 +02:00
|
|
|
const result = convertDepositAmountForAvailableCoins(
|
2023-06-16 14:50:19 +02:00
|
|
|
{
|
|
|
|
list: coinList.map(([v, t]) => defaultFeeConfig(v, t)),
|
|
|
|
exchanges: {},
|
|
|
|
},
|
2023-06-20 19:30:02 +02:00
|
|
|
kudos`40`,
|
|
|
|
TransactionAmountMode.Effective,
|
2023-06-16 14:50:19 +02:00
|
|
|
);
|
2023-06-20 19:30:02 +02:00
|
|
|
t.is(Amounts.stringifyValue(result.effective), "35");
|
|
|
|
t.is(Amounts.stringifyValue(result.raw), "34.9");
|
|
|
|
});
|
2023-06-16 14:50:19 +02:00
|
|
|
|
2023-06-20 19:30:02 +02:00
|
|
|
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");
|
2023-06-16 14:50:19 +02:00
|
|
|
});
|
|
|
|
|
2023-06-20 19:30:02 +02:00
|
|
|
/**
|
|
|
|
* Making a deposit with raw amount, using the result from effective
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
test("deposit raw 1.99 (effective 2)", (t) => {
|
2023-06-15 18:07:31 +02:00
|
|
|
const coinList: Coin[] = [
|
2023-06-20 19:30:02 +02:00
|
|
|
[kudos`2`, 5],
|
|
|
|
[kudos`5`, 5],
|
2023-06-15 18:07:31 +02:00
|
|
|
];
|
2023-06-20 19:30:02 +02:00
|
|
|
const result = convertDepositAmountForAvailableCoins(
|
2023-06-16 14:40:45 +02:00
|
|
|
{
|
|
|
|
list: coinList.map(([v, t]) => defaultFeeConfig(v, t)),
|
|
|
|
exchanges: {},
|
|
|
|
},
|
2023-06-20 19:30:02 +02:00
|
|
|
kudos`1.99`,
|
|
|
|
TransactionAmountMode.Raw,
|
2023-06-16 14:40:45 +02:00
|
|
|
);
|
2023-06-20 19:30:02 +02:00
|
|
|
t.is(Amounts.stringifyValue(result.effective), "2");
|
|
|
|
t.is(Amounts.stringifyValue(result.raw), "1.99");
|
2023-06-15 18:07:31 +02:00
|
|
|
});
|
|
|
|
|
2023-06-20 19:30:02 +02:00
|
|
|
test("deposit raw 9.98 (effective 10)", (t) => {
|
2023-06-15 18:07:31 +02:00
|
|
|
const coinList: Coin[] = [
|
2023-06-20 19:30:02 +02:00
|
|
|
[kudos`2`, 5],
|
|
|
|
[kudos`5`, 5],
|
2023-06-15 18:07:31 +02:00
|
|
|
];
|
2023-06-20 19:30:02 +02:00
|
|
|
const result = convertDepositAmountForAvailableCoins(
|
2023-06-16 14:40:45 +02:00
|
|
|
{
|
|
|
|
list: coinList.map(([v, t]) => defaultFeeConfig(v, t)),
|
|
|
|
exchanges: {},
|
|
|
|
},
|
2023-06-20 19:30:02 +02:00
|
|
|
kudos`9.98`,
|
|
|
|
TransactionAmountMode.Raw,
|
2023-06-16 14:40:45 +02:00
|
|
|
);
|
2023-06-20 19:30:02 +02:00
|
|
|
t.is(Amounts.stringifyValue(result.effective), "10");
|
|
|
|
t.is(Amounts.stringifyValue(result.raw), "9.98");
|
|
|
|
});
|
2023-06-15 18:07:31 +02:00
|
|
|
|
2023-06-20 19:30:02 +02:00
|
|
|
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");
|
2023-06-15 18:07:31 +02:00
|
|
|
});
|
|
|
|
|
2023-06-20 19:30:02 +02:00
|
|
|
test("deposit raw 34.9 (effective 40)", (t) => {
|
2023-06-15 18:07:31 +02:00
|
|
|
const coinList: Coin[] = [
|
2023-06-20 19:30:02 +02:00
|
|
|
[kudos`2`, 5],
|
|
|
|
[kudos`5`, 5],
|
2023-06-15 18:07:31 +02:00
|
|
|
];
|
2023-06-20 19:30:02 +02:00
|
|
|
const result = convertDepositAmountForAvailableCoins(
|
2023-06-16 14:40:45 +02:00
|
|
|
{
|
|
|
|
list: coinList.map(([v, t]) => defaultFeeConfig(v, t)),
|
|
|
|
exchanges: {},
|
|
|
|
},
|
2023-06-20 19:30:02 +02:00
|
|
|
kudos`34.9`,
|
|
|
|
TransactionAmountMode.Raw,
|
2023-06-16 14:40:45 +02:00
|
|
|
);
|
2023-06-20 19:30:02 +02:00
|
|
|
t.is(Amounts.stringifyValue(result.effective), "35");
|
|
|
|
t.is(Amounts.stringifyValue(result.raw), "34.9");
|
|
|
|
});
|
2023-06-15 18:07:31 +02:00
|
|
|
|
2023-06-20 19:30:02 +02:00
|
|
|
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");
|
2023-06-15 18:07:31 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
/**
|
2023-06-20 19:30:02 +02:00
|
|
|
* Calculating the max amount possible to deposit
|
2023-06-15 18:07:31 +02:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2023-06-20 19:30:02 +02:00
|
|
|
test("deposit max 35", (t) => {
|
2023-06-15 18:07:31 +02:00
|
|
|
const coinList: Coin[] = [
|
2023-06-20 19:30:02 +02:00
|
|
|
[kudos`2`, 5],
|
|
|
|
[kudos`5`, 5],
|
2023-06-15 18:07:31 +02:00
|
|
|
];
|
2023-06-20 19:30:02 +02:00
|
|
|
const result = getMaxDepositAmountForAvailableCoins(
|
2023-06-15 18:07:31 +02:00
|
|
|
{
|
|
|
|
list: coinList.map(([v, t]) => defaultFeeConfig(v, t)),
|
|
|
|
exchanges: {
|
|
|
|
"2": {
|
2023-06-20 19:30:02 +02:00
|
|
|
wireFee: kudos`0.00`,
|
|
|
|
purseFee: kudos`0.00`,
|
2023-06-15 18:07:31 +02:00
|
|
|
creditDeadline: AbsoluteTime.never(),
|
|
|
|
debitDeadline: AbsoluteTime.never(),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2023-06-20 19:30:02 +02:00
|
|
|
"KUDOS",
|
2023-06-15 18:07:31 +02:00
|
|
|
);
|
2023-06-20 19:30:02 +02:00
|
|
|
t.is(Amounts.stringifyValue(result.raw), "34.9");
|
|
|
|
t.is(Amounts.stringifyValue(result.effective), "35");
|
2023-06-15 18:07:31 +02:00
|
|
|
});
|
|
|
|
|
2023-06-20 19:30:02 +02:00
|
|
|
test("deposit max 35 with wirefee", (t) => {
|
2023-06-15 18:07:31 +02:00
|
|
|
const coinList: Coin[] = [
|
2023-06-20 19:30:02 +02:00
|
|
|
[kudos`2`, 5],
|
|
|
|
[kudos`5`, 5],
|
2023-06-15 18:07:31 +02:00
|
|
|
];
|
2023-06-20 19:30:02 +02:00
|
|
|
const result = getMaxDepositAmountForAvailableCoins(
|
2023-06-15 18:07:31 +02:00
|
|
|
{
|
|
|
|
list: coinList.map(([v, t]) => defaultFeeConfig(v, t)),
|
|
|
|
exchanges: {
|
|
|
|
"2": {
|
2023-06-20 19:30:02 +02:00
|
|
|
wireFee: kudos`1`,
|
|
|
|
purseFee: kudos`0.00`,
|
2023-06-15 18:07:31 +02:00
|
|
|
creditDeadline: AbsoluteTime.never(),
|
|
|
|
debitDeadline: AbsoluteTime.never(),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2023-06-20 19:30:02 +02:00
|
|
|
"KUDOS",
|
2023-06-15 18:07:31 +02:00
|
|
|
);
|
2023-06-20 19:30:02 +02:00
|
|
|
t.is(Amounts.stringifyValue(result.raw), "33.9");
|
|
|
|
t.is(Amounts.stringifyValue(result.effective), "35");
|
2023-06-15 18:07:31 +02:00
|
|
|
});
|
|
|
|
|
2023-06-20 19:30:02 +02:00
|
|
|
test("deposit max repeated denom", (t) => {
|
2023-06-15 18:07:31 +02:00
|
|
|
const coinList: Coin[] = [
|
2023-06-20 19:30:02 +02:00
|
|
|
[kudos`2`, 1],
|
|
|
|
[kudos`2`, 1],
|
|
|
|
[kudos`5`, 1],
|
2023-06-15 18:07:31 +02:00
|
|
|
];
|
2023-06-20 19:30:02 +02:00
|
|
|
const result = getMaxDepositAmountForAvailableCoins(
|
2023-06-15 18:07:31 +02:00
|
|
|
{
|
|
|
|
list: coinList.map(([v, t]) => defaultFeeConfig(v, t)),
|
|
|
|
exchanges: {
|
|
|
|
"2": {
|
2023-06-20 19:30:02 +02:00
|
|
|
wireFee: kudos`0.00`,
|
|
|
|
purseFee: kudos`0.00`,
|
2023-06-15 18:07:31 +02:00
|
|
|
creditDeadline: AbsoluteTime.never(),
|
|
|
|
debitDeadline: AbsoluteTime.never(),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2023-06-20 19:30:02 +02:00
|
|
|
"KUDOS",
|
2023-06-15 18:07:31 +02:00
|
|
|
);
|
2023-06-20 19:30:02 +02:00
|
|
|
t.is(Amounts.stringifyValue(result.raw), "8.97");
|
|
|
|
t.is(Amounts.stringifyValue(result.effective), "9");
|
|
|
|
});
|
2023-06-15 18:07:31 +02:00
|
|
|
|
2023-06-20 19:30:02 +02:00
|
|
|
/**
|
|
|
|
* 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");
|
2023-03-31 17:27:05 +02:00
|
|
|
});
|
2023-06-16 14:50:19 +02:00
|
|
|
|
2023-06-20 19:30:02 +02:00
|
|
|
test("withdraw effective 40", (t) => {
|
2023-06-16 14:50:19 +02:00
|
|
|
const coinList: Coin[] = [
|
2023-06-20 19:30:02 +02:00
|
|
|
[kudos`2`, 5],
|
|
|
|
[kudos`5`, 5],
|
2023-06-16 14:50:19 +02:00
|
|
|
];
|
2023-06-20 19:30:02 +02:00
|
|
|
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`,
|
2023-06-16 14:50:19 +02:00
|
|
|
TransactionAmountMode.Raw,
|
2023-06-20 19:30:02 +02:00
|
|
|
);
|
|
|
|
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(
|
2023-06-16 14:50:19 +02:00
|
|
|
{
|
|
|
|
list: coinList.map(([v, t]) => defaultFeeConfig(v, t)),
|
2023-06-20 19:30:02 +02:00
|
|
|
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: {},
|
2023-06-16 14:50:19 +02:00
|
|
|
},
|
2023-06-20 19:30:02 +02:00
|
|
|
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,
|
2023-06-16 14:50:19 +02:00
|
|
|
);
|
2023-06-20 19:30:02 +02:00
|
|
|
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
|
2023-06-16 14:50:19 +02:00
|
|
|
|
2023-06-20 19:30:02 +02:00
|
|
|
//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]]);
|
2023-06-16 14:50:19 +02:00
|
|
|
});
|
2023-06-20 19:30:02 +02:00
|
|
|
|
|
|
|
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];
|
|
|
|
});
|
|
|
|
}
|
2023-06-20 22:50:07 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
});
|