summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core/src/operations/transactions.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-core/src/operations/transactions.ts')
-rw-r--r--packages/taler-wallet-core/src/operations/transactions.ts416
1 files changed, 44 insertions, 372 deletions
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts
index 142eff7c1..908aa540a 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -79,61 +79,45 @@ import {
constructTaskIdentifier,
resetPendingTaskTimeout,
TaskIdentifiers,
- TombstoneTag,
+ TransactionContext,
} from "./common.js";
import {
- abortDepositGroup,
computeDepositTransactionActions,
computeDepositTransactionStatus,
- deleteDepositGroup,
- failDepositTransaction,
- resumeDepositGroup,
- suspendDepositGroup,
+ DepositTransactionContext,
} from "./deposits.js";
import {
ExchangeWireDetails,
getExchangeWireDetailsInTx,
} from "./exchanges.js";
import {
- abortPayMerchant,
computePayMerchantTransactionActions,
computePayMerchantTransactionState,
computeRefundTransactionState,
expectProposalDownload,
extractContractData,
- failPaymentTransaction,
- resumePayMerchant,
- suspendPayMerchant,
+ PayMerchantTransactionContext,
+ RefundTransactionContext,
} from "./pay-merchant.js";
import {
- abortPeerPullCreditTransaction,
computePeerPullCreditTransactionActions,
computePeerPullCreditTransactionState,
- failPeerPullCreditTransaction,
- resumePeerPullCreditTransaction,
- suspendPeerPullCreditTransaction,
+ PeerPullCreditTransactionContext,
} from "./pay-peer-pull-credit.js";
import {
computePeerPullDebitTransactionActions,
computePeerPullDebitTransactionState,
PeerPullDebitTransactionContext,
- suspendPeerPullDebitTransaction,
} from "./pay-peer-pull-debit.js";
import {
- abortPeerPushCreditTransaction,
computePeerPushCreditTransactionActions,
computePeerPushCreditTransactionState,
- failPeerPushCreditTransaction,
- resumePeerPushCreditTransaction,
- suspendPeerPushCreditTransaction,
+ PeerPushCreditTransactionContext,
} from "./pay-peer-push-credit.js";
import {
- abortPeerPushDebitTransaction,
computePeerPushDebitTransactionActions,
computePeerPushDebitTransactionState,
- failPeerPushDebitTransaction,
- resumePeerPushDebitTransaction,
- suspendPeerPushDebitTransaction,
+ PeerPushDebitTransactionContext,
} from "./pay-peer-push-debit.js";
import {
iterRecordsForDeposit,
@@ -148,29 +132,20 @@ import {
iterRecordsForWithdrawal,
} from "./pending.js";
import {
- abortRefreshGroup,
computeRefreshTransactionActions,
computeRefreshTransactionState,
- failRefreshGroup,
- resumeRefreshGroup,
- suspendRefreshGroup,
+ RefreshTransactionContext,
} from "./refresh.js";
import {
- abortTipTransaction,
computeRewardTransactionStatus,
computeTipTransactionActions,
- failTipTransaction,
- resumeTipTransaction,
- suspendRewardTransaction,
+ RewardTransactionContext,
} from "./reward.js";
import {
- abortWithdrawalTransaction,
augmentPaytoUrisForWithdrawal,
computeWithdrawalTransactionActions,
computeWithdrawalTransactionStatus,
- failWithdrawalTransaction,
- resumeWithdrawalTransaction,
- suspendWithdrawalTransaction,
+ WithdrawTransactionContext,
} from "./withdraw.js";
const logger = new Logger("taler-wallet-core:transactions.ts");
@@ -1565,100 +1540,61 @@ export async function retryTransaction(
}
}
-/**
- * Suspends a pending transaction, stopping any associated network activities,
- * but with a chance of trying again at a later time. This could be useful if
- * a user needs to save battery power or bandwidth and an operation is expected
- * to take longer (such as a backup, recovery or very large withdrawal operation).
- */
-export async function suspendTransaction(
+async function getContextForTransaction(
ws: InternalWalletState,
transactionId: string,
-): Promise<void> {
+): Promise<TransactionContext> {
const tx = parseTransactionIdentifier(transactionId);
if (!tx) {
throw Error("invalid transaction ID");
}
switch (tx.tag) {
case TransactionType.Deposit:
- await suspendDepositGroup(ws, tx.depositGroupId);
- return;
+ return new DepositTransactionContext(ws, tx.depositGroupId);
case TransactionType.Refresh:
- await suspendRefreshGroup(ws, tx.refreshGroupId);
- return;
+ return new RefreshTransactionContext(ws, tx.refreshGroupId);
case TransactionType.InternalWithdrawal:
case TransactionType.Withdrawal:
- await suspendWithdrawalTransaction(ws, tx.withdrawalGroupId);
- return;
+ return new WithdrawTransactionContext(ws, tx.withdrawalGroupId);
case TransactionType.Payment:
- await suspendPayMerchant(ws, tx.proposalId);
- return;
+ return new PayMerchantTransactionContext(ws, tx.proposalId);
case TransactionType.PeerPullCredit:
- await suspendPeerPullCreditTransaction(ws, tx.pursePub);
- break;
+ return new PeerPullCreditTransactionContext(ws, tx.pursePub);
case TransactionType.PeerPushDebit:
- await suspendPeerPushDebitTransaction(ws, tx.pursePub);
- break;
+ return new PeerPushDebitTransactionContext(ws, tx.pursePub);
case TransactionType.PeerPullDebit:
- await suspendPeerPullDebitTransaction(ws, tx.peerPullDebitId);
- break;
+ return new PeerPullDebitTransactionContext(ws, tx.peerPullDebitId);
case TransactionType.PeerPushCredit:
- await suspendPeerPushCreditTransaction(ws, tx.peerPushCreditId);
- break;
+ return new PeerPushCreditTransactionContext(ws, tx.peerPushCreditId);
case TransactionType.Refund:
- throw Error("refund transactions can't be suspended or resumed");
+ return new RefundTransactionContext(ws, tx.refundGroupId);
case TransactionType.Reward:
- await suspendRewardTransaction(ws, tx.walletRewardId);
- break;
+ return new RewardTransactionContext(ws, tx.walletRewardId);
default:
assertUnreachable(tx);
}
}
+/**
+ * Suspends a pending transaction, stopping any associated network activities,
+ * but with a chance of trying again at a later time. This could be useful if
+ * a user needs to save battery power or bandwidth and an operation is expected
+ * to take longer (such as a backup, recovery or very large withdrawal operation).
+ */
+export async function suspendTransaction(
+ ws: InternalWalletState,
+ transactionId: string,
+): Promise<void> {
+ const ctx = await getContextForTransaction(ws, transactionId);
+ await ctx.suspendTransaction();
+}
+
export async function failTransaction(
ws: InternalWalletState,
transactionId: string,
): Promise<void> {
- const tx = parseTransactionIdentifier(transactionId);
- if (!tx) {
- throw Error("invalid transaction ID");
- }
- switch (tx.tag) {
- case TransactionType.Deposit:
- await failDepositTransaction(ws, tx.depositGroupId);
- return;
- case TransactionType.InternalWithdrawal:
- case TransactionType.Withdrawal:
- await failWithdrawalTransaction(ws, tx.withdrawalGroupId);
- return;
- case TransactionType.Payment:
- await failPaymentTransaction(ws, tx.proposalId);
- return;
- case TransactionType.Refund:
- throw Error("can't do cancel-aborting on refund transaction");
- case TransactionType.Reward:
- await failTipTransaction(ws, tx.walletRewardId);
- return;
- case TransactionType.Refresh:
- await failRefreshGroup(ws, tx.refreshGroupId);
- return;
- case TransactionType.PeerPullCredit:
- await failPeerPullCreditTransaction(ws, tx.pursePub);
- return;
- case TransactionType.PeerPullDebit: {
- const ctx = new PeerPullDebitTransactionContext(ws, tx.peerPullDebitId);
- await ctx.failTransaction();
- return;
- }
- case TransactionType.PeerPushCredit:
- await failPeerPushCreditTransaction(ws, tx.peerPushCreditId);
- return;
- case TransactionType.PeerPushDebit:
- await failPeerPushDebitTransaction(ws, tx.pursePub);
- return;
- default:
- assertUnreachable(tx);
- }
+ const ctx = await getContextForTransaction(ws, transactionId);
+ await ctx.failTransaction();
}
/**
@@ -1668,44 +1604,8 @@ export async function resumeTransaction(
ws: InternalWalletState,
transactionId: string,
): Promise<void> {
- const tx = parseTransactionIdentifier(transactionId);
- if (!tx) {
- throw Error("invalid transaction ID");
- }
- switch (tx.tag) {
- case TransactionType.Deposit:
- await resumeDepositGroup(ws, tx.depositGroupId);
- return;
- case TransactionType.Refresh:
- await resumeRefreshGroup(ws, tx.refreshGroupId);
- return;
- case TransactionType.InternalWithdrawal:
- case TransactionType.Withdrawal:
- await resumeWithdrawalTransaction(ws, tx.withdrawalGroupId);
- return;
- case TransactionType.Payment:
- await resumePayMerchant(ws, tx.proposalId);
- return;
- case TransactionType.PeerPullCredit:
- await resumePeerPullCreditTransaction(ws, tx.pursePub);
- break;
- case TransactionType.PeerPushDebit:
- await resumePeerPushDebitTransaction(ws, tx.pursePub);
- break;
- case TransactionType.PeerPullDebit: {
- const ctx = new PeerPullDebitTransactionContext(ws, tx.peerPullDebitId);
- await ctx.resumeTransaction();
- return;
- }
- case TransactionType.PeerPushCredit:
- await resumePeerPushCreditTransaction(ws, tx.peerPushCreditId);
- break;
- case TransactionType.Refund:
- throw Error("refund transactions can't be suspended or resumed");
- case TransactionType.Reward:
- await resumeTipTransaction(ws, tx.walletRewardId);
- break;
- }
+ const ctx = await getContextForTransaction(ws, transactionId);
+ await ctx.resumeTransaction();
}
/**
@@ -1715,244 +1615,16 @@ export async function deleteTransaction(
ws: InternalWalletState,
transactionId: string,
): Promise<void> {
- const parsedTx = parseTransactionIdentifier(transactionId);
-
- if (!parsedTx) {
- throw Error("invalid transaction ID");
- }
-
- switch (parsedTx.tag) {
- case TransactionType.PeerPushCredit: {
- const peerPushCreditId = parsedTx.peerPushCreditId;
- await ws.db
- .mktx((x) => [x.withdrawalGroups, x.peerPushCredit, x.tombstones])
- .runReadWrite(async (tx) => {
- const pushInc = await tx.peerPushCredit.get(peerPushCreditId);
- if (!pushInc) {
- return;
- }
- if (pushInc.withdrawalGroupId) {
- const withdrawalGroupId = pushInc.withdrawalGroupId;
- const withdrawalGroupRecord =
- await tx.withdrawalGroups.get(withdrawalGroupId);
- if (withdrawalGroupRecord) {
- await tx.withdrawalGroups.delete(withdrawalGroupId);
- await tx.tombstones.put({
- id:
- TombstoneTag.DeleteWithdrawalGroup + ":" + withdrawalGroupId,
- });
- }
- }
- await tx.peerPushCredit.delete(peerPushCreditId);
- await tx.tombstones.put({
- id: TombstoneTag.DeletePeerPushCredit + ":" + peerPushCreditId,
- });
- });
- return;
- }
-
- case TransactionType.PeerPullCredit: {
- const pursePub = parsedTx.pursePub;
- await ws.db
- .mktx((x) => [x.withdrawalGroups, x.peerPullCredit, x.tombstones])
- .runReadWrite(async (tx) => {
- const pullIni = await tx.peerPullCredit.get(pursePub);
- if (!pullIni) {
- return;
- }
- if (pullIni.withdrawalGroupId) {
- const withdrawalGroupId = pullIni.withdrawalGroupId;
- const withdrawalGroupRecord =
- await tx.withdrawalGroups.get(withdrawalGroupId);
- if (withdrawalGroupRecord) {
- await tx.withdrawalGroups.delete(withdrawalGroupId);
- await tx.tombstones.put({
- id:
- TombstoneTag.DeleteWithdrawalGroup + ":" + withdrawalGroupId,
- });
- }
- }
- await tx.peerPullCredit.delete(pursePub);
- await tx.tombstones.put({
- id: TombstoneTag.DeletePeerPullCredit + ":" + pursePub,
- });
- });
-
- return;
- }
-
- case TransactionType.Withdrawal: {
- const withdrawalGroupId = parsedTx.withdrawalGroupId;
- await ws.db
- .mktx((x) => [x.withdrawalGroups, x.tombstones])
- .runReadWrite(async (tx) => {
- const withdrawalGroupRecord =
- await tx.withdrawalGroups.get(withdrawalGroupId);
- if (withdrawalGroupRecord) {
- await tx.withdrawalGroups.delete(withdrawalGroupId);
- await tx.tombstones.put({
- id: TombstoneTag.DeleteWithdrawalGroup + ":" + withdrawalGroupId,
- });
- return;
- }
- });
- return;
- }
-
- case TransactionType.Payment: {
- const proposalId = parsedTx.proposalId;
- await ws.db
- .mktx((x) => [x.purchases, x.tombstones])
- .runReadWrite(async (tx) => {
- let found = false;
- const purchase = await tx.purchases.get(proposalId);
- if (purchase) {
- found = true;
- await tx.purchases.delete(proposalId);
- }
- if (found) {
- await tx.tombstones.put({
- id: TombstoneTag.DeletePayment + ":" + proposalId,
- });
- }
- });
- return;
- }
-
- case TransactionType.Refresh: {
- const refreshGroupId = parsedTx.refreshGroupId;
- await ws.db
- .mktx((x) => [x.refreshGroups, x.tombstones])
- .runReadWrite(async (tx) => {
- const rg = await tx.refreshGroups.get(refreshGroupId);
- if (rg) {
- await tx.refreshGroups.delete(refreshGroupId);
- await tx.tombstones.put({
- id: TombstoneTag.DeleteRefreshGroup + ":" + refreshGroupId,
- });
- }
- });
-
- return;
- }
-
- case TransactionType.Reward: {
- const tipId = parsedTx.walletRewardId;
- await ws.db
- .mktx((x) => [x.rewards, x.tombstones])
- .runReadWrite(async (tx) => {
- const tipRecord = await tx.rewards.get(tipId);
- if (tipRecord) {
- await tx.rewards.delete(tipId);
- await tx.tombstones.put({
- id: TombstoneTag.DeleteReward + ":" + tipId,
- });
- }
- });
- return;
- }
-
- case TransactionType.Deposit: {
- const depositGroupId = parsedTx.depositGroupId;
- await deleteDepositGroup(ws, depositGroupId);
- return;
- }
-
- case TransactionType.Refund: {
- const refundGroupId = parsedTx.refundGroupId;
- await ws.db
- .mktx((x) => [x.refundGroups, x.tombstones])
- .runReadWrite(async (tx) => {
- const refundRecord = await tx.refundGroups.get(refundGroupId);
- if (!refundRecord) {
- return;
- }
- await tx.refundGroups.delete(refundGroupId);
- await tx.tombstones.put({ id: transactionId });
- // FIXME: Also tombstone the refund items, so that they won't reappear.
- });
- return;
- }
-
- case TransactionType.PeerPullDebit: {
- const peerPullDebitId = parsedTx.peerPullDebitId;
- await ws.db
- .mktx((x) => [x.peerPullDebit, x.tombstones])
- .runReadWrite(async (tx) => {
- const debit = await tx.peerPullDebit.get(peerPullDebitId);
- if (debit) {
- await tx.peerPullDebit.delete(peerPullDebitId);
- await tx.tombstones.put({ id: transactionId });
- }
- });
-
- return;
- }
-
- case TransactionType.PeerPushDebit: {
- const pursePub = parsedTx.pursePub;
- await ws.db
- .mktx((x) => [x.peerPushDebit, x.tombstones])
- .runReadWrite(async (tx) => {
- const debit = await tx.peerPushDebit.get(pursePub);
- if (debit) {
- await tx.peerPushDebit.delete(pursePub);
- await tx.tombstones.put({ id: transactionId });
- }
- });
- return;
- }
- }
+ const ctx = await getContextForTransaction(ws, transactionId);
+ await ctx.deleteTransaction();
}
export async function abortTransaction(
ws: InternalWalletState,
transactionId: string,
): Promise<void> {
- const txId = parseTransactionIdentifier(transactionId);
- if (!txId) {
- throw Error("invalid transaction identifier");
- }
-
- switch (txId.tag) {
- case TransactionType.Payment: {
- await abortPayMerchant(ws, txId.proposalId);
- break;
- }
- case TransactionType.Withdrawal:
- case TransactionType.InternalWithdrawal: {
- await abortWithdrawalTransaction(ws, txId.withdrawalGroupId);
- break;
- }
- case TransactionType.Deposit:
- await abortDepositGroup(ws, txId.depositGroupId);
- break;
- case TransactionType.Reward:
- await abortTipTransaction(ws, txId.walletRewardId);
- break;
- case TransactionType.Refund:
- throw Error("can't abort refund transactions");
- case TransactionType.Refresh:
- await abortRefreshGroup(ws, txId.refreshGroupId);
- break;
- case TransactionType.PeerPullCredit:
- await abortPeerPullCreditTransaction(ws, txId.pursePub);
- break;
- case TransactionType.PeerPullDebit: {
- const ctx = new PeerPullDebitTransactionContext(ws, txId.peerPullDebitId);
- await ctx.abortTransaction();
- return;
- }
- case TransactionType.PeerPushCredit:
- await abortPeerPushCreditTransaction(ws, txId.peerPushCreditId);
- break;
- case TransactionType.PeerPushDebit:
- await abortPeerPushDebitTransaction(ws, txId.pursePub);
- break;
- default: {
- assertUnreachable(txId);
- }
- }
+ const ctx = await getContextForTransaction(ws, transactionId);
+ await ctx.abortTransaction();
}
export interface TransitionInfo {