From 5ca3c7878da9a495c67ea7faed91c8dbce04e603 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 7 Mar 2024 11:33:41 +0100 Subject: wallet-core: simplify/improve insufficient balance details computation --- packages/taler-wallet-core/src/balance.ts | 167 ++++++++---------------- packages/taler-wallet-core/src/coinSelection.ts | 10 ++ 2 files changed, 66 insertions(+), 111 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-wallet-core/src/balance.ts b/packages/taler-wallet-core/src/balance.ts index 4c58814a1..26d348b39 100644 --- a/packages/taler-wallet-core/src/balance.ts +++ b/packages/taler-wallet-core/src/balance.ts @@ -59,8 +59,6 @@ import { assertUnreachable, BalanceFlag, BalancesResponse, - canonicalizeBaseUrl, - checkLogicInvariant, GetBalanceDetailRequest, Logger, parsePaytoUri, @@ -487,100 +485,6 @@ export interface AcceptableExchanges { depositableExchanges: string[]; } -/** - * Get all exchanges that are acceptable for a particular payment. - */ -async function getAcceptableExchangeBaseUrlsInTx( - wex: WalletExecutionContext, - tx: WalletDbReadOnlyTransaction<["exchanges", "exchangeDetails"]>, - req: PaymentRestrictionsForBalance, -): Promise { - const acceptableExchangeUrls = new Set(); - const depositableExchangeUrls = new Set(); - // FIXME: We should have a DB index to look up all exchanges - // for a particular auditor ... - - const canonExchanges = new Set(); - const canonAuditors = new Set(); - - if (req.restrictExchanges) { - for (const exchangeHandle of req.restrictExchanges.exchanges) { - const normUrl = canonicalizeBaseUrl(exchangeHandle.exchangeBaseUrl); - canonExchanges.add(normUrl); - } - - for (const auditorHandle of req.restrictExchanges.auditors) { - const normUrl = canonicalizeBaseUrl(auditorHandle.auditorBaseUrl); - canonAuditors.add(normUrl); - } - } - - await tx.exchanges.iter().forEachAsync(async (exchange) => { - const dp = exchange.detailsPointer; - if (!dp) { - return; - } - const { currency, masterPublicKey } = dp; - const exchangeDetails = await tx.exchangeDetails.indexes.byPointer.get([ - exchange.baseUrl, - currency, - masterPublicKey, - ]); - if (!exchangeDetails) { - return; - } - - let acceptable = false; - - if (canonExchanges.has(exchange.baseUrl)) { - acceptableExchangeUrls.add(exchange.baseUrl); - acceptable = true; - } - for (const exchangeAuditor of exchangeDetails.auditors) { - if (canonAuditors.has(exchangeAuditor.auditor_url)) { - acceptableExchangeUrls.add(exchange.baseUrl); - acceptable = true; - break; - } - } - - if (!acceptable) { - return; - } - // FIXME: Also consider exchange and auditor public key - // instead of just base URLs? - - let wireMethodSupported = false; - - if (req.restrictWireMethods) { - for (const acc of exchangeDetails.wireInfo.accounts) { - const pp = parsePaytoUri(acc.payto_uri); - checkLogicInvariant(!!pp); - for (const wm of req.restrictWireMethods) { - if (pp.targetType === wm) { - wireMethodSupported = true; - break; - } - if (wireMethodSupported) { - break; - } - } - } - } else { - wireMethodSupported = true; - } - - acceptableExchangeUrls.add(exchange.baseUrl); - if (wireMethodSupported) { - depositableExchangeUrls.add(exchange.baseUrl); - } - }); - return { - acceptableExchanges: [...acceptableExchangeUrls], - depositableExchanges: [...depositableExchangeUrls], - }; -} - export interface PaymentBalanceDetails { /** * Balance of type "available" (see balance.ts for definition). @@ -648,8 +552,6 @@ export async function getPaymentBalanceDetailsInTx( >, req: PaymentRestrictionsForBalance, ): Promise { - const acceptability = await getAcceptableExchangeBaseUrlsInTx(wex, tx, req); - const d: PaymentBalanceDetails = { balanceAvailable: Amounts.zeroOfCurrency(req.currency), balanceMaterial: Amounts.zeroOfCurrency(req.currency), @@ -691,38 +593,64 @@ export async function getPaymentBalanceDetailsInTx( ca.freshCoinCount, ).amount; - d.maxEffectiveSpendAmount = Amounts.add( - d.maxEffectiveSpendAmount, - Amounts.mult(ca.value, ca.freshCoinCount).amount, - ).amount; - - d.maxEffectiveSpendAmount = Amounts.sub( - d.maxEffectiveSpendAmount, - Amounts.mult(denom.feeDeposit, ca.freshCoinCount).amount, - ).amount; - let wireOkay = false; if (req.restrictWireMethods == null) { wireOkay = true; } else { for (const wm of req.restrictWireMethods) { const wmf = findMatchingWire(wm, req.depositPaytoUri, wireDetails); + if (wmf) { + wireOkay = true; + break; + } + } + } + + if (wireOkay) { + d.balanceExchangeDepositable = Amounts.add( + d.balanceExchangeDepositable, + coinAmount, + ).amount; + } + + let ageOkay = ca.maxAge === 0 || ca.maxAge > req.minAge; + + let merchantExchangeAcceptable = false; + + if (!req.restrictExchanges) { + merchantExchangeAcceptable = true; + } else { + for (const ex of req.restrictExchanges.exchanges) { + if (ex.exchangeBaseUrl === ca.exchangeBaseUrl) { + merchantExchangeAcceptable = true; + break; + } + } + for (const acceptedAuditor of req.restrictExchanges.auditors) { + for (const exchangeAuditor of wireDetails.auditors) { + if (acceptedAuditor.auditorBaseUrl === exchangeAuditor.auditor_url) { + merchantExchangeAcceptable = true; + break; + } + } } } + const merchantExchangeDepositable = merchantExchangeAcceptable && wireOkay; + d.balanceAvailable = Amounts.add(d.balanceAvailable, coinAmount).amount; d.balanceMaterial = Amounts.add(d.balanceMaterial, coinAmount).amount; - if (ca.maxAge === 0 || ca.maxAge > req.minAge) { + if (ageOkay) { d.balanceAgeAcceptable = Amounts.add( d.balanceAgeAcceptable, coinAmount, ).amount; - if (acceptability.acceptableExchanges.includes(ca.exchangeBaseUrl)) { + if (merchantExchangeAcceptable) { d.balanceMerchantAcceptable = Amounts.add( d.balanceMerchantAcceptable, coinAmount, ).amount; - if (acceptability.depositableExchanges.includes(ca.exchangeBaseUrl)) { + if (merchantExchangeDepositable) { d.balanceMerchantDepositable = Amounts.add( d.balanceMerchantDepositable, coinAmount, @@ -730,6 +658,23 @@ export async function getPaymentBalanceDetailsInTx( } } } + + if ( + ageOkay && + wireOkay && + merchantExchangeAcceptable && + merchantExchangeDepositable + ) { + d.maxEffectiveSpendAmount = Amounts.add( + d.maxEffectiveSpendAmount, + Amounts.mult(ca.value, ca.freshCoinCount).amount, + ).amount; + + d.maxEffectiveSpendAmount = Amounts.sub( + d.maxEffectiveSpendAmount, + Amounts.mult(denom.feeDeposit, ca.freshCoinCount).amount, + ).amount; + } } await tx.refreshGroups.iter().forEach((r) => { diff --git a/packages/taler-wallet-core/src/coinSelection.ts b/packages/taler-wallet-core/src/coinSelection.ts index 695be79ac..87b29a998 100644 --- a/packages/taler-wallet-core/src/coinSelection.ts +++ b/packages/taler-wallet-core/src/coinSelection.ts @@ -425,6 +425,16 @@ export async function reportInsufficientBalanceDetails( balanceExchangeDepositable: Amounts.stringify( exchDet.balanceExchangeDepositable, ), + balanceAgeAcceptable: Amounts.stringify(exchDet.balanceAgeAcceptable), + balanceMerchantAcceptable: Amounts.stringify( + exchDet.balanceMerchantAcceptable, + ), + balanceMerchantDepositable: Amounts.stringify( + exchDet.balanceMerchantDepositable, + ), + maxEffectiveSpendAmount: Amounts.stringify( + exchDet.maxEffectiveSpendAmount, + ), }; } -- cgit v1.2.3