summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2023-05-30 15:58:28 +0200
committerFlorian Dold <florian@dold.me>2023-05-30 15:58:28 +0200
commit2a92ca8732195a3a317a0edc155efc0b72351272 (patch)
tree0a9acdb7014b3a4018f904ad307b32f7eb40f848
parent000359a5e746d9b704b05f2f3eb8442e10a31f75 (diff)
downloadwallet-core-2a92ca8732195a3a317a0edc155efc0b72351272.tar.gz
wallet-core-2a92ca8732195a3a317a0edc155efc0b72351272.tar.bz2
wallet-core-2a92ca8732195a3a317a0edc155efc0b72351272.zip
wallet-core: report possible actions in transactions list
-rw-r--r--packages/taler-util/src/transactions-types.ts14
-rw-r--r--packages/taler-wallet-core/src/db.ts2
-rw-r--r--packages/taler-wallet-core/src/operations/backup/export.ts2
-rw-r--r--packages/taler-wallet-core/src/operations/backup/import.ts2
-rw-r--r--packages/taler-wallet-core/src/operations/deposits.ts59
-rw-r--r--packages/taler-wallet-core/src/operations/pay-merchant.ts77
-rw-r--r--packages/taler-wallet-core/src/operations/pay-peer.ts131
-rw-r--r--packages/taler-wallet-core/src/operations/refresh.ts44
-rw-r--r--packages/taler-wallet-core/src/operations/tip.ts21
-rw-r--r--packages/taler-wallet-core/src/operations/transactions.ts60
-rw-r--r--packages/taler-wallet-core/src/operations/withdraw.ts46
-rw-r--r--packages/taler-wallet-core/src/wallet.ts4
12 files changed, 407 insertions, 55 deletions
diff --git a/packages/taler-util/src/transactions-types.ts b/packages/taler-util/src/transactions-types.ts
index c06bc7369..5f5b9d112 100644
--- a/packages/taler-util/src/transactions-types.ts
+++ b/packages/taler-util/src/transactions-types.ts
@@ -125,6 +125,15 @@ export enum TransactionMinorState {
AcceptRefund = "accept-refund",
}
+export enum TransactionAction {
+ Delete = "delete",
+ Suspend = "suspend",
+ Resume = "resume",
+ Abort = "abort",
+ Fail = "fail",
+ Retry = "retry",
+}
+
export interface TransactionsResponse {
// a list of past and pending transactions sorted by pending, timestamp and transactionId.
// In case two events are both pending and have the same timestamp,
@@ -150,6 +159,11 @@ export interface TransactionCommon {
txState: TransactionState;
/**
+ * Possible transitions based on the current state.
+ */
+ txActions: string[];
+
+ /**
* Raw amount of the transaction (exclusive of fees or other extra costs).
*/
amountRaw: AmountString;
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index 3147cb9b9..74332de33 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -1131,7 +1131,7 @@ export enum PurchaseStatus {
/**
* Proposal downloaded, but the user needs to accept/reject it.
*/
- Proposed = 30,
+ DialogProposed = 30,
/**
* The user has rejected the proposal.
diff --git a/packages/taler-wallet-core/src/operations/backup/export.ts b/packages/taler-wallet-core/src/operations/backup/export.ts
index 0aca45551..23c6e787a 100644
--- a/packages/taler-wallet-core/src/operations/backup/export.ts
+++ b/packages/taler-wallet-core/src/operations/backup/export.ts
@@ -418,7 +418,7 @@ export async function exportBackup(
break;
case PurchaseStatus.PendingPayingReplay:
case PurchaseStatus.PendingDownloadingProposal:
- case PurchaseStatus.Proposed:
+ case PurchaseStatus.DialogProposed:
case PurchaseStatus.PendingPaying:
propStatus = BackupProposalStatus.Proposed;
break;
diff --git a/packages/taler-wallet-core/src/operations/backup/import.ts b/packages/taler-wallet-core/src/operations/backup/import.ts
index 5efdb78c1..d3346a3a2 100644
--- a/packages/taler-wallet-core/src/operations/backup/import.ts
+++ b/packages/taler-wallet-core/src/operations/backup/import.ts
@@ -578,7 +578,7 @@ export async function importBackup(
proposalStatus = PurchaseStatus.Done;
break;
case BackupProposalStatus.Proposed:
- proposalStatus = PurchaseStatus.Proposed;
+ proposalStatus = PurchaseStatus.DialogProposed;
break;
case BackupProposalStatus.PermanentlyFailed:
proposalStatus = PurchaseStatus.AbortedIncompletePayment;
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts b/packages/taler-wallet-core/src/operations/deposits.ts
index 1ed2a705e..6387fc9b7 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -59,11 +59,11 @@ import {
TransactionType,
URL,
WireFee,
+ TransactionAction,
} from "@gnu-taler/taler-util";
import {
DenominationRecord,
DepositGroupRecord,
- OperationStatus,
DepositElementStatus,
} from "../db.js";
import { TalerError } from "@gnu-taler/taler-util";
@@ -115,6 +115,7 @@ export function computeDepositTransactionStatus(
major: TransactionMajorState.Done,
};
}
+ // FIXME: We should actually use separate pending states for this!
case DepositOperationStatus.Pending: {
const numTotal = dg.payCoinSelection.coinPubs.length;
let numDeposited = 0;
@@ -134,9 +135,6 @@ export function computeDepositTransactionStatus(
}
}
- logger.info(`num total ${numTotal}`);
- logger.info(`num deposited ${numDeposited}`);
-
if (numKycRequired > 0) {
return {
major: TransactionMajorState.Pending,
@@ -181,6 +179,57 @@ export function computeDepositTransactionStatus(
}
}
+export function computeDepositTransactionActions(
+ dg: DepositGroupRecord,
+): TransactionAction[] {
+ switch (dg.operationStatus) {
+ case DepositOperationStatus.Finished: {
+ return [TransactionAction.Delete];
+ }
+ case DepositOperationStatus.Pending: {
+ const numTotal = dg.payCoinSelection.coinPubs.length;
+ let numDeposited = 0;
+ let numKycRequired = 0;
+ let numWired = 0;
+ for (let i = 0; i < numTotal; i++) {
+ if (dg.depositedPerCoin[i]) {
+ numDeposited++;
+ }
+ switch (dg.transactionPerCoin[i]) {
+ case DepositElementStatus.KycRequired:
+ numKycRequired++;
+ break;
+ case DepositElementStatus.Wired:
+ numWired++;
+ break;
+ }
+ }
+
+ if (numKycRequired > 0) {
+ return [TransactionAction.Suspend, TransactionAction.Fail];
+ }
+
+ if (numDeposited == numTotal) {
+ return [TransactionAction.Suspend, TransactionAction.Fail];
+ }
+
+ return [TransactionAction.Suspend, TransactionAction.Abort];
+ }
+ case DepositOperationStatus.Suspended:
+ return [TransactionAction.Resume];
+ case DepositOperationStatus.Aborting:
+ return [TransactionAction.Fail, TransactionAction.Suspend];
+ case DepositOperationStatus.Aborted:
+ return [TransactionAction.Delete];
+ case DepositOperationStatus.Failed:
+ return [TransactionAction.Delete];
+ case DepositOperationStatus.SuspendedAborting:
+ return [TransactionAction.Resume, TransactionAction.Fail];
+ default:
+ throw Error(`unexpected deposit group state (${dg.operationStatus})`);
+ }
+}
+
export async function suspendDepositGroup(
ws: InternalWalletState,
depositGroupId: string,
@@ -309,7 +358,7 @@ export async function abortDepositGroup(
notifyTransition(ws, transactionId, transitionInfo);
}
-export async function cancelAbortingDepositGroup(
+export async function failDepositTransaction(
ws: InternalWalletState,
depositGroupId: string,
): Promise<void> {
diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts b/packages/taler-wallet-core/src/operations/pay-merchant.ts
index 8462f2fb9..dce2a30ed 100644
--- a/packages/taler-wallet-core/src/operations/pay-merchant.ts
+++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts
@@ -70,6 +70,7 @@ import {
TalerProtocolTimestamp,
TalerProtocolViolationError,
TalerUriAction,
+ TransactionAction,
TransactionMajorState,
TransactionMinorState,
TransactionState,
@@ -547,7 +548,7 @@ async function processDownloadProposal(
await tx.purchases.put(p);
}
} else {
- p.purchaseStatus = PurchaseStatus.Proposed;
+ p.purchaseStatus = PurchaseStatus.DialogProposed;
await tx.purchases.put(p);
}
const newTxState = computePayMerchantTransactionState(p);
@@ -994,7 +995,7 @@ export async function checkPaymentByProposalId(
return tx.purchases.get(proposalId);
});
- if (!purchase || purchase.purchaseStatus === PurchaseStatus.Proposed) {
+ if (!purchase || purchase.purchaseStatus === PurchaseStatus.DialogProposed) {
// If not already paid, check if we could pay for it.
const res = await selectPayCoinsNew(ws, {
auditors: [],
@@ -1417,7 +1418,7 @@ export async function confirmPay(
}
const oldTxState = computePayMerchantTransactionState(p);
switch (p.purchaseStatus) {
- case PurchaseStatus.Proposed:
+ case PurchaseStatus.DialogProposed:
p.payInfo = {
payCoinSelection: coinSelection,
payCoinSelectionUid: encodeCrock(getRandomBytes(16)),
@@ -1498,7 +1499,7 @@ export async function processPurchase(
case PurchaseStatus.FailedClaim:
case PurchaseStatus.Done:
case PurchaseStatus.RepurchaseDetected:
- case PurchaseStatus.Proposed:
+ case PurchaseStatus.DialogProposed:
case PurchaseStatus.AbortedProposalRefused:
case PurchaseStatus.AbortedIncompletePayment:
case PurchaseStatus.SuspendedAbortingWithRefund:
@@ -1713,7 +1714,7 @@ export async function refuseProposal(
logger.trace(`proposal ${proposalId} not found, won't refuse proposal`);
return undefined;
}
- if (proposal.purchaseStatus !== PurchaseStatus.Proposed) {
+ if (proposal.purchaseStatus !== PurchaseStatus.DialogProposed) {
return undefined;
}
const oldTxState = computePayMerchantTransactionState(proposal);
@@ -1791,7 +1792,7 @@ export async function abortPayMerchant(
ws.workAvailable.trigger();
}
-export async function cancelAbortingPaymentTransaction(
+export async function failPaymentTransaction(
ws: InternalWalletState,
proposalId: string,
): Promise<void> {
@@ -2023,7 +2024,7 @@ export function computePayMerchantTransactionState(
major: TransactionMajorState.SuspendedAborting,
};
// Dialog States
- case PurchaseStatus.Proposed:
+ case PurchaseStatus.DialogProposed:
return {
major: TransactionMajorState.Dialog,
minor: TransactionMinorState.MerchantOrderProposed,
@@ -2060,6 +2061,68 @@ export function computePayMerchantTransactionState(
}
}
+export function computePayMerchantTransactionActions(
+ purchaseRecord: PurchaseRecord,
+): TransactionAction[] {
+ switch (purchaseRecord.purchaseStatus) {
+ // Pending States
+ case PurchaseStatus.PendingDownloadingProposal:
+ return [TransactionAction.Suspend, TransactionAction.Abort];
+ case PurchaseStatus.PendingPaying:
+ return [TransactionAction.Suspend, TransactionAction.Abort];
+ case PurchaseStatus.PendingPayingReplay:
+ // Special "abort" since it goes back to "done".
+ return [TransactionAction.Suspend, TransactionAction.Abort];
+ case PurchaseStatus.PendingQueryingAutoRefund:
+ // Special "abort" since it goes back to "done".
+ return [TransactionAction.Suspend, TransactionAction.Abort];
+ case PurchaseStatus.PendingQueryingRefund:
+ // Special "abort" since it goes back to "done".
+ return [TransactionAction.Suspend, TransactionAction.Abort];
+ case PurchaseStatus.PendingAcceptRefund:
+ // Special "abort" since it goes back to "done".
+ return [TransactionAction.Suspend, TransactionAction.Abort];
+ // Suspended Pending States
+ case PurchaseStatus.SuspendedDownloadingProposal:
+ return [TransactionAction.Resume, TransactionAction.Abort];
+ case PurchaseStatus.SuspendedPaying:
+ return [TransactionAction.Resume, TransactionAction.Abort];
+ case PurchaseStatus.SuspendedPayingReplay:
+ // Special "abort" since it goes back to "done".
+ return [TransactionAction.Resume, TransactionAction.Abort];
+ case PurchaseStatus.SuspendedQueryingAutoRefund:
+ // Special "abort" since it goes back to "done".
+ return [TransactionAction.Resume, TransactionAction.Abort];
+ case PurchaseStatus.SuspendedQueryingRefund:
+ // Special "abort" since it goes back to "done".
+ return [TransactionAction.Resume, TransactionAction.Abort];
+ case PurchaseStatus.SuspendedPendingAcceptRefund:
+ // Special "abort" since it goes back to "done".
+ return [TransactionAction.Resume, TransactionAction.Abort];
+ // Aborting States
+ case PurchaseStatus.AbortingWithRefund:
+ return [TransactionAction.Fail, TransactionAction.Suspend];
+ case PurchaseStatus.SuspendedAbortingWithRefund:
+ return [TransactionAction.Fail, TransactionAction.Resume];
+ // Dialog States
+ case PurchaseStatus.DialogProposed:
+ return [];
+ // Final States
+ case PurchaseStatus.AbortedProposalRefused:
+ return [TransactionAction.Delete];
+ case PurchaseStatus.Done:
+ return [TransactionAction.Delete];
+ case PurchaseStatus.RepurchaseDetected:
+ return [TransactionAction.Delete];
+ case PurchaseStatus.AbortedIncompletePayment:
+ return [TransactionAction.Delete];
+ case PurchaseStatus.FailedClaim:
+ return [TransactionAction.Delete];
+ case PurchaseStatus.FailedAbort:
+ return [TransactionAction.Delete];
+ }
+}
+
async function processPurchaseAutoRefund(
ws: InternalWalletState,
purchase: PurchaseRecord,
diff --git a/packages/taler-wallet-core/src/operations/pay-peer.ts b/packages/taler-wallet-core/src/operations/pay-peer.ts
index 031bdfb92..edebad65b 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer.ts
@@ -79,6 +79,7 @@ import {
TransactionMajorState,
TransactionMinorState,
TalerPreciseTimestamp,
+ TransactionAction,
} from "@gnu-taler/taler-util";
import { SpendCoinDetails } from "../crypto/cryptoImplementation.js";
import {
@@ -2008,7 +2009,36 @@ export function computePeerPushDebitTransactionState(
case PeerPushPaymentInitiationStatus.Failed:
return {
major: TransactionMajorState.Failed,
- }
+ };
+ }
+}
+
+export function computePeerPushDebitTransactionActions(
+ ppiRecord: PeerPushPaymentInitiationRecord,
+): TransactionAction[] {
+ switch (ppiRecord.status) {
+ case PeerPushPaymentInitiationStatus.PendingCreatePurse:
+ return [TransactionAction.Abort, TransactionAction.Suspend];
+ case PeerPushPaymentInitiationStatus.PendingReady:
+ return [TransactionAction.Abort, TransactionAction.Suspend];
+ case PeerPushPaymentInitiationStatus.Aborted:
+ return [TransactionAction.Delete];
+ case PeerPushPaymentInitiationStatus.AbortingDeletePurse:
+ return [TransactionAction.Suspend, TransactionAction.Fail];
+ case PeerPushPaymentInitiationStatus.AbortingRefresh:
+ return [TransactionAction.Suspend, TransactionAction.Fail];
+ case PeerPushPaymentInitiationStatus.SuspendedAbortingDeletePurse:
+ return [TransactionAction.Resume, TransactionAction.Fail];
+ case PeerPushPaymentInitiationStatus.SuspendedAbortingRefresh:
+ return [TransactionAction.Resume, TransactionAction.Fail];
+ case PeerPushPaymentInitiationStatus.SuspendedCreatePurse:
+ return [TransactionAction.Resume, TransactionAction.Abort];
+ case PeerPushPaymentInitiationStatus.SuspendedReady:
+ return [TransactionAction.Suspend, TransactionAction.Abort];
+ case PeerPushPaymentInitiationStatus.Done:
+ return [TransactionAction.Delete];
+ case PeerPushPaymentInitiationStatus.Failed:
+ return [TransactionAction.Delete];
}
}
@@ -2072,7 +2102,7 @@ export async function abortPeerPushDebitTransaction(
notifyTransition(ws, transactionId, transitionInfo);
}
-export async function cancelAbortingPeerPushDebitTransaction(
+export async function failPeerPushDebitTransaction(
ws: InternalWalletState,
pursePub: string,
) {
@@ -2316,8 +2346,7 @@ export async function abortPeerPullDebitTransaction(
notifyTransition(ws, transactionId, transitionInfo);
}
-
-export async function cancelAbortingPeerPullDebitTransaction(
+export async function failPeerPullDebitTransaction(
ws: InternalWalletState,
peerPullPaymentIncomingId: string,
) {
@@ -2501,7 +2530,6 @@ export async function suspendPeerPushCreditTransaction(
notifyTransition(ws, transactionId, transitionInfo);
}
-
export async function abortPeerPushCreditTransaction(
ws: InternalWalletState,
peerPushPaymentIncomingId: string,
@@ -2568,7 +2596,7 @@ export async function abortPeerPushCreditTransaction(
notifyTransition(ws, transactionId, transitionInfo);
}
-export async function cancelAbortingPeerPushCreditTransaction(
+export async function failPeerPushCreditTransaction(
ws: InternalWalletState,
peerPushPaymentIncomingId: string,
) {
@@ -2765,7 +2793,7 @@ export async function abortPeerPullCreditTransaction(
notifyTransition(ws, transactionId, transitionInfo);
}
-export async function cancelAbortingPeerPullCreditTransaction(
+export async function failPeerPullCreditTransaction(
ws: InternalWalletState,
pursePub: string,
) {
@@ -2996,12 +3024,41 @@ export function computePeerPushCreditTransactionState(
};
case PeerPushPaymentIncomingStatus.Aborted:
return {
- major: TransactionMajorState.Aborted
+ major: TransactionMajorState.Aborted,
};
case PeerPushPaymentIncomingStatus.Failed:
return {
major: TransactionMajorState.Failed,
- }
+ };
+ default:
+ assertUnreachable(pushCreditRecord.status);
+ }
+}
+
+export function computePeerPushCreditTransactionActions(
+ pushCreditRecord: PeerPushPaymentIncomingRecord,
+): TransactionAction[] {
+ switch (pushCreditRecord.status) {
+ case PeerPushPaymentIncomingStatus.DialogProposed:
+ return [];
+ case PeerPushPaymentIncomingStatus.PendingMerge:
+ return [TransactionAction.Abort, TransactionAction.Suspend];
+ case PeerPushPaymentIncomingStatus.Done:
+ return [TransactionAction.Delete];
+ case PeerPushPaymentIncomingStatus.PendingMergeKycRequired:
+ return [TransactionAction.Abort, TransactionAction.Suspend];
+ case PeerPushPaymentIncomingStatus.PendingWithdrawing:
+ return [TransactionAction.Suspend, TransactionAction.Fail];
+ case PeerPushPaymentIncomingStatus.SuspendedMerge:
+ return [TransactionAction.Resume, TransactionAction.Abort];
+ case PeerPushPaymentIncomingStatus.SuspendedMergeKycRequired:
+ return [TransactionAction.Resume, TransactionAction.Abort];
+ case PeerPushPaymentIncomingStatus.SuspendedWithdrawing:
+ return [TransactionAction.Resume, TransactionAction.Fail];
+ case PeerPushPaymentIncomingStatus.Aborted:
+ return [TransactionAction.Delete];
+ case PeerPushPaymentIncomingStatus.Failed:
+ return [TransactionAction.Delete];
default:
assertUnreachable(pushCreditRecord.status);
}
@@ -3076,6 +3133,39 @@ export function computePeerPullCreditTransactionState(
}
}
+export function computePeerPullCreditTransactionActions(
+ pullCreditRecord: PeerPullPaymentInitiationRecord,
+): TransactionAction[] {
+ switch (pullCreditRecord.status) {
+ case PeerPullPaymentInitiationStatus.PendingCreatePurse:
+ return [TransactionAction.Abort, TransactionAction.Suspend];
+ case PeerPullPaymentInitiationStatus.PendingMergeKycRequired:
+ return [TransactionAction.Abort, TransactionAction.Suspend];
+ case PeerPullPaymentInitiationStatus.PendingReady:
+ return [TransactionAction.Abort, TransactionAction.Suspend];
+ case PeerPullPaymentInitiationStatus.DonePurseDeposited:
+ return [TransactionAction.Delete];
+ case PeerPullPaymentInitiationStatus.PendingWithdrawing:
+ return [TransactionAction.Abort, TransactionAction.Suspend];
+ case PeerPullPaymentInitiationStatus.SuspendedCreatePurse:
+ return [TransactionAction.Resume, TransactionAction.Abort];
+ case PeerPullPaymentInitiationStatus.SuspendedReady:
+ return [TransactionAction.Abort, TransactionAction.Resume];
+ case PeerPullPaymentInitiationStatus.SuspendedWithdrawing:
+ return [TransactionAction.Resume, TransactionAction.Fail];
+ case PeerPullPaymentInitiationStatus.SuspendedMergeKycRequired:
+ return [TransactionAction.Resume, TransactionAction.Fail];
+ case PeerPullPaymentInitiationStatus.Aborted:
+ return [TransactionAction.Delete];
+ case PeerPullPaymentInitiationStatus.AbortingDeletePurse:
+ return [TransactionAction.Suspend, TransactionAction.Fail];
+ case PeerPullPaymentInitiationStatus.Failed:
+ return [TransactionAction.Delete];
+ case PeerPullPaymentInitiationStatus.SuspendedAbortingDeletePurse:
+ return [TransactionAction.Resume, TransactionAction.Fail];
+ }
+}
+
export function computePeerPullDebitTransactionState(
pullDebitRecord: PeerPullPaymentIncomingRecord,
): TransactionState {
@@ -3119,3 +3209,26 @@ export function computePeerPullDebitTransactionState(
};
}
}
+
+export function computePeerPullDebitTransactionActions(
+ pullDebitRecord: PeerPullPaymentIncomingRecord,
+): TransactionAction[] {
+ switch (pullDebitRecord.status) {
+ case PeerPullDebitRecordStatus.DialogProposed:
+ return [];
+ case PeerPullDebitRecordStatus.PendingDeposit:
+ return [TransactionAction.Abort, TransactionAction.Suspend];
+ case PeerPullDebitRecordStatus.DonePaid:
+ return [TransactionAction.Delete];
+ case PeerPullDebitRecordStatus.SuspendedDeposit:
+ return [TransactionAction.Resume, TransactionAction.Abort];
+ case PeerPullDebitRecordStatus.Aborted:
+ return [TransactionAction.Delete];
+ case PeerPullDebitRecordStatus.AbortingRefresh:
+ return [TransactionAction.Fail, TransactionAction.Suspend];
+ case PeerPullDebitRecordStatus.Failed:
+ return [TransactionAction.Delete];
+ case PeerPullDebitRecordStatus.SuspendedAbortingRefresh:
+ return [TransactionAction.Resume, TransactionAction.Fail];
+ }
+}
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts b/packages/taler-wallet-core/src/operations/refresh.ts
index 8437d2d0b..c2cf13857 100644
--- a/packages/taler-wallet-core/src/operations/refresh.ts
+++ b/packages/taler-wallet-core/src/operations/refresh.ts
@@ -50,6 +50,7 @@ import {
TalerErrorDetail,
TalerPreciseTimestamp,
TalerProtocolTimestamp,
+ TransactionAction,
TransactionMajorState,
TransactionState,
TransactionType,
@@ -96,7 +97,10 @@ import {
PendingTaskType,
WalletConfig,
} from "../index.js";
-import { constructTransactionIdentifier, notifyTransition } from "./transactions.js";
+import {
+ constructTransactionIdentifier,
+ notifyTransition,
+} from "./transactions.js";
const logger = new Logger("refresh.ts");
@@ -1076,8 +1080,12 @@ export async function createRefreshGroup(
* Timestamp after which the wallet would do the next check for an auto-refresh.
*/
function getAutoRefreshCheckThreshold(d: DenominationRecord): AbsoluteTime {
- const expireWithdraw = AbsoluteTime.fromProtocolTimestamp(d.stampExpireWithdraw);
- const expireDeposit = AbsoluteTime.fromProtocolTimestamp(d.stampExpireDeposit);
+ const expireWithdraw = AbsoluteTime.fromProtocolTimestamp(
+ d.stampExpireWithdraw,
+ );
+ const expireDeposit = AbsoluteTime.fromProtocolTimestamp(
+ d.stampExpireDeposit,
+ );
const delta = AbsoluteTime.difference(expireWithdraw, expireDeposit);
const deltaDiv = durationMul(delta, 0.75);
return AbsoluteTime.addDuration(expireWithdraw, deltaDiv);
@@ -1087,8 +1095,12 @@ function getAutoRefreshCheckThreshold(d: DenominationRecord): AbsoluteTime {
* Timestamp after which the wallet would do an auto-refresh.
*/
function getAutoRefreshExecuteThreshold(d: DenominationRecord): AbsoluteTime {
- const expireWithdraw = AbsoluteTime.fromProtocolTimestamp(d.stampExpireWithdraw);
- const expireDeposit = AbsoluteTime.fromProtocolTimestamp(d.stampExpireDeposit);
+ const expireWithdraw = AbsoluteTime.fromProtocolTimestamp(
+ d.stampExpireWithdraw,
+ );
+ const expireDeposit = AbsoluteTime.fromProtocolTimestamp(
+ d.stampExpireDeposit,
+ );
const delta = AbsoluteTime.difference(expireWithdraw, expireDeposit);
const deltaDiv = durationMul(delta, 0.5);
return AbsoluteTime.addDuration(expireWithdraw, deltaDiv);
@@ -1175,7 +1187,8 @@ export async function autoRefresh(
logger.info(
`next refresh check at ${AbsoluteTime.toIsoString(minCheckThreshold)}`,
);
- exchange.nextRefreshCheck = AbsoluteTime.toPreciseTimestamp(minCheckThreshold);
+ exchange.nextRefreshCheck =
+ AbsoluteTime.toPreciseTimestamp(minCheckThreshold);
await tx.exchanges.put(exchange);
});
return OperationAttemptResult.finishedEmpty();
@@ -1204,6 +1217,21 @@ export function computeRefreshTransactionState(
}
}
+export function computeRefreshTransactionActions(
+ rg: RefreshGroupRecord,
+): TransactionAction[] {
+ switch (rg.operationStatus) {
+ case RefreshOperationStatus.Finished:
+ return [TransactionAction.Delete];
+ case RefreshOperationStatus.Failed:
+ return [TransactionAction.Delete];
+ case RefreshOperationStatus.Pending:
+ return [TransactionAction.Suspend, TransactionAction.Fail];
+ case RefreshOperationStatus.Suspended:
+ return [TransactionAction.Resume, TransactionAction.Fail];
+ }
+}
+
export async function suspendRefreshGroup(
ws: InternalWalletState,
refreshGroupId: string,
@@ -1292,7 +1320,7 @@ export async function resumeRefreshGroup(
notifyTransition(ws, transactionId, transitionInfo);
}
-export async function cancelAbortingRefreshGroup(
+export async function failRefreshGroup(
ws: InternalWalletState,
refreshGroupId: string,
): Promise<void> {
@@ -1321,7 +1349,7 @@ export async function abortRefreshGroup(
let newStatus: RefreshOperationStatus | undefined;
switch (dg.operationStatus) {
case RefreshOperationStatus.Finished:
- break;;
+ break;
case RefreshOperationStatus.Pending:
case RefreshOperationStatus.Suspended:
newStatus = RefreshOperationStatus.Failed;
diff --git a/packages/taler-wallet-core/src/operations/tip.ts b/packages/taler-wallet-core/src/operations/tip.ts
index 0bee2b406..02c933cba 100644
--- a/packages/taler-wallet-core/src/operations/tip.ts
+++ b/packages/taler-wallet-core/src/operations/tip.ts
@@ -36,6 +36,7 @@ import {
TalerPreciseTimestamp,
TalerProtocolTimestamp,
TipPlanchetDetail,
+ TransactionAction,
TransactionMajorState,
TransactionMinorState,
TransactionState,
@@ -111,6 +112,24 @@ export function computeTipTransactionStatus(
}
}
+
+export function computeTipTransactionActions(
+ tipRecord: TipRecord,
+): TransactionAction[] {
+ switch (tipRecord.status) {
+ case TipRecordStatus.Done:
+ return [TransactionAction.Delete];
+ case TipRecordStatus.Aborted:
+ return [TransactionAction.Delete];
+ case TipRecordStatus.PendingPickup:
+ return [TransactionAction.Suspend, TransactionAction.Fail];
+ case TipRecordStatus.SuspendidPickup:
+ return [TransactionAction.Resume, TransactionAction.Fail];
+ default:
+ assertUnreachable(tipRecord.status);
+ }
+}
+
export async function prepareTip(
ws: InternalWalletState,
talerTipUri: string,
@@ -526,7 +545,7 @@ export async function resumeTipTransaction(
notifyTransition(ws, transactionId, transitionInfo);
}
-export async function cancelAbortingTipTransaction(
+export async function failTipTransaction(
ws: InternalWalletState,
walletTipId: string,
): Promise<void> {
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts
index d424019ac..a0da95799 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -73,32 +73,34 @@ import { constructTaskIdentifier, TaskIdentifiers } from "../util/retries.js";
import { resetOperationTimeout, TombstoneTag } from "./common.js";
import {
abortDepositGroup,
- cancelAbortingDepositGroup,
+ failDepositTransaction,
computeDepositTransactionStatus,
deleteDepositGroup,
resumeDepositGroup,
suspendDepositGroup,
+ computeDepositTransactionActions,
} from "./deposits.js";
import { getExchangeDetails } from "./exchanges.js";
import {
abortPayMerchant,
- cancelAbortingPaymentTransaction,
+ failPaymentTransaction,
computePayMerchantTransactionState,
computeRefundTransactionState,
expectProposalDownload,
extractContractData,
resumePayMerchant,
suspendPayMerchant,
+ computePayMerchantTransactionActions,
} from "./pay-merchant.js";
import {
abortPeerPullCreditTransaction,
abortPeerPullDebitTransaction,
abortPeerPushCreditTransaction,
abortPeerPushDebitTransaction,
- cancelAbortingPeerPullCreditTransaction,
- cancelAbortingPeerPullDebitTransaction,
- cancelAbortingPeerPushCreditTransaction,
- cancelAbortingPeerPushDebitTransaction,
+ failPeerPullCreditTransaction,
+ failPeerPullDebitTransaction,
+ failPeerPushCreditTransaction,
+ failPeerPushDebitTransaction,
computePeerPullCreditTransactionState,
computePeerPullDebitTransactionState,
computePeerPushCreditTransactionState,
@@ -111,28 +113,35 @@ import {
suspendPeerPullDebitTransaction,
suspendPeerPushCreditTransaction,
suspendPeerPushDebitTransaction,
+ computePeerPushDebitTransactionActions,
+ computePeerPullDebitTransactionActions,
+ computePeerPullCreditTransactionActions,
+ computePeerPushCreditTransactionActions,
} from "./pay-peer.js";
import {
abortRefreshGroup,
- cancelAbortingRefreshGroup,
+ failRefreshGroup,
computeRefreshTransactionState,
resumeRefreshGroup,
suspendRefreshGroup,
+ computeRefreshTransactionActions,
} from "./refresh.js";
import {
abortTipTransaction,
- cancelAbortingTipTransaction,
+ failTipTransaction,
computeTipTransactionStatus,
resumeTipTransaction,
suspendTipTransaction,
+ computeTipTransactionActions,
} from "./tip.js";
import {
abortWithdrawalTransaction,
augmentPaytoUrisForWithdrawal,
- cancelAbortingWithdrawalTransaction,
+ failWithdrawalTransaction,
computeWithdrawalTransactionStatus,
resumeWithdrawalTransaction,
suspendWithdrawalTransaction,
+ computeWithdrawalTransactionActions,
} from "./withdraw.js";
const logger = new Logger("taler-wallet-core:transactions.ts");
@@ -429,6 +438,7 @@ function buildTransactionForPushPaymentDebit(
return {
type: TransactionType.PeerPushDebit,
txState: computePeerPushDebitTransactionState(pi),
+ txActions: computePeerPushDebitTransactionActions(pi),
amountEffective: pi.totalCost,
amountRaw: pi.amount,
exchangeBaseUrl: pi.exchangeBaseUrl,
@@ -456,6 +466,7 @@ function buildTransactionForPullPaymentDebit(
return {
type: TransactionType.PeerPullDebit,
txState: computePeerPullDebitTransactionState(pi),
+ txActions: computePeerPullDebitTransactionActions(pi),
amountEffective: pi.coinSel?.totalCost
? pi.coinSel?.totalCost
: Amounts.stringify(pi.contractTerms.amount),
@@ -503,6 +514,7 @@ function buildTransactionForPeerPullCredit(
return {
type: TransactionType.PeerPullCredit,
txState: computePeerPullCreditTransactionState(pullCredit),
+ txActions: computePeerPullCreditTransactionActions(pullCredit),
amountEffective: Amounts.stringify(wsr.denomsSel.totalCoinValue),
amountRaw: Amounts.stringify(wsr.instructedAmount),
exchangeBaseUrl: wsr.exchangeBaseUrl,
@@ -533,6 +545,7 @@ function buildTransactionForPeerPullCredit(
return {
type: TransactionType.PeerPullCredit,
txState: computePeerPullCreditTransactionState(pullCredit),
+ txActions: computePeerPullCreditTransactionActions(pullCredit),
amountEffective: Amounts.stringify(pullCredit.estimatedAmountEffective),
amountRaw: Amounts.stringify(peerContractTerms.amount),
exchangeBaseUrl: pullCredit.exchangeBaseUrl,
@@ -569,6 +582,7 @@ function buildTransactionForPeerPushCredit(
return {
type: TransactionType.PeerPushCredit,
txState: computePeerPushCreditTransactionState(pushInc),
+ txActions: computePeerPushCreditTransactionActions(pushInc),
amountEffective: Amounts.stringify(wsr.denomsSel.totalCoinValue),
amountRaw: Amounts.stringify(wsr.instructedAmount),
exchangeBaseUrl: wsr.exchangeBaseUrl,
@@ -588,6 +602,7 @@ function buildTransactionForPeerPushCredit(
return {
type: TransactionType.PeerPushCredit,
txState: computePeerPushCreditTransactionState(pushInc),
+ txActions: computePeerPushCreditTransactionActions(pushInc),
// FIXME: This is wrong, needs to consider fees!
amountEffective: Amounts.stringify(peerContractTerms.amount),
amountRaw: Amounts.stringify(peerContractTerms.amount),
@@ -615,6 +630,7 @@ function buildTransactionForBankIntegratedWithdraw(
return {
type: TransactionType.Withdrawal,
txState: computeWithdrawalTransactionStatus(wgRecord),
+ txActions: computeWithdrawalTransactionActions(wgRecord),
amountEffective: Amounts.stringify(wgRecord.denomsSel.totalCoinValue),
amountRaw: Amounts.stringify(wgRecord.instructedAmount),
withdrawalDetails: {
@@ -656,6 +672,7 @@ function buildTransactionForManualWithdraw(
return {
type: TransactionType.Withdrawal,
txState: computeWithdrawalTransactionStatus(withdrawalGroup),
+ txActions: computeWithdrawalTransactionActions(withdrawalGroup),
amountEffective: Amounts.stringify(
withdrawalGroup.denomsSel.totalCoinValue,
),
@@ -706,6 +723,7 @@ function buildTransactionForRefund(
refundGroupId: refundRecord.refundGroupId,
}),
txState: computeRefundTransactionState(refundRecord),
+ txActions: [],
paymentInfo,
};
}
@@ -725,6 +743,7 @@ function buildTransactionForRefresh(
return {
type: TransactionType.Refresh,
txState: computeRefreshTransactionState(refreshGroupRecord),
+ txActions: computeRefreshTransactionActions(refreshGroupRecord),
refreshReason: refreshGroupRecord.reason,
amountEffective: Amounts.stringify(
Amounts.zeroOfCurrency(refreshGroupRecord.currency),
@@ -759,6 +778,7 @@ function buildTransactionForDeposit(
return {
type: TransactionType.Deposit,
txState: computeDepositTransactionStatus(dg),
+ txActions: computeDepositTransactionActions(dg),
amountRaw: Amounts.stringify(dg.effectiveDepositAmount),
amountEffective: Amounts.stringify(dg.totalPayCost),
timestamp: dg.timestampCreated,
@@ -791,6 +811,7 @@ function buildTransactionForTip(
return {
type: TransactionType.Tip,
txState: computeTipTransactionStatus(tipRecord),
+ txActions: computeTipTransactionActions(tipRecord),
amountEffective: Amounts.stringify(tipRecord.tipAmountEffective),
amountRaw: Amounts.stringify(tipRecord.tipAmountRaw),
timestamp: tipRecord.acceptedTimestamp,
@@ -860,6 +881,7 @@ async function buildTransactionForPurchase(
return {
type: TransactionType.Payment,
txState: computePayMerchantTransactionState(purchaseRecord),
+ txActions: computePayMerchantTransactionActions(purchaseRecord),
amountRaw: Amounts.stringify(contractData.amount),
amountEffective: Amounts.stringify(purchaseRecord.payInfo.totalPayCost),
totalRefundRaw: Amounts.stringify(zero), // FIXME!
@@ -1493,7 +1515,7 @@ export async function suspendTransaction(
}
}
-export async function cancelAbortingTransaction(
+export async function failTransaction(
ws: InternalWalletState,
transactionId: string,
): Promise<void> {
@@ -1503,34 +1525,34 @@ export async function cancelAbortingTransaction(
}
switch (tx.tag) {
case TransactionType.Deposit:
- await cancelAbortingDepositGroup(ws, tx.depositGroupId);
+ await failDepositTransaction(ws, tx.depositGroupId);
return;
case TransactionType.InternalWithdrawal:
case TransactionType.Withdrawal:
- await cancelAbortingWithdrawalTransaction(ws, tx.withdrawalGroupId);
+ await failWithdrawalTransaction(ws, tx.withdrawalGroupId);
return;
case TransactionType.Payment:
- await cancelAbortingPaymentTransaction(ws, tx.proposalId);
+ await failPaymentTransaction(ws, tx.proposalId);
return;
case TransactionType.Refund:
throw Error("can't do cancel-aborting on refund transaction");
case TransactionType.Tip:
- await cancelAbortingTipTransaction(ws, tx.walletTipId);
+ await failTipTransaction(ws, tx.walletTipId);
return;
case TransactionType.Refresh:
- await cancelAbortingRefreshGroup(ws, tx.refreshGroupId);
+ await failRefreshGroup(ws, tx.refreshGroupId);
return;
case TransactionType.PeerPullCredit:
- await cancelAbortingPeerPullCreditTransaction(ws, tx.pursePub);
+ await failPeerPullCreditTransaction(ws, tx.pursePub);
return;
case TransactionType.PeerPullDebit:
- await cancelAbortingPeerPullDebitTransaction(ws, tx.peerPullPaymentIncomingId);
+ await failPeerPullDebitTransaction(ws, tx.peerPullPaymentIncomingId);
return;
case TransactionType.PeerPushCredit:
- await cancelAbortingPeerPushCreditTransaction(ws, tx.peerPushPaymentIncomingId);
+ await failPeerPushCreditTransaction(ws, tx.peerPushPaymentIncomingId);
return;
case TransactionType.PeerPushDebit:
- await cancelAbortingPeerPushDebitTransaction(ws, tx.pursePub);
+ await failPeerPushDebitTransaction(ws, tx.pursePub);
return;
default:
assertUnreachable(tx);
diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts
index e08aa59a7..4801a67ee 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.ts
@@ -67,6 +67,7 @@ import {
TransactionMajorState,
TransactionMinorState,
TalerPreciseTimestamp,
+ TransactionAction,
} from "@gnu-taler/taler-util";
import { EddsaKeypair } from "../crypto/cryptoImplementation.js";
import {
@@ -338,7 +339,7 @@ export async function abortWithdrawalTransaction(
notifyTransition(ws, transactionId, transitionInfo);
}
-export async function cancelAbortingWithdrawalTransaction(
+export async function failWithdrawalTransaction(
ws: InternalWalletState,
withdrawalGroupId: string,
) {
@@ -483,6 +484,49 @@ export function computeWithdrawalTransactionStatus(
}
}
+export function computeWithdrawalTransactionActions(
+ wgRecord: WithdrawalGroupRecord,
+): TransactionAction[] {
+ switch (wgRecord.status) {
+ case WithdrawalGroupStatus.FailedBankAborted:
+ return [TransactionAction.Delete];
+ case WithdrawalGroupStatus.Finished:
+ return [TransactionAction.Delete];
+ case WithdrawalGroupStatus.PendingRegisteringBank:
+ return [TransactionAction.Suspend, TransactionAction.Abort];
+ case WithdrawalGroupStatus.PendingReady:
+ return [TransactionAction.Suspend, TransactionAction.Abort];
+ case WithdrawalGroupStatus.PendingQueryingStatus:
+ return [TransactionAction.Suspend, TransactionAction.Abort];
+ case WithdrawalGroupStatus.PendingWaitConfirmBank:
+ return [TransactionAction.Suspend, TransactionAction.Abort];
+ case WithdrawalGroupStatus.AbortingBank:
+ return [TransactionAction.Suspend, TransactionAction.Fail];
+ case WithdrawalGroupStatus.SuspendedAbortingBank:
+ return [TransactionAction.Resume, TransactionAction.Fail];
+ case WithdrawalGroupStatus.SuspendedQueryingStatus:
+ return [TransactionAction.Resume, TransactionAction.Abort];
+ case WithdrawalGroupStatus.SuspendedRegisteringBank:
+ return [TransactionAction.Resume, TransactionAction.Abort]
+ case WithdrawalGroupStatus.SuspendedWaitConfirmBank:
+ return [TransactionAction.Resume, TransactionAction.Abort];
+ case WithdrawalGroupStatus.SuspendedReady:
+ return [TransactionAction.Resume, TransactionAction.Abort];
+ case WithdrawalGroupStatus.PendingAml:
+ return [TransactionAction.Resume, TransactionAction.Abort];
+ case WithdrawalGroupStatus.PendingKyc:
+ return [TransactionAction.Resume, TransactionAction.Abort];
+ case WithdrawalGroupStatus.SuspendedAml:
+ return [TransactionAction.Resume, TransactionAction.Abort];
+ case WithdrawalGroupStatus.SuspendedKyc:
+ return [TransactionAction.Resume, TransactionAction.Abort]
+ case WithdrawalGroupStatus.FailedAbortingBank:
+ return [TransactionAction.Delete];
+ case WithdrawalGroupStatus.AbortedExchange:
+ return [TransactionAction.Delete];
+ }
+}
+
/**
* Get information about a withdrawal from
* a taler://withdraw URI by asking the bank.
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index 85b0b9250..953353164 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -232,7 +232,7 @@ import {
import { acceptTip, prepareTip, processTip } from "./operations/tip.js";
import {
abortTransaction,
- cancelAbortingTransaction,
+ failTransaction,
deleteTransaction,
getTransactionById,
getTransactions,
@@ -1233,7 +1233,7 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
}
case WalletApiOperation.CancelAbortingTransaction: {
const req = codecForCancelAbortingTransactionRequest().decode(payload);
- await cancelAbortingTransaction(ws, req.transactionId);
+ await failTransaction(ws, req.transactionId);
return {};
}
case WalletApiOperation.ResumeTransaction: {