taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 658d9f309c1336ab84d57c7defd5dab33b2c19e0
parent 1db9018c79b14e8b605526cdd13775bcd2345801
Author: Antoine A <>
Date:   Tue, 15 Apr 2025 18:59:37 +0200

wallet-core: clean pay-peer-push-credit

Diffstat:
Mpackages/taler-wallet-core/src/pay-peer-push-credit.ts | 467+++++++++++++++++++++++++++----------------------------------------------------
Mpackages/taler-wallet-core/src/pay-peer-push-debit.ts | 2+-
2 files changed, 161 insertions(+), 308 deletions(-)

diff --git a/packages/taler-wallet-core/src/pay-peer-push-credit.ts b/packages/taler-wallet-core/src/pay-peer-push-credit.ts @@ -1,6 +1,6 @@ /* This file is part of GNU Taler - (C) 2022-2023 Taler Systems S.A. + (C) 2022-2025 Taler Systems S.A. GNU Taler is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -65,7 +65,6 @@ import { TaskIdentifiers, TaskRunResult, TransactionContext, - TransitionResult, TransitionResultType, constructTaskIdentifier, genericWaitForStateVal, @@ -139,31 +138,25 @@ export class PeerPushCreditTransactionContext implements TransactionContext { } /** - * Transition a peer-push-credit transaction. - * Extra object stores may be accessed during the transition. - */ - async transition<StoreNameArray extends WalletDbStoresArr = []>( - opts: { extraStores?: StoreNameArray; transactionLabel?: string }, + * Transition an existing peer-push-credit transaction. + * Extra object stores may be accessed during the transition. + */ + async transition<StoreNameArray extends WalletDbStoresArr>( + opts: { extraStores?: StoreNameArray }, f: ( - rec: PeerPushPaymentIncomingRecord | undefined, + rec: PeerPushPaymentIncomingRecord, tx: WalletDbReadWriteTransaction< [ "peerPushCredit", "transactionsMeta", - "operationRetries", - "exchanges", - "exchangeDetails", ...StoreNameArray, ] >, - ) => Promise<TransitionResult<PeerPushPaymentIncomingRecord>>, + ) => Promise<TransitionResultType>, ): Promise<TransitionInfo | undefined> { const baseStores = [ "peerPushCredit" as const, - "transactionsMeta" as const, - "operationRetries" as const, - "exchanges" as const, - "exchangeDetails" as const, + "transactionsMeta" as const ]; const stores = opts.extraStores ? [...baseStores, ...opts.extraStores] @@ -174,15 +167,12 @@ export class PeerPushCreditTransactionContext implements TransactionContext { { storeNames: stores }, async (tx) => { const rec = await tx.peerPushCredit.get(this.peerPushCreditId); - let oldTxState: TransactionState; - if (rec) { - oldTxState = computePeerPushCreditTransactionState(rec); - } else { - oldTxState = { - major: TransactionMajorState.None, - }; + if (rec == null) { + logger.warn(`peer push credit ${this.peerPushCreditId} not found`); + return; } - let res: TransitionResult<PeerPushPaymentIncomingRecord> | undefined; + const oldTxState = computePeerPushCreditTransactionState(rec); + let res: TransitionResultType; try { res = await f(rec, tx); } catch (error) { @@ -192,29 +182,21 @@ export class PeerPushCreditTransactionContext implements TransactionContext { return undefined; } - switch (res.type) { + switch (res) { case TransitionResultType.Transition: { - await tx.peerPushCredit.put(res.rec); + await tx.peerPushCredit.put(rec); await this.updateTransactionMeta(tx); - const newTxState = computePeerPushCreditTransactionState(res.rec); + const newTxState = computePeerPushCreditTransactionState(rec); return { oldTxState, newTxState, - balanceEffect: res.balanceEffect, + balanceEffect: BalanceEffect.Any, }; } case TransitionResultType.Delete: - await tx.peerPushCredit.delete(this.peerPushCreditId); - await this.updateTransactionMeta(tx); - return { - oldTxState, - newTxState: { - major: TransactionMajorState.None, - }, - balanceEffect: BalanceEffect.Any, - }; - default: - return undefined; + throw new Error("Cannot delete using transition"); + case TransitionResultType.Stay: + return; } }, ); @@ -225,6 +207,23 @@ export class PeerPushCreditTransactionContext implements TransactionContext { return transitionInfo; } + /** + * Transition an existing peer-push-credit transaction status + */ + async transitionStatus( + from: PeerPushCreditStatus, + to: PeerPushCreditStatus + ) { + await this.transition({}, async (rec) => { + if (rec.status !== from) { + return TransitionResultType.Stay + } else { + rec.status = to; + return TransitionResultType.Transition + } + }); + } + async updateTransactionMeta( tx: WalletDbReadWriteTransaction<["peerPushCredit", "transactionsMeta"]>, ): Promise<void> { @@ -326,7 +325,7 @@ export class PeerPushCreditTransactionContext implements TransactionContext { amountEffective: isUnsuccessfulTransaction(txState) ? Amounts.stringify(Amounts.zeroOfAmount(peerContractTerms.amount)) : // FIXME: This is wrong, needs to consider fees! - Amounts.stringify(peerContractTerms.amount), + Amounts.stringify(peerContractTerms.amount), amountRaw: Amounts.stringify(peerContractTerms.amount), exchangeBaseUrl: pushInc.exchangeBaseUrl, info: { @@ -359,9 +358,7 @@ export class PeerPushCreditTransactionContext implements TransactionContext { "transactionsMeta", ], }, - async (tx) => { - return this.deleteTransactionInTx(tx); - }, + async (tx) => this.deleteTransactionInTx(tx) ); for (const notif of res.notifs) { this.wex.ws.notify(notif); @@ -408,12 +405,8 @@ export class PeerPushCreditTransactionContext implements TransactionContext { } async suspendTransaction(): Promise<void> { - await this.transition({}, async (pushCreditRec) => { - if (!pushCreditRec) { - return TransitionResult.stay(); - } - let newStatus: PeerPushCreditStatus | undefined = undefined; - switch (pushCreditRec.status) { + this.transition({}, async (rec) => { + switch (rec.status) { case PeerPushCreditStatus.DialogProposed: case PeerPushCreditStatus.Done: case PeerPushCreditStatus.SuspendedMerge: @@ -423,199 +416,121 @@ export class PeerPushCreditTransactionContext implements TransactionContext { case PeerPushCreditStatus.SuspendedBalanceKycInit: case PeerPushCreditStatus.Failed: case PeerPushCreditStatus.Aborted: - break; + return TransitionResultType.Stay; case PeerPushCreditStatus.PendingBalanceKycRequired: - newStatus = PeerPushCreditStatus.SuspendedBalanceKycRequired; - break; + rec.status = PeerPushCreditStatus.SuspendedBalanceKycRequired; + return TransitionResultType.Transition; case PeerPushCreditStatus.PendingBalanceKycInit: - newStatus = PeerPushCreditStatus.SuspendedBalanceKycInit; - break; + rec.status = PeerPushCreditStatus.SuspendedBalanceKycInit; + return TransitionResultType.Transition; case PeerPushCreditStatus.PendingMergeKycRequired: - newStatus = PeerPushCreditStatus.SuspendedMergeKycRequired; - break; + rec.status = PeerPushCreditStatus.SuspendedMergeKycRequired; + return TransitionResultType.Transition; case PeerPushCreditStatus.PendingMerge: - newStatus = PeerPushCreditStatus.SuspendedMerge; - break; + rec.status = PeerPushCreditStatus.SuspendedMerge; + return TransitionResultType.Transition; case PeerPushCreditStatus.PendingWithdrawing: // FIXME: Suspend internal withdrawal transaction! - newStatus = PeerPushCreditStatus.SuspendedWithdrawing; - break; + rec.status = PeerPushCreditStatus.SuspendedWithdrawing; + return TransitionResultType.Transition; default: - assertUnreachable(pushCreditRec.status); + assertUnreachable(rec.status); } - if (newStatus != null) { - pushCreditRec.status = newStatus; - return TransitionResult.transition(pushCreditRec); - } else { - return TransitionResult.stay(); - } - }); + }) + this.wex.taskScheduler.stopShepherdTask(this.taskId) } async abortTransaction(): Promise<void> { - const { wex, peerPushCreditId, taskId: retryTag, transactionId } = this; - const transitionInfo = await wex.db.runReadWriteTx( - { storeNames: ["peerPushCredit", "transactionsMeta"] }, - async (tx) => { - const pushCreditRec = await tx.peerPushCredit.get(peerPushCreditId); - if (!pushCreditRec) { - logger.warn(`peer push credit ${peerPushCreditId} not found`); - return; - } - let newStatus: PeerPushCreditStatus | undefined = undefined; - switch (pushCreditRec.status) { - case PeerPushCreditStatus.Failed: - case PeerPushCreditStatus.Aborted: - case PeerPushCreditStatus.Done: - break; - case PeerPushCreditStatus.SuspendedMerge: - case PeerPushCreditStatus.DialogProposed: - case PeerPushCreditStatus.SuspendedMergeKycRequired: - case PeerPushCreditStatus.SuspendedWithdrawing: - case PeerPushCreditStatus.PendingBalanceKycRequired: - case PeerPushCreditStatus.SuspendedBalanceKycRequired: - case PeerPushCreditStatus.PendingWithdrawing: - case PeerPushCreditStatus.PendingMergeKycRequired: - case PeerPushCreditStatus.PendingMerge: - case PeerPushCreditStatus.PendingBalanceKycInit: - case PeerPushCreditStatus.SuspendedBalanceKycInit: - newStatus = PeerPushCreditStatus.Aborted; - break; - default: - assertUnreachable(pushCreditRec.status); - } - if (newStatus != null) { - const oldTxState = - computePeerPushCreditTransactionState(pushCreditRec); - pushCreditRec.status = newStatus; - const newTxState = - computePeerPushCreditTransactionState(pushCreditRec); - await tx.peerPushCredit.put(pushCreditRec); - await this.updateTransactionMeta(tx); - return { - oldTxState, - newTxState, - balanceEffect: BalanceEffect.Any, - }; - } - return undefined; - }, - ); - notifyTransition(wex, transactionId, transitionInfo); - wex.taskScheduler.startShepherdTask(retryTag); + this.transition({}, async (rec) => { + switch (rec.status) { + case PeerPushCreditStatus.Failed: + case PeerPushCreditStatus.Aborted: + case PeerPushCreditStatus.Done: + return TransitionResultType.Stay; + case PeerPushCreditStatus.SuspendedMerge: + case PeerPushCreditStatus.DialogProposed: + case PeerPushCreditStatus.SuspendedMergeKycRequired: + case PeerPushCreditStatus.SuspendedWithdrawing: + case PeerPushCreditStatus.PendingBalanceKycRequired: + case PeerPushCreditStatus.SuspendedBalanceKycRequired: + case PeerPushCreditStatus.PendingWithdrawing: + case PeerPushCreditStatus.PendingMergeKycRequired: + case PeerPushCreditStatus.PendingMerge: + case PeerPushCreditStatus.PendingBalanceKycInit: + case PeerPushCreditStatus.SuspendedBalanceKycInit: + rec.status = PeerPushCreditStatus.Aborted; + return TransitionResultType.Transition; + default: + assertUnreachable(rec.status); + } + }); + this.wex.taskScheduler.startShepherdTask(this.taskId); } async resumeTransaction(): Promise<void> { - const { wex, peerPushCreditId, taskId: retryTag, transactionId } = this; - const transitionInfo = await wex.db.runReadWriteTx( - { storeNames: ["peerPushCredit", "transactionsMeta"] }, - async (tx) => { - const pushCreditRec = await tx.peerPushCredit.get(peerPushCreditId); - if (!pushCreditRec) { - logger.warn(`peer push credit ${peerPushCreditId} not found`); - return; - } - let newStatus: PeerPushCreditStatus | undefined = undefined; - switch (pushCreditRec.status) { - case PeerPushCreditStatus.DialogProposed: - case PeerPushCreditStatus.PendingMergeKycRequired: - case PeerPushCreditStatus.PendingMerge: - case PeerPushCreditStatus.PendingWithdrawing: - case PeerPushCreditStatus.PendingBalanceKycRequired: - case PeerPushCreditStatus.PendingBalanceKycInit: - case PeerPushCreditStatus.Done: - case PeerPushCreditStatus.Aborted: - case PeerPushCreditStatus.Failed: - break; - case PeerPushCreditStatus.SuspendedMerge: - newStatus = PeerPushCreditStatus.PendingMerge; - break; - case PeerPushCreditStatus.SuspendedMergeKycRequired: - newStatus = PeerPushCreditStatus.PendingMergeKycRequired; - break; - case PeerPushCreditStatus.SuspendedWithdrawing: - // FIXME: resume underlying "internal-withdrawal" transaction. - newStatus = PeerPushCreditStatus.PendingWithdrawing; - break; - case PeerPushCreditStatus.SuspendedBalanceKycRequired: - newStatus = PeerPushCreditStatus.PendingBalanceKycRequired; - break; - case PeerPushCreditStatus.SuspendedBalanceKycInit: - newStatus = PeerPushCreditStatus.PendingBalanceKycInit; - break; - default: - assertUnreachable(pushCreditRec.status); - } - if (newStatus != null) { - const oldTxState = - computePeerPushCreditTransactionState(pushCreditRec); - pushCreditRec.status = newStatus; - const newTxState = - computePeerPushCreditTransactionState(pushCreditRec); - await tx.peerPushCredit.put(pushCreditRec); - await this.updateTransactionMeta(tx); - return { - oldTxState, - newTxState, - balanceEffect: BalanceEffect.None, - }; - } - return undefined; - }, - ); - notifyTransition(wex, transactionId, transitionInfo); - wex.taskScheduler.startShepherdTask(retryTag); + this.transition({}, async (rec) => { + switch (rec.status) { + case PeerPushCreditStatus.DialogProposed: + case PeerPushCreditStatus.PendingMergeKycRequired: + case PeerPushCreditStatus.PendingMerge: + case PeerPushCreditStatus.PendingWithdrawing: + case PeerPushCreditStatus.PendingBalanceKycRequired: + case PeerPushCreditStatus.PendingBalanceKycInit: + case PeerPushCreditStatus.Done: + case PeerPushCreditStatus.Aborted: + case PeerPushCreditStatus.Failed: + return TransitionResultType.Stay; + case PeerPushCreditStatus.SuspendedMerge: + rec.status = PeerPushCreditStatus.PendingMerge; + return TransitionResultType.Transition; + case PeerPushCreditStatus.SuspendedMergeKycRequired: + rec.status = PeerPushCreditStatus.PendingMergeKycRequired; + return TransitionResultType.Transition; + case PeerPushCreditStatus.SuspendedWithdrawing: + // FIXME: resume underlying "internal-withdrawal" transaction. + rec.status = PeerPushCreditStatus.PendingWithdrawing; + return TransitionResultType.Transition; + case PeerPushCreditStatus.SuspendedBalanceKycRequired: + rec.status = PeerPushCreditStatus.PendingBalanceKycRequired; + return TransitionResultType.Transition; + case PeerPushCreditStatus.SuspendedBalanceKycInit: + rec.status = PeerPushCreditStatus.PendingBalanceKycInit; + return TransitionResultType.Transition; + default: + assertUnreachable(rec.status); + } + }); + this.wex.taskScheduler.startShepherdTask(this.taskId); } async failTransaction(reason?: TalerErrorDetail): Promise<void> { - const { wex, peerPushCreditId, taskId: retryTag, transactionId } = this; - const transitionInfo = await wex.db.runReadWriteTx( - { storeNames: ["peerPushCredit", "transactionsMeta"] }, - async (tx) => { - const pushCreditRec = await tx.peerPushCredit.get(peerPushCreditId); - if (!pushCreditRec) { - logger.warn(`peer push credit ${peerPushCreditId} not found`); - return; - } - let newStatus: PeerPushCreditStatus; - switch (pushCreditRec.status) { - case PeerPushCreditStatus.Done: - case PeerPushCreditStatus.Aborted: - case PeerPushCreditStatus.Failed: - // Already in a final state. - return; - case PeerPushCreditStatus.DialogProposed: - case PeerPushCreditStatus.PendingMergeKycRequired: - case PeerPushCreditStatus.PendingMerge: - case PeerPushCreditStatus.PendingWithdrawing: - case PeerPushCreditStatus.SuspendedMerge: - case PeerPushCreditStatus.SuspendedMergeKycRequired: - case PeerPushCreditStatus.SuspendedWithdrawing: - case PeerPushCreditStatus.PendingBalanceKycRequired: - case PeerPushCreditStatus.SuspendedBalanceKycRequired: - case PeerPushCreditStatus.PendingBalanceKycInit: - case PeerPushCreditStatus.SuspendedBalanceKycInit: - newStatus = PeerPushCreditStatus.Failed; - break; - default: - assertUnreachable(pushCreditRec.status); - } - const oldTxState = computePeerPushCreditTransactionState(pushCreditRec); - pushCreditRec.status = newStatus; - pushCreditRec.failReason = reason; - const newTxState = computePeerPushCreditTransactionState(pushCreditRec); - await tx.peerPushCredit.put(pushCreditRec); - await this.updateTransactionMeta(tx); - return { - oldTxState, - newTxState, - balanceEffect: BalanceEffect.Any, - }; - }, - ); - wex.taskScheduler.stopShepherdTask(retryTag); - notifyTransition(wex, transactionId, transitionInfo); - wex.taskScheduler.startShepherdTask(retryTag); + this.transition({}, async (rec) => { + switch (rec.status) { + case PeerPushCreditStatus.Done: + case PeerPushCreditStatus.Aborted: + case PeerPushCreditStatus.Failed: + // Already in a final state. + return TransitionResultType.Stay; + case PeerPushCreditStatus.DialogProposed: + case PeerPushCreditStatus.PendingMergeKycRequired: + case PeerPushCreditStatus.PendingMerge: + case PeerPushCreditStatus.PendingWithdrawing: + case PeerPushCreditStatus.SuspendedMerge: + case PeerPushCreditStatus.SuspendedMergeKycRequired: + case PeerPushCreditStatus.SuspendedWithdrawing: + case PeerPushCreditStatus.PendingBalanceKycRequired: + case PeerPushCreditStatus.SuspendedBalanceKycRequired: + case PeerPushCreditStatus.PendingBalanceKycInit: + case PeerPushCreditStatus.SuspendedBalanceKycInit: + rec.status = PeerPushCreditStatus.Failed; + rec.failReason = reason + return TransitionResultType.Transition; + default: + assertUnreachable(rec.status); + } + }); + this.wex.taskScheduler.stopShepherdTask(this.taskId); + this.wex.taskScheduler.startShepherdTask(this.taskId); } } @@ -778,11 +693,9 @@ export async function preparePeerPushCredit( } satisfies TransitionInfo; }, ); - - const currency = Amounts.currencyOf(wi.withdrawalAmountRaw); - notifyTransition(wex, ctx.transactionId, transitionInfo); + const currency = Amounts.currencyOf(wi.withdrawalAmountRaw); const scopeInfo = await wex.db.runAllStoresReadOnlyTx( {}, async (tx) => await getExchangeScopeInfo(tx, exchangeBaseUrl, currency), @@ -839,25 +752,7 @@ async function longpollKycStatus( kycStatusRes.status === HttpStatusCode.Ok || kycStatusRes.status === HttpStatusCode.NoContent ) { - const transitionInfo = await wex.db.runReadWriteTx( - { storeNames: ["peerPushCredit", "transactionsMeta"] }, - async (tx) => { - const peerInc = await tx.peerPushCredit.get(peerPushCreditId); - if (!peerInc) { - return; - } - if (peerInc.status !== PeerPushCreditStatus.PendingMergeKycRequired) { - return; - } - const oldTxState = computePeerPushCreditTransactionState(peerInc); - peerInc.status = PeerPushCreditStatus.PendingMerge; - const newTxState = computePeerPushCreditTransactionState(peerInc); - await tx.peerPushCredit.put(peerInc); - await ctx.updateTransactionMeta(tx); - return { oldTxState, newTxState, balanceEffect: BalanceEffect.Any }; - }, - ); - notifyTransition(wex, ctx.transactionId, transitionInfo); + await ctx.transitionStatus(PeerPushCreditStatus.PendingMergeKycRequired, PeerPushCreditStatus.PendingMerge); return TaskRunResult.progress(); } else if (kycStatusRes.status === HttpStatusCode.Accepted) { // Access token / URL stays the same, just long-poll again. @@ -974,16 +869,7 @@ async function handlePendingMerge( amount: kycCheckRes.nextThreshold, exchangeBaseUrl: peerInc.exchangeBaseUrl, }); - await ctx.transition({}, async (rec) => { - if (!rec) { - return TransitionResult.stay(); - } - if (rec.status !== PeerPushCreditStatus.PendingMerge) { - return TransitionResult.stay(); - } - rec.status = PeerPushCreditStatus.PendingBalanceKycInit; - return TransitionResult.transition(rec); - }); + await ctx.transitionStatus(PeerPushCreditStatus.PendingMerge, PeerPushCreditStatus.PendingBalanceKycInit); return TaskRunResult.progress(); } @@ -1195,21 +1081,21 @@ export async function processPeerPushCredit( } const ctx = new PeerPushCreditTransactionContext(wex, peerPushCreditId); - let peerInc: PeerPushPaymentIncomingRecord | undefined; - let contractTerms: PeerContractTerms | undefined; - await wex.db.runReadWriteTx( + const { peerInc, contractTerms } = await wex.db.runReadOnlyTx( { storeNames: ["contractTerms", "peerPushCredit", "transactionsMeta"] }, async (tx) => { - peerInc = await tx.peerPushCredit.get(peerPushCreditId); - if (!peerInc) { - return; + const rec = await tx.peerPushCredit.get(peerPushCreditId); + let contractTerms = null + if (rec != null) { + const contract = await tx.contractTerms.get(rec.contractTermsHash) + if (contract != null) { + contractTerms = contract.contractTermsRaw + } } - const ctRec = await tx.contractTerms.get(peerInc.contractTermsHash); - if (ctRec) { - contractTerms = ctRec.contractTermsRaw; + return { + peerInc: rec, + contractTerms } - await tx.peerPushCredit.put(peerInc); - await ctx.updateTransactionMeta(tx); }, ); @@ -1233,7 +1119,7 @@ export async function processPeerPushCredit( if (!peerInc.kycPaytoHash) { throw Error("invalid state, kycPaytoHash required"); } - return await longpollKycStatus( + return longpollKycStatus( wex, peerPushCreditId, peerInc.exchangeBaseUrl, @@ -1248,7 +1134,7 @@ export async function processPeerPushCredit( } case PeerPushCreditStatus.PendingBalanceKycInit: case PeerPushCreditStatus.PendingBalanceKycRequired: { - return await processPeerPushCreditBalanceKyc(ctx, peerInc); + return processPeerPushCreditBalanceKyc(ctx, peerInc); } default: return TaskRunResult.finished(); @@ -1299,32 +1185,13 @@ async function processPeerPushCreditBalanceKyc( }); if (ret.result === "ok") { - await ctx.transition({}, async (rec) => { - if (!rec) { - return TransitionResult.stay(); - } - if (rec.status !== PeerPushCreditStatus.PendingBalanceKycRequired) { - return TransitionResult.stay(); - } - rec.status = PeerPushCreditStatus.PendingMerge; - return TransitionResult.transition(rec); - }); + await ctx.transitionStatus(PeerPushCreditStatus.PendingBalanceKycRequired, PeerPushCreditStatus.PendingMerge); return TaskRunResult.progress(); } else if ( peerInc.status === PeerPushCreditStatus.PendingBalanceKycInit && ret.walletKycStatus === ExchangeWalletKycStatus.Legi ) { - await ctx.transition({}, async (rec) => { - if (!rec) { - return TransitionResult.stay(); - } - if (rec.status !== PeerPushCreditStatus.PendingBalanceKycInit) { - return TransitionResult.stay(); - } - rec.status = PeerPushCreditStatus.PendingBalanceKycRequired; - rec.kycAccessToken = ret.walletKycAccessToken; - return TransitionResult.transition(rec); - }); + await ctx.transitionStatus(PeerPushCreditStatus.PendingBalanceKycInit, PeerPushCreditStatus.PendingBalanceKycRequired); return TaskRunResult.progress(); } else { throw Error("not reached"); @@ -1349,7 +1216,7 @@ export async function confirmPeerPushCredit( logger.trace(`confirming peer-push-credit ${ctx.peerPushCreditId}`); - const res = await wex.db.runReadWriteTx( + const res = await wex.db.runReadOnlyTx( { storeNames: ["contractTerms", "peerPushCredit", "transactionsMeta"] }, async (tx) => { const rec = await tx.peerPushCredit.get(ctx.peerPushCreditId); @@ -1382,21 +1249,7 @@ export async function confirmPeerPushCredit( throw Error("peer credit would exceed hard KYC limit"); } - await wex.db.runReadWriteTx( - { storeNames: ["contractTerms", "peerPushCredit", "transactionsMeta"] }, - async (tx) => { - const rec = await tx.peerPushCredit.get(ctx.peerPushCreditId); - if (!rec) { - return; - } - if (rec.status === PeerPushCreditStatus.DialogProposed) { - rec.status = PeerPushCreditStatus.PendingMerge; - } - await tx.peerPushCredit.put(rec); - await ctx.updateTransactionMeta(tx); - return rec; - }, - ); + await ctx.transitionStatus(PeerPushCreditStatus.DialogProposed, PeerPushCreditStatus.PendingMerge); wex.taskScheduler.startShepherdTask(ctx.taskId); diff --git a/packages/taler-wallet-core/src/pay-peer-push-debit.ts b/packages/taler-wallet-core/src/pay-peer-push-debit.ts @@ -160,7 +160,7 @@ export class PeerPushDebitTransactionContext implements TransactionContext { logger.warn(`peer pull debit ${this.pursePub} not found`); return; } - let oldTxState = computePeerPushDebitTransactionState(rec); + const oldTxState = computePeerPushDebitTransactionState(rec); let res: TransitionResultType; try { res = await lambda(rec, tx);