taler-typescript-core

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

commit d229818619a4b29d5be2c10ebea2adc64a09d243
parent 6f5aaaf1219060350567fa24ebb32f0c2eca27d9
Author: Florian Dold <florian@dold.me>
Date:   Tue, 20 May 2025 15:20:17 +0200

formatting: use prettier

Diffstat:
Mpackages/taler-wallet-core/src/pay-peer-pull-credit.ts | 216++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
1 file changed, 126 insertions(+), 90 deletions(-)

diff --git a/packages/taler-wallet-core/src/pay-peer-pull-credit.ts b/packages/taler-wallet-core/src/pay-peer-pull-credit.ts @@ -127,8 +127,8 @@ export class PeerPullCreditTransactionContext implements TransactionContext { } readonly store = "peerPullCredit"; - readonly recordId = this.pursePub - readonly recordState = computePeerPullCreditTransactionState + readonly recordId = this.pursePub; + readonly recordState = computePeerPullCreditTransactionState; readonly recordMeta = (rec: PeerPullCreditRecord) => ({ transactionId: this.transactionId, status: rec.status, @@ -136,7 +136,9 @@ export class PeerPullCreditTransactionContext implements TransactionContext { currency: Amounts.currencyOf(rec.amount), exchanges: [rec.exchangeBaseUrl], }); - updateTransactionMeta = (tx: WalletDbReadWriteTransaction<["peerPullCredit", "transactionsMeta"]>) => recordUpdateMeta(this, tx) + updateTransactionMeta = ( + tx: WalletDbReadWriteTransaction<["peerPullCredit", "transactionsMeta"]>, + ) => recordUpdateMeta(this, tx); async deleteTransactionInTx( tx: WalletDbReadWriteTransaction< @@ -159,7 +161,7 @@ export class PeerPullCreditTransactionContext implements TransactionContext { const res = await withdrawalCtx.deleteTransactionInTx(tx); notifs.push(...res.notifs); } - }) + }); } /** @@ -213,7 +215,7 @@ export class PeerPullCreditTransactionContext implements TransactionContext { const silentWithdrawalErrorForInvoice = wsrOrt?.lastError && wsrOrt.lastError.code === - TalerErrorCode.WALLET_WITHDRAWAL_GROUP_INCOMPLETE && + TalerErrorCode.WALLET_WITHDRAWAL_GROUP_INCOMPLETE && Object.values(wsrOrt.lastError.errorsPerCoin ?? {}).every((e) => { return ( e.code === TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR && @@ -250,10 +252,10 @@ export class PeerPullCreditTransactionContext implements TransactionContext { kycUrl: kycUrl, ...(wsrOrt?.lastError ? { - error: silentWithdrawalErrorForInvoice - ? undefined - : wsrOrt.lastError, - } + error: silentWithdrawalErrorForInvoice + ? undefined + : wsrOrt.lastError, + } : {}), }; } @@ -322,8 +324,7 @@ export class PeerPullCreditTransactionContext implements TransactionContext { rec.status = PeerPullPaymentCreditStatus.SuspendedReady; return TransitionResultType.Transition; case PeerPullPaymentCreditStatus.AbortingDeletePurse: - rec.status = - PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse; + rec.status = PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse; return TransitionResultType.Transition; case PeerPullPaymentCreditStatus.PendingBalanceKycRequired: rec.status = PeerPullPaymentCreditStatus.SuspendedBalanceKycRequired; @@ -346,7 +347,7 @@ export class PeerPullCreditTransactionContext implements TransactionContext { default: assertUnreachable(rec.status); } - }) + }); this.wex.taskScheduler.stopShepherdTask(this.taskId); } @@ -378,7 +379,7 @@ export class PeerPullCreditTransactionContext implements TransactionContext { default: assertUnreachable(rec.status); } - }) + }); this.wex.taskScheduler.stopShepherdTask(this.taskId); } @@ -453,7 +454,7 @@ export class PeerPullCreditTransactionContext implements TransactionContext { case PeerPullPaymentCreditStatus.Failed: case PeerPullPaymentCreditStatus.Expired: case PeerPullPaymentCreditStatus.SuspendedAbortingDeletePurse: - return TransitionResultType.Stay + return TransitionResultType.Stay; default: assertUnreachable(rec.status); } @@ -468,21 +469,28 @@ async function queryPurseForPeerPullCredit( pullIni: PeerPullCreditRecord, ): Promise<TaskRunResult> { const ctx = new PeerPullCreditTransactionContext(wex, pullIni.pursePub); - const exchangeClient = walletExchangeClient(pullIni.exchangeBaseUrl, wex) - const resp = await exchangeClient.getPurseStatusAtDeposit(pullIni.pursePub, true); + const exchangeClient = walletExchangeClient(pullIni.exchangeBaseUrl, wex); + const resp = await exchangeClient.getPurseStatusAtDeposit( + pullIni.pursePub, + true, + ); switch (resp.case) { case "ok": break; case HttpStatusCode.Gone: // Exchange says that purse doesn't exist anymore => expired! - await recordTransitionStatus(ctx, PeerPullPaymentCreditStatus.PendingReady, PeerPullPaymentCreditStatus.Expired); + await recordTransitionStatus( + ctx, + PeerPullPaymentCreditStatus.PendingReady, + PeerPullPaymentCreditStatus.Expired, + ); return TaskRunResult.finished(); case HttpStatusCode.NotFound: - await ctx.failTransaction(resp.detail) + await ctx.failTransaction(resp.detail); return TaskRunResult.finished(); default: - assertUnreachable(resp) + assertUnreachable(resp); } if (!isPurseDeposited(resp.body)) { @@ -492,7 +500,7 @@ async function queryPurseForPeerPullCredit( const reserve = await wex.db.runReadOnlyTx( { storeNames: ["reserves"] }, - (tx) => tx.reserves.get(pullIni.mergeReserveRowId) + (tx) => tx.reserves.get(pullIni.mergeReserveRowId), ); if (!reserve) { @@ -513,7 +521,11 @@ async function queryPurseForPeerPullCredit( pub: reserve.reservePub, }, }); - await recordTransitionStatus(ctx, PeerPullPaymentCreditStatus.PendingReady, PeerPullPaymentCreditStatus.PendingWithdrawing); + await recordTransitionStatus( + ctx, + PeerPullPaymentCreditStatus.PendingReady, + PeerPullPaymentCreditStatus.PendingWithdrawing, + ); return TaskRunResult.progress(); } @@ -526,7 +538,11 @@ async function longpollKycStatus( const done = await waitForKycCompletion(wex, exchangeUrl, kycPaytoHash); if (done) { const ctx = new PeerPullCreditTransactionContext(wex, pursePub); - await recordTransitionStatus(ctx, PeerPullPaymentCreditStatus.PendingMergeKycRequired, PeerPullPaymentCreditStatus.PendingCreatePurse); + await recordTransitionStatus( + ctx, + PeerPullPaymentCreditStatus.PendingMergeKycRequired, + PeerPullPaymentCreditStatus.PendingCreatePurse, + ); return TaskRunResult.progress(); } else { return TaskRunResult.longpollReturnedPending(); @@ -539,7 +555,7 @@ async function processPeerPullCreditAbortingDeletePurse( ): Promise<TaskRunResult> { const { pursePub, pursePriv } = peerPullIni; const ctx = new PeerPullCreditTransactionContext(wex, peerPullIni.pursePub); - const exchangeClient = walletExchangeClient(peerPullIni.exchangeBaseUrl, wex) + const exchangeClient = walletExchangeClient(peerPullIni.exchangeBaseUrl, wex); const sigResp = await wex.cryptoApi.signDeletePurse({ pursePriv, }); @@ -547,10 +563,14 @@ async function processPeerPullCreditAbortingDeletePurse( switch (resp.case) { case "ok": case HttpStatusCode.NotFound: - await recordTransitionStatus(ctx, PeerPullPaymentCreditStatus.AbortingDeletePurse, PeerPullPaymentCreditStatus.Aborted); + await recordTransitionStatus( + ctx, + PeerPullPaymentCreditStatus.AbortingDeletePurse, + PeerPullPaymentCreditStatus.Aborted, + ); return TaskRunResult.finished(); case HttpStatusCode.Forbidden: - await ctx.failTransaction(resp.detail) + await ctx.failTransaction(resp.detail); return TaskRunResult.finished(); case HttpStatusCode.Conflict: // FIXME check if done ? @@ -570,25 +590,29 @@ async function handlePeerPullCreditWithdrawing( await waitWithdrawalFinal(wex, pullIni.withdrawalGroupId); const ctx = new PeerPullCreditTransactionContext(wex, pullIni.pursePub); const wgId = pullIni.withdrawalGroupId; - const info = await recordTransition(ctx, { - extraStores: ["withdrawalGroups"] - }, async (rec, tx) => { - if (rec.status !== PeerPullPaymentCreditStatus.PendingWithdrawing) { - return TransitionResultType.Stay - } - const wg = await tx.withdrawalGroups.get(wgId); - if (!wg) { - // FIXME: Fail the operation instead? - return TransitionResultType.Stay - } - switch (wg.status) { - case WithdrawalGroupStatus.Done: - rec.status = PeerPullPaymentCreditStatus.Done; - break; - // FIXME: Also handle other final states! - } - return TransitionResultType.Transition - }) + const info = await recordTransition( + ctx, + { + extraStores: ["withdrawalGroups"], + }, + async (rec, tx) => { + if (rec.status !== PeerPullPaymentCreditStatus.PendingWithdrawing) { + return TransitionResultType.Stay; + } + const wg = await tx.withdrawalGroups.get(wgId); + if (!wg) { + // FIXME: Fail the operation instead? + return TransitionResultType.Stay; + } + switch (wg.status) { + case WithdrawalGroupStatus.Done: + rec.status = PeerPullPaymentCreditStatus.Done; + break; + // FIXME: Also handle other final states! + } + return TransitionResultType.Transition; + }, + ); if (info?.newTxState.major != TransactionMajorState.Pending) { return TaskRunResult.finished(); } else { @@ -615,7 +639,11 @@ async function handlePeerPullCreditCreatePurse( amount: kycCheckRes.nextThreshold, exchangeBaseUrl: pullIni.exchangeBaseUrl, }); - await recordTransitionStatus(ctx, PeerPullPaymentCreditStatus.PendingCreatePurse, PeerPullPaymentCreditStatus.PendingBalanceKycInit); + await recordTransitionStatus( + ctx, + PeerPullPaymentCreditStatus.PendingCreatePurse, + PeerPullPaymentCreditStatus.PendingBalanceKycInit, + ); return TaskRunResult.progress(); } @@ -623,7 +651,7 @@ async function handlePeerPullCreditCreatePurse( const mergeReserve = await wex.db.runReadOnlyTx( { storeNames: ["reserves"] }, - async (tx) => tx.reserves.get(pullIni.mergeReserveRowId) + async (tx) => tx.reserves.get(pullIni.mergeReserveRowId), ); if (!mergeReserve) { throw Error("merge reserve for peer pull payment not found in database"); @@ -631,7 +659,7 @@ async function handlePeerPullCreditCreatePurse( const contractTermsRecord = await wex.db.runReadOnlyTx( { storeNames: ["contractTerms"] }, - async (tx) => tx.contractTerms.get(pullIni.contractTermsHash) + async (tx) => tx.contractTerms.get(pullIni.contractTermsHash), ); if (!contractTermsRecord) { throw Error("contract terms for peer pull payment not found in database"); @@ -685,14 +713,14 @@ async function handlePeerPullCreditCreatePurse( econtract: econtractResp.econtract, }; - const exchangeClient = walletExchangeClient(pullIni.exchangeBaseUrl, wex) + const exchangeClient = walletExchangeClient(pullIni.exchangeBaseUrl, wex); logger.info(`reserve purse request: ${j2s(reservePurseReqBody)}`); const resp = await exchangeClient.createPurseFromReserve( mergeReserve.reservePub, - reservePurseReqBody - ) + reservePurseReqBody, + ); switch (resp.case) { case "ok": @@ -703,21 +731,21 @@ async function handlePeerPullCreditCreatePurse( } case HttpStatusCode.Forbidden: case HttpStatusCode.NotFound: - await ctx.failTransaction(resp.detail) + await ctx.failTransaction(resp.detail); return TaskRunResult.finished(); case HttpStatusCode.Conflict: - await ctx.failTransaction({ code: resp.body.code }) + await ctx.failTransaction({ code: resp.body.code }); return TaskRunResult.finished(); case HttpStatusCode.PaymentRequired: - throw Error(`unexpected reserve merge response ${resp.case}`) + throw Error(`unexpected reserve merge response ${resp.case}`); default: assertUnreachable(resp); } await recordTransition(ctx, {}, async (rec, _) => { - rec.status = PeerPullPaymentCreditStatus.PendingReady - return TransitionResultType.Transition - }) + rec.status = PeerPullPaymentCreditStatus.PendingReady; + return TransitionResultType.Transition; + }); return TaskRunResult.backoff(); } @@ -817,11 +845,15 @@ async function processPeerPullCreditBalanceKyc( filterNotification: (notif) => (notif.type === NotificationType.ExchangeStateTransition && notif.exchangeBaseUrl === exchangeBaseUrl) || - notif.type === NotificationType.BalanceChange + notif.type === NotificationType.BalanceChange, }); if (ret.result === "ok") { - await recordTransitionStatus(ctx, PeerPullPaymentCreditStatus.PendingBalanceKycRequired, PeerPullPaymentCreditStatus.PendingCreatePurse); + await recordTransitionStatus( + ctx, + PeerPullPaymentCreditStatus.PendingBalanceKycRequired, + PeerPullPaymentCreditStatus.PendingCreatePurse, + ); return TaskRunResult.progress(); } else if ( peerInc.status === PeerPullPaymentCreditStatus.PendingBalanceKycInit && @@ -829,11 +861,11 @@ async function processPeerPullCreditBalanceKyc( ) { await recordTransition(ctx, {}, async (rec) => { if (rec.status !== PeerPullPaymentCreditStatus.PendingBalanceKycInit) { - return TransitionResultType.Stay + return TransitionResultType.Stay; } rec.status = PeerPullPaymentCreditStatus.PendingBalanceKycRequired; rec.kycAccessToken = ret.walletKycAccessToken; - return TransitionResultType.Transition + return TransitionResultType.Transition; }); return TaskRunResult.progress(); } else { @@ -858,7 +890,7 @@ async function processPeerPullCreditKycRequired( accountPub: mergeReserveInfo.reservePub, }); - const exchangeClient = walletExchangeClient(peerIni.exchangeBaseUrl, wex) + const exchangeClient = walletExchangeClient(peerIni.exchangeBaseUrl, wex); const res = await exchangeClient.checkKycStatus(sigResp.sig, kycPayoHash); switch (res.case) { @@ -875,9 +907,9 @@ async function processPeerPullCreditKycRequired( ); rec.kycAccessToken = res.body.access_token; rec.status = PeerPullPaymentCreditStatus.PendingMergeKycRequired; - return TransitionResultType.Transition - }) - return TaskRunResult.progress() + return TransitionResultType.Transition; + }); + return TaskRunResult.progress(); } default: throw Error(`unexpected response from kyc-check (${res.case})`); @@ -1039,32 +1071,36 @@ export async function initiatePeerPullPayment( const mergeTimestamp = TalerPreciseTimestamp.now(); const ctx = new PeerPullCreditTransactionContext(wex, pursePair.pub); - await recordCreate(ctx, { - extraStores: ["contractTerms"], - label: "create-transaction-peer-pull-credit" - }, async (tx) => { - await tx.contractTerms.put({ - contractTermsRaw: contractTerms, - h: hContractTerms, - }); - return { - amount: req.partialContractTerms.amount, - contractTermsHash: hContractTerms, - exchangeBaseUrl: exchangeBaseUrl, - pursePriv: pursePair.priv, - pursePub: pursePair.pub, - mergePriv: mergePair.priv, - mergePub: mergePair.pub, - status: PeerPullPaymentCreditStatus.PendingCreatePurse, - mergeTimestamp: timestampPreciseToDb(mergeTimestamp), - contractEncNonce, - mergeReserveRowId: mergeReserveRowId, - contractPriv: contractKeyPair.priv, - contractPub: contractKeyPair.pub, - withdrawalGroupId, - estimatedAmountEffective: wi.withdrawalAmountEffective, - }; - }); + await recordCreate( + ctx, + { + extraStores: ["contractTerms"], + label: "create-transaction-peer-pull-credit", + }, + async (tx) => { + await tx.contractTerms.put({ + contractTermsRaw: contractTerms, + h: hContractTerms, + }); + return { + amount: req.partialContractTerms.amount, + contractTermsHash: hContractTerms, + exchangeBaseUrl: exchangeBaseUrl, + pursePriv: pursePair.priv, + pursePub: pursePair.pub, + mergePriv: mergePair.priv, + mergePub: mergePair.pub, + status: PeerPullPaymentCreditStatus.PendingCreatePurse, + mergeTimestamp: timestampPreciseToDb(mergeTimestamp), + contractEncNonce, + mergeReserveRowId: mergeReserveRowId, + contractPriv: contractKeyPair.priv, + contractPub: contractKeyPair.pub, + withdrawalGroupId, + estimatedAmountEffective: wi.withdrawalAmountEffective, + }; + }, + ); wex.taskScheduler.startShepherdTask(ctx.taskId); return {