summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core/src/coinSelection.ts
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2024-03-07 11:10:52 +0100
committerFlorian Dold <florian@dold.me>2024-03-07 11:10:52 +0100
commit466e2b7643692aa6b7f76a193b84775008e17350 (patch)
treedd3f9a0b67765e2c7ea6b97c2a7acbbcac71d4b7 /packages/taler-wallet-core/src/coinSelection.ts
parent8eb3e505be967afde0053d5a392e8c6877d8f1dd (diff)
downloadwallet-core-466e2b7643692aa6b7f76a193b84775008e17350.tar.gz
wallet-core-466e2b7643692aa6b7f76a193b84775008e17350.tar.bz2
wallet-core-466e2b7643692aa6b7f76a193b84775008e17350.zip
wallet-core: improve insufficient balance reporting
Diffstat (limited to 'packages/taler-wallet-core/src/coinSelection.ts')
-rw-r--r--packages/taler-wallet-core/src/coinSelection.ts114
1 files changed, 37 insertions, 77 deletions
diff --git a/packages/taler-wallet-core/src/coinSelection.ts b/packages/taler-wallet-core/src/coinSelection.ts
index 5ac52e1d3..695be79ac 100644
--- a/packages/taler-wallet-core/src/coinSelection.ts
+++ b/packages/taler-wallet-core/src/coinSelection.ts
@@ -42,15 +42,12 @@ import {
Logger,
parsePaytoUri,
PayCoinSelection,
- PayMerchantInsufficientBalanceDetails,
+ PaymentInsufficientBalanceDetails,
SelectedCoin,
strcmp,
TalerProtocolTimestamp,
} from "@gnu-taler/taler-util";
-import {
- getExchangePaymentBalanceDetailsInTx,
- getMerchantPaymentBalanceDetailsInTx,
-} from "./balance.js";
+import { getPaymentBalanceDetailsInTx } from "./balance.js";
import { getAutoRefreshExecuteThreshold } from "./common.js";
import { DenominationRecord, WalletDbReadOnlyTransaction } from "./db.js";
import {
@@ -171,7 +168,7 @@ function tallyFees(
export type SelectPayCoinsResult =
| {
type: "failure";
- insufficientBalanceDetails: PayMerchantInsufficientBalanceDetails;
+ insufficientBalanceDetails: PaymentInsufficientBalanceDetails;
}
| { type: "success"; coinSel: PayCoinSelection };
@@ -264,6 +261,7 @@ export async function selectPayCoins(
instructedAmount: req.contractTermsAmount,
requiredMinimumAge: req.requiredMinimumAge,
wireMethod: req.restrictWireMethod,
+ depositPaytoUri: req.depositPaytoUri,
},
),
} satisfies SelectPayCoinsResult;
@@ -273,7 +271,6 @@ export async function selectPayCoins(
tx,
selectedDenom,
coinRes,
- req.contractTermsAmount,
tally,
);
@@ -334,7 +331,6 @@ async function assembleSelectPayCoinsSuccessResult(
tx: WalletDbReadOnlyTransaction<["coins"]>,
finalSel: SelResult,
coinRes: SelectedCoin[],
- contractTermsAmount: AmountJson,
tally: CoinSelectionTally,
): Promise<PayCoinSelection> {
for (const dph of Object.keys(finalSel)) {
@@ -378,6 +374,7 @@ interface ReportInsufficientBalanceRequest {
requiredMinimumAge: number | undefined;
restrictExchanges: ExchangeRestrictionSpec | undefined;
wireMethod: string | undefined;
+ depositPaytoUri: string | undefined;
}
export async function reportInsufficientBalanceDetails(
@@ -392,82 +389,42 @@ export async function reportInsufficientBalanceDetails(
]
>,
req: ReportInsufficientBalanceRequest,
-): Promise<PayMerchantInsufficientBalanceDetails> {
- const currency = Amounts.currencyOf(req.instructedAmount);
- const details = await getMerchantPaymentBalanceDetailsInTx(wex, tx, {
+): Promise<PaymentInsufficientBalanceDetails> {
+ const details = await getPaymentBalanceDetailsInTx(wex, tx, {
restrictExchanges: req.restrictExchanges,
restrictWireMethods: req.wireMethod ? [req.wireMethod] : [],
currency: Amounts.currencyOf(req.instructedAmount),
minAge: req.requiredMinimumAge ?? 0,
+ depositPaytoUri: req.depositPaytoUri,
});
- let feeGapEstimate: AmountJson;
-
- // FIXME: need fee gap estimate
- // FIXME: We can probably give a better estimate.
- // feeGapEstimate = Amounts.add(
- // tally.amountPayRemaining,
- // tally.lastDepositFee,
- // ).amount;
-
- feeGapEstimate = Amounts.zeroOfAmount(req.instructedAmount);
-
- const perExchange: PayMerchantInsufficientBalanceDetails["perExchange"] = {};
-
- const exchanges = await tx.exchanges.iter().toArray();
-
- let maxEffectiveSpendAmount = Amounts.zeroOfAmount(req.instructedAmount);
+ const perExchange: PaymentInsufficientBalanceDetails["perExchange"] = {};
+ const exchanges = await tx.exchanges.getAll();
for (const exch of exchanges) {
- if (exch.detailsPointer?.currency !== currency) {
+ if (!exch.detailsPointer) {
continue;
}
-
- // We now see how much we could spend if we paid all the fees ourselves
- // in a worst-case estimate.
-
- const exchangeBaseUrl = exch.baseUrl;
- let ageLower = 0;
- let ageUpper = AgeRestriction.AGE_UNRESTRICTED;
- if (req.requiredMinimumAge) {
- ageLower = req.requiredMinimumAge;
- }
-
- const myExchangeCoins =
- await tx.coinAvailability.indexes.byExchangeAgeAvailability.getAll(
- GlobalIDB.KeyRange.bound(
- [exchangeBaseUrl, ageLower, 1],
- [exchangeBaseUrl, ageUpper, Number.MAX_SAFE_INTEGER],
- ),
- );
-
- for (const ec of myExchangeCoins) {
- maxEffectiveSpendAmount = Amounts.add(
- maxEffectiveSpendAmount,
- Amounts.mult(ec.value, ec.freshCoinCount).amount,
- ).amount;
-
- const denom = await getDenomInfo(
- wex,
- tx,
- exchangeBaseUrl,
- ec.denomPubHash,
- );
- if (!denom) {
- continue;
- }
- maxEffectiveSpendAmount = Amounts.sub(
- maxEffectiveSpendAmount,
- Amounts.mult(denom.feeDeposit, ec.freshCoinCount).amount,
- ).amount;
- }
-
- const infoExchange = await getExchangePaymentBalanceDetailsInTx(wex, tx, {
- currency,
- restrictExchangeTo: exch.baseUrl,
+ const exchDet = await getPaymentBalanceDetailsInTx(wex, tx, {
+ restrictExchanges: {
+ exchanges: [
+ {
+ exchangeBaseUrl: exch.baseUrl,
+ exchangePub: exch.detailsPointer?.masterPublicKey,
+ },
+ ],
+ auditors: [],
+ },
+ restrictWireMethods: req.wireMethod ? [req.wireMethod] : [],
+ currency: Amounts.currencyOf(req.instructedAmount),
+ minAge: req.requiredMinimumAge ?? 0,
+ depositPaytoUri: req.depositPaytoUri,
});
perExchange[exch.baseUrl] = {
- balanceAvailable: Amounts.stringify(infoExchange.balanceAvailable),
- balanceMaterial: Amounts.stringify(infoExchange.balanceMaterial),
+ balanceAvailable: Amounts.stringify(exchDet.balanceAvailable),
+ balanceMaterial: Amounts.stringify(exchDet.balanceMaterial),
+ balanceExchangeDepositable: Amounts.stringify(
+ exchDet.balanceExchangeDepositable,
+ ),
};
}
@@ -479,10 +436,13 @@ export async function reportInsufficientBalanceDetails(
balanceMerchantAcceptable: Amounts.stringify(
details.balanceMerchantAcceptable,
),
+ balanceExchangeDepositable: Amounts.stringify(
+ details.balanceExchangeDepositable,
+ ),
balanceMerchantDepositable: Amounts.stringify(
details.balanceMerchantDepositable,
),
- maxEffectiveSpendAmount: Amounts.stringify(maxEffectiveSpendAmount),
+ maxEffectiveSpendAmount: Amounts.stringify(details.maxEffectiveSpendAmount),
perExchange,
};
}
@@ -682,7 +642,7 @@ export type AvailableDenom = DenominationInfo & {
numAvailable: number;
};
-function findMatchingWire(
+export function findMatchingWire(
wireMethod: string,
depositPaytoUri: string | undefined,
exchangeWireDetails: ExchangeWireDetails,
@@ -876,7 +836,7 @@ export type SelectPeerCoinsResult =
| { type: "success"; result: PeerCoinSelectionDetails }
| {
type: "failure";
- insufficientBalanceDetails: PayMerchantInsufficientBalanceDetails;
+ insufficientBalanceDetails: PaymentInsufficientBalanceDetails;
};
export interface PeerCoinSelectionRequest {
@@ -1017,7 +977,6 @@ export async function selectPeerCoins(
tx,
selectedDenom,
resCoins,
- req.instructedAmount,
tally,
);
@@ -1046,6 +1005,7 @@ export async function selectPeerCoins(
instructedAmount: req.instructedAmount,
requiredMinimumAge: undefined,
wireMethod: undefined,
+ depositPaytoUri: undefined,
},
);
return {