aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core/src/pay-merchant.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-core/src/pay-merchant.ts')
-rw-r--r--packages/taler-wallet-core/src/pay-merchant.ts106
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) {