wallet-core: use division for withdrawal coin selection
This commit is contained in:
parent
da87ce41a6
commit
ea953f2b77
@ -138,3 +138,13 @@ test("amount multiplication", (t) => {
|
||||
t.is(Amounts.stringify(Amounts.mult(sAmt("EUR:1.11"), 4).amount), "EUR:4.44");
|
||||
t.is(Amounts.stringify(Amounts.mult(sAmt("EUR:1.11"), 5).amount), "EUR:5.55");
|
||||
});
|
||||
|
||||
|
||||
|
||||
test("amount division", (t) => {
|
||||
t.is(Amounts.divmod("EUR:5", "EUR:1").quotient, 5);
|
||||
t.is(Amounts.stringify(Amounts.divmod("EUR:5", "EUR:1").remainder), "EUR:0");
|
||||
|
||||
t.is(Amounts.divmod("EUR:5", "EUR:2").quotient, 2);
|
||||
t.is(Amounts.stringify(Amounts.divmod("EUR:5", "EUR:2").remainder), "EUR:1");
|
||||
});
|
||||
|
@ -95,6 +95,11 @@ export interface Result {
|
||||
*/
|
||||
export type AmountLike = AmountString | AmountJson;
|
||||
|
||||
export interface DivmodResult {
|
||||
quotient: number;
|
||||
remainder: AmountJson;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class for dealing with amounts.
|
||||
*/
|
||||
@ -135,6 +140,29 @@ export class Amounts {
|
||||
return amt;
|
||||
}
|
||||
|
||||
static divmod(a1: AmountLike, a2: AmountLike): DivmodResult {
|
||||
const am1 = Amounts.jsonifyAmount(a1);
|
||||
const am2 = Amounts.jsonifyAmount(a2);
|
||||
if (am1.currency != am2.currency) {
|
||||
throw Error(`incompatible currency (${am1.currency} vs${am2.currency})`);
|
||||
}
|
||||
|
||||
const x1 = BigInt(am1.value) * BigInt(amountFractionalBase) + BigInt(am1.fraction);
|
||||
const x2 = BigInt(am2.value) * BigInt(amountFractionalBase) + BigInt(am2.fraction);
|
||||
|
||||
const quotient = x1 / x2;
|
||||
const remainderScaled = x1 % x2;
|
||||
|
||||
return {
|
||||
quotient: Number(quotient),
|
||||
remainder: {
|
||||
currency: am1.currency,
|
||||
value: Number(remainderScaled / BigInt(amountFractionalBase)),
|
||||
fraction: Number(remainderScaled % BigInt(amountFractionalBase))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static sum(amounts: AmountLike[]): Result {
|
||||
if (amounts.length <= 0) {
|
||||
throw Error("can't sum zero amounts");
|
||||
|
@ -689,18 +689,13 @@ export function selectWithdrawalDenominations(
|
||||
);
|
||||
|
||||
for (const d of denoms) {
|
||||
let count = 0;
|
||||
const cost = Amounts.add(
|
||||
DenominationRecord.getValue(d),
|
||||
d.fees.feeWithdraw,
|
||||
).amount;
|
||||
for (;;) {
|
||||
if (Amounts.cmp(remaining, cost) < 0) {
|
||||
break;
|
||||
}
|
||||
remaining = Amounts.sub(remaining, cost).amount;
|
||||
count++;
|
||||
}
|
||||
const res = Amounts.divmod(remaining, cost);
|
||||
const count = res.quotient;
|
||||
remaining = Amounts.sub(remaining, Amounts.mult(cost, count).amount).amount;
|
||||
if (count > 0) {
|
||||
totalCoinValue = Amounts.add(
|
||||
totalCoinValue,
|
||||
|
Loading…
Reference in New Issue
Block a user