diff options
Diffstat (limited to 'packages/taler-wallet-core/src/pay-merchant.ts')
-rw-r--r-- | packages/taler-wallet-core/src/pay-merchant.ts | 106 |
1 files changed, 65 insertions, 41 deletions
diff --git a/packages/taler-wallet-core/src/pay-merchant.ts b/packages/taler-wallet-core/src/pay-merchant.ts index 3b58c1e0a..25725052c 100644 --- a/packages/taler-wallet-core/src/pay-merchant.ts +++ b/packages/taler-wallet-core/src/pay-merchant.ts @@ -63,12 +63,12 @@ import { parsePayTemplateUri, parsePayUri, parseTalerUri, - PayCoinSelection, PreparePayResult, PreparePayResultType, PreparePayTemplateRequest, randomBytes, RefreshReason, + SelectedProspectiveCoin, SharePaymentResult, StartRefundQueryForUriResponse, stringifyPayUri, @@ -453,19 +453,15 @@ export class RefundTransactionContext implements TransactionContext { */ export async function getTotalPaymentCost( wex: WalletExecutionContext, - pcs: PayCoinSelection, + currency: string, + pcs: SelectedProspectiveCoin[], ): Promise<AmountJson> { - const currency = Amounts.currencyOf(pcs.customerDepositFees); return wex.db.runReadOnlyTx(["coins", "denominations"], async (tx) => { const costs: AmountJson[] = []; - for (let i = 0; i < pcs.coins.length; i++) { - const coin = await tx.coins.get(pcs.coins[i].coinPub); - if (!coin) { - throw Error("can't calculate payment cost, coin not found"); - } + for (let i = 0; i < pcs.length; i++) { const denom = await tx.denominations.get([ - coin.exchangeBaseUrl, - coin.denomPubHash, + pcs[i].exchangeBaseUrl, + pcs[i].denomPubHash, ]); if (!denom) { throw Error( @@ -475,23 +471,20 @@ export async function getTotalPaymentCost( const allDenoms = await getCandidateWithdrawalDenomsTx( wex, tx, - coin.exchangeBaseUrl, + pcs[i].exchangeBaseUrl, currency, ); - const amountLeft = Amounts.sub( - denom.value, - pcs.coins[i].contribution, - ).amount; + const amountLeft = Amounts.sub(denom.value, pcs[i].contribution).amount; const refreshCost = getTotalRefreshCost( allDenoms, DenominationRecord.toDenomInfo(denom), amountLeft, wex.ws.config.testing.denomselAllowLate, ); - costs.push(Amounts.parseOrThrow(pcs.coins[i].contribution)); + costs.push(Amounts.parseOrThrow(pcs[i].contribution)); costs.push(refreshCost); } - const zero = Amounts.zeroOfAmount(pcs.customerDepositFees); + const zero = Amounts.zeroOfCurrency(currency); return Amounts.sum([zero, ...costs]).amount; }); } @@ -1256,6 +1249,8 @@ async function checkPaymentByProposalId( proposalId = proposal.proposalId; + const currency = Amounts.currencyOf(contractData.amount); + const ctx = new PayMerchantTransactionContext(wex, proposalId); const transactionId = ctx.transactionId; @@ -1293,23 +1288,37 @@ async function checkPaymentByProposalId( restrictWireMethod: contractData.wireMethod, }); - if (res.type !== "success") { - logger.info("not allowing payment, insufficient coins"); - logger.info( - `insufficient balance details: ${j2s(res.insufficientBalanceDetails)}`, - ); - return { - status: PreparePayResultType.InsufficientBalance, - contractTerms: d.contractTermsRaw, - proposalId: proposal.proposalId, - transactionId, - amountRaw: Amounts.stringify(d.contractData.amount), - talerUri, - balanceDetails: res.insufficientBalanceDetails, - }; + switch (res.type) { + case "failure": { + logger.info("not allowing payment, insufficient coins"); + logger.info( + `insufficient balance details: ${j2s( + res.insufficientBalanceDetails, + )}`, + ); + return { + status: PreparePayResultType.InsufficientBalance, + contractTerms: d.contractTermsRaw, + proposalId: proposal.proposalId, + transactionId, + amountRaw: Amounts.stringify(d.contractData.amount), + talerUri, + balanceDetails: res.insufficientBalanceDetails, + }; + } + case "prospective": + throw Error("insufficient balance (waiting on refresh)"); + case "success": + break; + default: + assertUnreachable(res); } - const totalCost = await getTotalPaymentCost(wex, res.coinSel); + const totalCost = await getTotalPaymentCost( + wex, + currency, + res.coinSel.coins, + ); logger.trace("costInfo", totalCost); logger.trace("coinsForPayment", res); @@ -1813,6 +1822,8 @@ export async function confirmPay( const contractData = d.contractData; + const currency = Amounts.currencyOf(contractData.amount); + const selectCoinsResult = await selectPayCoins(wex, { restrictExchanges: { auditors: [], @@ -1827,18 +1838,31 @@ export async function confirmPay( forcedSelection: forcedCoinSel, }); - logger.trace("coin selection result", selectCoinsResult); - - if (selectCoinsResult.type === "failure") { - // Should not happen, since checkPay should be called first - // FIXME: Actually, this should be handled gracefully, - // and the status should be stored in the DB. - logger.warn("not confirming payment, insufficient coins"); - throw Error("insufficient balance"); + switch (selectCoinsResult.type) { + case "failure": { + // Should not happen, since checkPay should be called first + // FIXME: Actually, this should be handled gracefully, + // and the status should be stored in the DB. + logger.warn("not confirming payment, insufficient coins"); + throw Error("insufficient balance"); + } + case "prospective": { + throw Error("insufficient balance (waiting on refresh)"); + } + case "success": + break; + default: + assertUnreachable(selectCoinsResult); } + logger.trace("coin selection result", selectCoinsResult); + const coinSelection = selectCoinsResult.coinSel; - const payCostInfo = await getTotalPaymentCost(wex, coinSelection); + const payCostInfo = await getTotalPaymentCost( + wex, + currency, + coinSelection.coins, + ); let sessionId: string | undefined; if (sessionIdOverride) { |