summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2023-01-11 17:12:08 +0100
committerFlorian Dold <florian@dold.me>2023-01-11 17:14:49 +0100
commit143a4fe4ac5b8724cf6e13a704e88daa99dd4202 (patch)
tree07b2fe6d993ae46838bc4072db8eba609bbb1801
parent5fc0cb7927e7a81a80129f6165b2027e72b89d33 (diff)
downloadwallet-core-143a4fe4ac5b8724cf6e13a704e88daa99dd4202.tar.gz
wallet-core-143a4fe4ac5b8724cf6e13a704e88daa99dd4202.tar.bz2
wallet-core-143a4fe4ac5b8724cf6e13a704e88daa99dd4202.zip
wallet-core: refresh when aborting payments
-rw-r--r--packages/taler-harness/src/harness/faultInjection.ts17
-rw-r--r--packages/taler-harness/src/integrationtests/testrunner.ts2
-rw-r--r--packages/taler-util/src/transactions-types.ts11
-rw-r--r--packages/taler-util/src/wallet-types.ts20
-rw-r--r--packages/taler-wallet-core/src/db.ts14
-rw-r--r--packages/taler-wallet-core/src/operations/backup/export.ts2
-rw-r--r--packages/taler-wallet-core/src/operations/exchanges.ts2
-rw-r--r--packages/taler-wallet-core/src/operations/pay-merchant.ts118
-rw-r--r--packages/taler-wallet-core/src/operations/transactions.ts68
-rw-r--r--packages/taler-wallet-core/src/util/query.ts1
-rw-r--r--packages/taler-wallet-core/src/wallet-api-types.ts18
-rw-r--r--packages/taler-wallet-core/src/wallet.ts11
12 files changed, 202 insertions, 82 deletions
diff --git a/packages/taler-harness/src/harness/faultInjection.ts b/packages/taler-harness/src/harness/faultInjection.ts
index 4c3d0c123..f4d7fc4b9 100644
--- a/packages/taler-harness/src/harness/faultInjection.ts
+++ b/packages/taler-harness/src/harness/faultInjection.ts
@@ -47,6 +47,10 @@ export interface FaultInjectionRequestContext {
requestHeaders: Record<string, string | string[] | undefined>;
requestBody?: Buffer;
dropRequest: boolean;
+ // These are only used when the request is dropped
+ substituteResponseBody?: Buffer;
+ substituteResponseStatusCode?: number;
+ substituteResponseHeaders?: Record<string, string | string[] | undefined>;
}
export interface FaultInjectionResponseContext {
@@ -101,7 +105,18 @@ export class FaultProxy {
}
if (faultReqContext.dropRequest) {
- res.destroy();
+ if (faultReqContext.substituteResponseStatusCode) {
+ const statusCode = faultReqContext.substituteResponseStatusCode;
+ res.writeHead(
+ statusCode,
+ http.STATUS_CODES[statusCode],
+ faultReqContext.substituteResponseHeaders,
+ );
+ res.write(faultReqContext.substituteResponseBody);
+ res.end();
+ } else {
+ res.destroy();
+ }
return;
}
diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts b/packages/taler-harness/src/integrationtests/testrunner.ts
index 9e64a151a..b5afa5d5b 100644
--- a/packages/taler-harness/src/integrationtests/testrunner.ts
+++ b/packages/taler-harness/src/integrationtests/testrunner.ts
@@ -97,6 +97,7 @@ import { runAgeRestrictionsMixedMerchantTest } from "./test-age-restrictions-mix
import { runWalletCryptoWorkerTest } from "./test-wallet-cryptoworker.js";
import { runWithdrawalHighTest } from "./test-withdrawal-high.js";
import { runKycTest } from "./test-kyc.js";
+import { runPaymentAbortTest } from "./test-payment-abort.js";
/**
* Test runner.
@@ -159,6 +160,7 @@ const allTests: TestMainFunction[] = [
runPaymentIdempotencyTest,
runPaymentMultipleTest,
runPaymentTest,
+ runPaymentAbortTest,
runPaymentTransientTest,
runPaymentZeroTest,
runPayPaidTest,
diff --git a/packages/taler-util/src/transactions-types.ts b/packages/taler-util/src/transactions-types.ts
index 62caaa055..59116a150 100644
--- a/packages/taler-util/src/transactions-types.ts
+++ b/packages/taler-util/src/transactions-types.ts
@@ -49,6 +49,15 @@ import {
TransactionIdStr,
} from "./wallet-types.js";
+export enum ExtendedStatus {
+ Pending = "pending",
+ Done = "done",
+ Aborting = "aborting",
+ Aborted = "aborted",
+ Failed = "failed",
+ KycRequired = "kyc-required",
+}
+
export interface TransactionsRequest {
/**
* return only transactions in the given currency
@@ -80,6 +89,8 @@ export interface TransactionCommon {
// main timestamp of the transaction
timestamp: TalerProtocolTimestamp;
+ extendedStatus: ExtendedStatus;
+
// true if the transaction is still pending, false otherwise
// If a transaction is not longer pending, its timestamp will be updated,
// but its transactionId will remain unchanged
diff --git a/packages/taler-util/src/wallet-types.ts b/packages/taler-util/src/wallet-types.ts
index b33eac0df..1ad5ef0ec 100644
--- a/packages/taler-util/src/wallet-types.ts
+++ b/packages/taler-util/src/wallet-types.ts
@@ -538,7 +538,7 @@ export interface WalletDiagnostics {
export interface TalerErrorDetail {
code: TalerErrorCode;
- when: string;
+ when?: string;
hint?: string;
[x: string]: unknown;
}
@@ -1553,8 +1553,8 @@ export const codecForAcceptTipRequest = (): Codec<AcceptTipRequest> =>
.property("walletTipId", codecForString())
.build("AcceptTipRequest");
-export interface AbortPayRequest {
- proposalId: string;
+export interface AbortTransactionRequest {
+ transactionId: string;
/**
* Move the payment immediately into an aborted state.
@@ -1563,15 +1563,15 @@ export interface AbortPayRequest {
*
* Defaults to false.
*/
- cancelImmediately?: boolean;
+ forceImmediateAbort?: boolean;
}
-export const codecForAbortPayRequest =
- (): Codec<AbortPayRequest> =>
- buildCodecForObject<AbortPayRequest>()
- .property("proposalId", codecForString())
- .property("cancelImmediately", codecOptional(codecForBoolean()))
- .build("AbortPayRequest");
+export const codecForAbortTransaction =
+ (): Codec<AbortTransactionRequest> =>
+ buildCodecForObject<AbortTransactionRequest>()
+ .property("transactionId", codecForString())
+ .property("forceImmediateAbort", codecOptional(codecForBoolean()))
+ .build("AbortTransactionRequest");
export interface GetFeeForDepositRequest {
depositPaytoUri: string;
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index f3ef3aea5..7f114df78 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -849,6 +849,13 @@ export enum RefreshOperationStatus {
}
/**
+ * Additional information about the reason of a refresh.
+ */
+export interface RefreshReasonDetails {
+ proposalId?: string;
+}
+
+/**
* Group of refresh operations. The refreshed coins do not
* have to belong to the same exchange, but must have the same
* currency.
@@ -880,6 +887,11 @@ export interface RefreshGroupRecord {
*/
reason: RefreshReason;
+ /**
+ * Extra information depending on the reason.
+ */
+ reasonDetails?: RefreshReasonDetails;
+
oldCoinPubs: string[];
// FIXME: Should this go into a separate
@@ -2006,7 +2018,7 @@ export const WalletStoresV1 = {
),
},
),
- exchangeSignkeys: describeStore(
+ exchangeSignKeys: describeStore(
"exchangeSignKeys",
describeContents<ExchangeSignkeysRecord>({
keyPath: ["exchangeDetailsRowId", "signkeyPub"],
diff --git a/packages/taler-wallet-core/src/operations/backup/export.ts b/packages/taler-wallet-core/src/operations/backup/export.ts
index 965d51776..a66444485 100644
--- a/packages/taler-wallet-core/src/operations/backup/export.ts
+++ b/packages/taler-wallet-core/src/operations/backup/export.ts
@@ -89,7 +89,7 @@ export async function exportBackup(
x.config,
x.exchanges,
x.exchangeDetails,
- x.exchangeSignkeys,
+ x.exchangeSignKeys,
x.coins,
x.contractTerms,
x.denominations,
diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts
index b6e2a9d73..67f77de77 100644
--- a/packages/taler-wallet-core/src/operations/exchanges.ts
+++ b/packages/taler-wallet-core/src/operations/exchanges.ts
@@ -675,7 +675,7 @@ export async function updateExchangeFromUrlHandler(
x.exchanges,
x.exchangeTos,
x.exchangeDetails,
- x.exchangeSignkeys,
+ x.exchangeSignKeys,
x.denominations,
x.coins,
x.refreshGroups,
diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts b/packages/taler-wallet-core/src/operations/pay-merchant.ts
index c8e3230b9..2f1f3375c 100644
--- a/packages/taler-wallet-core/src/operations/pay-merchant.ts
+++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts
@@ -125,6 +125,7 @@ import {
} from "../util/retries.js";
import {
makeTransactionId,
+ runOperationWithErrorReporting,
spendCoins,
storeOperationError,
storeOperationPending,
@@ -1135,9 +1136,9 @@ export function selectForced(
export type SelectPayCoinsResult =
| {
- type: "failure";
- insufficientBalanceDetails: PayMerchantInsufficientBalanceDetails;
- }
+ type: "failure";
+ insufficientBalanceDetails: PayMerchantInsufficientBalanceDetails;
+ }
| { type: "success"; coinSel: PayCoinSelection };
/**
@@ -1594,7 +1595,12 @@ export async function runPayForConfirmPay(
ws: InternalWalletState,
proposalId: string,
): Promise<ConfirmPayResult> {
- const res = await processPurchasePay(ws, proposalId, { forceNow: true });
+ logger.trace("processing proposal for confirmPay");
+ const opId = RetryTags.byPaymentProposalId(proposalId);
+ const res = await runOperationWithErrorReporting(ws, opId, async () => {
+ return await processPurchasePay(ws, proposalId, { forceNow: true });
+ });
+ logger.trace(`processPurchasePay response type ${res.type}`);
switch (res.type) {
case OperationAttemptResultType.Finished: {
const purchase = await ws.db
@@ -1623,9 +1629,10 @@ export async function runPayForConfirmPay(
const numRetry = opRetry?.retryInfo.retryCounter ?? 0;
if (
res.errorDetail.code ===
- TalerErrorCode.WALLET_PAY_MERCHANT_SERVER_ERROR &&
+ TalerErrorCode.WALLET_PAY_MERCHANT_SERVER_ERROR &&
numRetry < maxRetry
) {
+ logger.trace("hiding transient error from caller");
// Pretend the operation is pending instead of reporting
// an error, but only up to maxRetry attempts.
await storeOperationPending(
@@ -1638,20 +1645,11 @@ export async function runPayForConfirmPay(
transactionId: makeTransactionId(TransactionType.Payment, proposalId),
};
} else {
- // FIXME: allocate error code!
- await storeOperationError(
- ws,
- RetryTags.byPaymentProposalId(proposalId),
- res.errorDetail,
- );
throw Error("payment failed");
}
}
case OperationAttemptResultType.Pending:
- await storeOperationPending(
- ws,
- `${PendingTaskType.Purchase}:${proposalId}`,
- );
+ logger.trace("reporting pending as confirmPay response");
return {
type: ConfirmPayResultType.Pending,
transactionId: makeTransactionId(TransactionType.Payment, proposalId),
@@ -1968,29 +1966,12 @@ export async function processPurchasePay(
result: undefined,
};
}
+ }
- if (resp.status >= 400 && resp.status <= 499) {
- const errDetails = await readUnexpectedResponseDetails(resp);
- logger.warn(`server returned ${resp.status} response for /pay`);
- logger.warn(j2s(errDetails));
- await ws.db
- .mktx((x) => [x.purchases])
- .runReadWrite(async (tx) => {
- const purch = await tx.purchases.get(proposalId);
- if (!purch) {
- return;
- }
- // FIXME: Should be some "PayPermanentlyFailed" and error info should be stored
- purch.purchaseStatus = PurchaseStatus.PaymentAbortFinished;
- await tx.purchases.put(purch);
- });
- throw makePendingOperationFailedError(
- errDetails,
- TransactionType.Payment,
- proposalId,
- );
- }
-
+ if (resp.status >= 400 && resp.status <= 499) {
+ logger.trace("got generic 4xx from merchant");
+ const err = await readTalerErrorResponse(resp);
+ throwUnexpectedRequestError(resp, err);
}
const merchantResp = await readSuccessResponseJsonOrThrow(
@@ -2395,16 +2376,18 @@ async function acceptRefunds(
}
}
- const refreshCoinsPubs = Object.values(refreshCoinsMap);
- logger.info(`refreshCoinMap ${j2s(refreshCoinsMap)}`);
- if (refreshCoinsPubs.length > 0) {
- await createRefreshGroup(
- ws,
- tx,
- Amounts.currencyOf(refreshCoinsPubs[0].amount),
- refreshCoinsPubs,
- RefreshReason.Refund,
- );
+ if (reason === RefundReason.AbortRefund) {
+ const refreshCoinsPubs = Object.values(refreshCoinsMap);
+ logger.info(`refreshCoinMap ${j2s(refreshCoinsMap)}`);
+ if (refreshCoinsPubs.length > 0) {
+ await createRefreshGroup(
+ ws,
+ tx,
+ Amounts.currencyOf(refreshCoinsPubs[0].amount),
+ refreshCoinsPubs,
+ RefreshReason.Refund,
+ );
+ }
}
// Are we done with querying yet, or do we need to do another round
@@ -2808,12 +2791,21 @@ export async function processPurchaseQueryRefund(
return OperationAttemptResult.finishedEmpty();
}
-export async function abortFailedPayWithRefund(
+export async function abortPay(
ws: InternalWalletState,
proposalId: string,
+ cancelImmediately?: boolean,
): Promise<void> {
+ const opId = RetryTags.byPaymentProposalId(proposalId);
await ws.db
- .mktx((x) => [x.purchases])
+ .mktx((x) => [
+ x.purchases,
+ x.refreshGroups,
+ x.denominations,
+ x.coinAvailability,
+ x.coins,
+ x.operationRetries,
+ ])
.runReadWrite(async (tx) => {
const purchase = await tx.purchases.get(proposalId);
if (!purchase) {
@@ -2828,10 +2820,30 @@ export async function abortFailedPayWithRefund(
purchase.purchaseStatus = PurchaseStatus.AbortingWithRefund;
}
await tx.purchases.put(purchase);
+ await tx.operationRetries.delete(opId);
+ if (purchase.payInfo) {
+ const coinSel = purchase.payInfo.payCoinSelection;
+ const currency = Amounts.currencyOf(purchase.payInfo.totalPayCost);
+ const refreshCoins: CoinRefreshRequest[] = [];
+ for (let i = 0; i < coinSel.coinPubs.length; i++) {
+ refreshCoins.push({
+ amount: coinSel.coinContributions[i],
+ coinPub: coinSel.coinPubs[i],
+ });
+ }
+ await createRefreshGroup(
+ ws,
+ tx,
+ currency,
+ refreshCoins,
+ RefreshReason.AbortPay,
+ );
+ }
+ });
+
+ runOperationWithErrorReporting(ws, opId, async () => {
+ return await processPurchaseQueryRefund(ws, proposalId, {
+ forceNow: true,
});
- processPurchaseQueryRefund(ws, proposalId, {
- forceNow: true,
- }).catch((e) => {
- logger.trace(`error during refund processing after abort pay: ${e}`);
});
}
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts
index 3fb13d2a0..2570a4e5f 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -23,6 +23,7 @@ import {
Amounts,
constructPayPullUri,
constructPayPushUri,
+ ExtendedStatus,
Logger,
OrderShortInfo,
PaymentStatus,
@@ -66,6 +67,7 @@ import {
import { processDepositGroup } from "./deposits.js";
import { getExchangeDetails } from "./exchanges.js";
import {
+ abortPay,
expectProposalDownload,
extractContractData,
processPurchasePay,
@@ -352,6 +354,10 @@ function buildTransactionForPushPaymentDebit(
summary: contractTerms.summary,
},
frozen: false,
+ extendedStatus:
+ pi.status != PeerPushPaymentInitiationStatus.PurseCreated
+ ? ExtendedStatus.Pending
+ : ExtendedStatus.Done,
pending: pi.status != PeerPushPaymentInitiationStatus.PurseCreated,
timestamp: pi.timestampCreated,
talerUri: constructPayPushUri({
@@ -377,6 +383,7 @@ function buildTransactionForPullPaymentDebit(
exchangeBaseUrl: pi.exchangeBaseUrl,
frozen: false,
pending: false,
+ extendedStatus: ExtendedStatus.Done,
info: {
expiration: pi.contractTerms.purse_expiration,
summary: pi.contractTerms.summary,
@@ -401,6 +408,7 @@ function buildTransactionForPullPaymentCredit(
amountEffective: Amounts.stringify(wsr.denomsSel.totalCoinValue),
amountRaw: Amounts.stringify(wsr.instructedAmount),
exchangeBaseUrl: wsr.exchangeBaseUrl,
+ extendedStatus: ExtendedStatus.Done,
pending: !wsr.timestampFinish,
timestamp: wsr.timestampStart,
info: {
@@ -435,6 +443,9 @@ function buildTransactionForPushPaymentCredit(
expiration: wsr.wgInfo.contractTerms.purse_expiration,
summary: wsr.wgInfo.contractTerms.summary,
},
+ extendedStatus: wsr.timestampFinish
+ ? ExtendedStatus.Done
+ : ExtendedStatus.Pending,
pending: !wsr.timestampFinish,
timestamp: wsr.timestampStart,
transactionId: makeTransactionId(
@@ -464,6 +475,9 @@ function buildTransactionForBankIntegratedWithdraw(
bankConfirmationUrl: wsr.wgInfo.bankInfo.confirmUrl,
},
exchangeBaseUrl: wsr.exchangeBaseUrl,
+ extendedStatus: wsr.timestampFinish
+ ? ExtendedStatus.Done
+ : ExtendedStatus.Pending,
pending: !wsr.timestampFinish,
timestamp: wsr.timestampStart,
transactionId: makeTransactionId(
@@ -504,6 +518,9 @@ function buildTransactionForManualWithdraw(
exchangePaytoUris,
},
exchangeBaseUrl: withdrawalGroup.exchangeBaseUrl,
+ extendedStatus: withdrawalGroup.timestampFinish
+ ? ExtendedStatus.Done
+ : ExtendedStatus.Pending,
pending: !withdrawalGroup.timestampFinish,
timestamp: withdrawalGroup.timestampStart,
transactionId: makeTransactionId(
@@ -523,6 +540,9 @@ function buildTransactionForDeposit(
type: TransactionType.Deposit,
amountRaw: Amounts.stringify(dg.effectiveDepositAmount),
amountEffective: Amounts.stringify(dg.totalPayCost),
+ extendedStatus: dg.timestampFinished
+ ? ExtendedStatus.Done
+ : ExtendedStatus.Pending,
pending: !dg.timestampFinished,
frozen: false,
timestamp: dg.timestampCreated,
@@ -547,6 +567,9 @@ function buildTransactionForTip(
type: TransactionType.Tip,
amountEffective: Amounts.stringify(tipRecord.tipAmountEffective),
amountRaw: Amounts.stringify(tipRecord.tipAmountRaw),
+ extendedStatus: tipRecord.pickedUpTimestamp
+ ? ExtendedStatus.Done
+ : ExtendedStatus.Pending,
pending: !tipRecord.pickedUpTimestamp,
frozen: false,
timestamp: tipRecord.acceptedTimestamp,
@@ -654,6 +677,7 @@ async function buildTransactionForRefund(
purchaseRecord.refundAmountAwaiting === undefined
? undefined
: Amounts.stringify(purchaseRecord.refundAmountAwaiting),
+ extendedStatus: ExtendedStatus.Done,
pending: false,
frozen: false,
...(ort?.lastError ? { error: ort.lastError } : {}),
@@ -710,6 +734,33 @@ async function buildTransactionForPurchase(
checkDbInvariant(!!timestamp);
checkDbInvariant(!!purchaseRecord.payInfo);
+
+ let status: ExtendedStatus;
+ switch (purchaseRecord.purchaseStatus) {
+ case PurchaseStatus.AbortingWithRefund:
+ status = ExtendedStatus.Aborting;
+ break;
+ case PurchaseStatus.Paid:
+ case PurchaseStatus.RepurchaseDetected:
+ status = ExtendedStatus.Done;
+ break;
+ case PurchaseStatus.DownloadingProposal:
+ case PurchaseStatus.QueryingRefund:
+ case PurchaseStatus.Proposed:
+ case PurchaseStatus.Paying:
+ status = ExtendedStatus.Pending;
+ break;
+ case PurchaseStatus.ProposalDownloadFailed:
+ status = ExtendedStatus.Failed;
+ break;
+ case PurchaseStatus.PaymentAbortFinished:
+ status = ExtendedStatus.Aborted;
+ break;
+ default:
+ // FIXME: Should we have some unknown status?
+ status = ExtendedStatus.Pending;
+ }
+
return {
type: TransactionType.Payment,
amountRaw: Amounts.stringify(contractData.amount),
@@ -723,6 +774,7 @@ async function buildTransactionForPurchase(
status: purchaseRecord.timestampFirstSuccessfulPay
? PaymentStatus.Paid
: PaymentStatus.Accepted,
+ extendedStatus: status,
pending: purchaseRecord.purchaseStatus === PurchaseStatus.Paying,
refunds,
timestamp,
@@ -1163,3 +1215,19 @@ export async function deleteTransaction(
throw Error(`can't delete a '${unknownTxType}' transaction`);
}
}
+
+export async function abortTransaction(
+ ws: InternalWalletState,
+ transactionId: string,
+ forceImmediateAbort?: boolean,
+): Promise<void> {
+ const { type, args: rest } = parseId("txn", transactionId);
+
+ if (type === TransactionType.Payment) {
+ const proposalId = rest[0];
+ await abortPay(ws, proposalId, forceImmediateAbort);
+ } else {
+ const unknownTxType: any = type;
+ throw Error(`can't abort a '${unknownTxType}' transaction`);
+ }
+}
diff --git a/packages/taler-wallet-core/src/util/query.ts b/packages/taler-wallet-core/src/util/query.ts
index 4eb354f3e..56a23c2dd 100644
--- a/packages/taler-wallet-core/src/util/query.ts
+++ b/packages/taler-wallet-core/src/util/query.ts
@@ -660,7 +660,6 @@ export class DbAccess<StoreMap> {
const storeNames: string[] = [];
const accessibleStores: { [x: string]: StoreWithIndexes<any, any, any> } =
{};
-
for (let i = 0; i < this.db.objectStoreNames.length; i++) {
const sn = this.db.objectStoreNames[i];
const swi = (this.stores as any)[sn] as StoreWithIndexes<any, any, any>;
diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts
index 3daa817e8..88ae3a5c1 100644
--- a/packages/taler-wallet-core/src/wallet-api-types.ts
+++ b/packages/taler-wallet-core/src/wallet-api-types.ts
@@ -24,7 +24,7 @@
* Imports.
*/
import {
- AbortPayRequest as AbortPayRequest,
+ AbortTransactionRequest as AbortTransactionRequest,
AcceptBankIntegratedWithdrawalRequest,
AcceptExchangeTosRequest,
AcceptManualWithdrawalRequest,
@@ -150,7 +150,7 @@ export enum WalletApiOperation {
GetExchangeTos = "getExchangeTos",
GetExchangeDetailedInfo = "getExchangeDetailedInfo",
RetryPendingNow = "retryPendingNow",
- AbortPay = "abortPay",
+ AbortTransaction = "abortTransaction",
ConfirmPay = "confirmPay",
DumpCoins = "dumpCoins",
SetCoinSuspended = "setCoinSuspended",
@@ -329,13 +329,13 @@ export type ConfirmPayOp = {
};
/**
- * Abort a pending payment.
- * Puts the payment into an "aborting" state
- * that can be cancelled.
+ * Abort a transaction
+ *
+ * For payment transactions, it puts the payment into an "aborting" state.
*/
-export type AbortPayOp = {
- op: WalletApiOperation.AbortPay;
- request: AbortPayRequest;
+export type AbortTransactionOp = {
+ op: WalletApiOperation.AbortTransaction;
+ request: AbortTransactionRequest;
response: EmptyObject;
};
@@ -829,7 +829,7 @@ export type WalletOperations = {
[WalletApiOperation.GetContractTermsDetails]: GetContractTermsDetailsOp;
[WalletApiOperation.WithdrawTestkudos]: WithdrawTestkudosOp;
[WalletApiOperation.ConfirmPay]: ConfirmPayOp;
- [WalletApiOperation.AbortPay]: AbortPayOp;
+ [WalletApiOperation.AbortTransaction]: AbortTransactionOp;
[WalletApiOperation.GetBalances]: GetBalancesOp;
[WalletApiOperation.GetTransactions]: GetTransactionsOp;
[WalletApiOperation.GetTransactionById]: GetTransactionByIdOp;
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index 2b386f0a8..e2a2b43f6 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -25,7 +25,7 @@
import {
AbsoluteTime,
Amounts,
- codecForAbortPayRequest,
+ codecForAbortTransaction,
codecForAcceptBankIntegratedWithdrawalRequest,
codecForAcceptExchangeTosRequest,
codecForAcceptManualWithdrawalRequet,
@@ -180,7 +180,7 @@ import {
} from "./operations/exchanges.js";
import { getMerchantInfo } from "./operations/merchants.js";
import {
- abortFailedPayWithRefund,
+ abortPay as abortPay,
applyRefund,
applyRefundFromPurchaseId,
confirmPay,
@@ -217,6 +217,7 @@ import {
} from "./operations/testing.js";
import { acceptTip, prepareTip, processTip } from "./operations/tip.js";
import {
+ abortTransaction,
deleteTransaction,
getTransactionById,
getTransactions,
@@ -1163,9 +1164,9 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
const req = codecForConfirmPayRequest().decode(payload);
return await confirmPay(ws, req.proposalId, req.sessionId);
}
- case WalletApiOperation.AbortPay: {
- const req = codecForAbortPayRequest().decode(payload);
- await abortFailedPayWithRefund(ws, req.proposalId);
+ case WalletApiOperation.AbortTransaction: {
+ const req = codecForAbortTransaction().decode(payload);
+ await abortTransaction(ws, req.transactionId, req.forceImmediateAbort);
return {};
}
case WalletApiOperation.DumpCoins: {