diff options
author | Florian Dold <florian@dold.me> | 2024-03-07 11:10:52 +0100 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2024-03-07 11:10:52 +0100 |
commit | 466e2b7643692aa6b7f76a193b84775008e17350 (patch) | |
tree | dd3f9a0b67765e2c7ea6b97c2a7acbbcac71d4b7 /packages/taler-wallet-core/src/coinSelection.ts | |
parent | 8eb3e505be967afde0053d5a392e8c6877d8f1dd (diff) | |
download | wallet-core-466e2b7643692aa6b7f76a193b84775008e17350.tar.xz |
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.ts | 114 |
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 { |