diff options
Diffstat (limited to 'packages/taler-wallet-core/src/operations/deposits.ts')
-rw-r--r-- | packages/taler-wallet-core/src/operations/deposits.ts | 114 |
1 files changed, 81 insertions, 33 deletions
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts b/packages/taler-wallet-core/src/operations/deposits.ts index f5ea41e01..6e56b0897 100644 --- a/packages/taler-wallet-core/src/operations/deposits.ts +++ b/packages/taler-wallet-core/src/operations/deposits.ts @@ -40,6 +40,7 @@ import { j2s, Logger, MerchantContractTerms, + NotificationType, parsePaytoUri, PayCoinSelection, PrepareDepositRequest, @@ -49,9 +50,9 @@ import { TalerErrorCode, TalerProtocolTimestamp, TrackTransaction, + TransactionMajorState, + TransactionMinorState, TransactionState, - TransactionStateInfo, - TransactionSubstate, TransactionType, URL, WireFee, @@ -60,13 +61,16 @@ import { DenominationRecord, DepositGroupRecord, OperationStatus, - TransactionStatus, + DepositElementStatus, } from "../db.js"; import { TalerError } from "@gnu-taler/taler-util"; import { getTotalRefreshCost, KycPendingInfo, KycUserType } from "../index.js"; import { InternalWalletState } from "../internal-wallet-state.js"; import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http"; -import { OperationAttemptResult } from "../util/retries.js"; +import { + OperationAttemptResult, + OperationAttemptResultType, +} from "../util/retries.js"; import { spendCoins } from "./common.js"; import { getExchangeDetails } from "./exchanges.js"; import { @@ -89,15 +93,13 @@ const logger = new Logger("deposits.ts"); * Get the (DD37-style) transaction status based on the * database record of a deposit group. */ -export async function computeDepositTransactionStatus( - ws: InternalWalletState, +export function computeDepositTransactionStatus( dg: DepositGroupRecord, -): Promise<TransactionStateInfo> { +): TransactionState { switch (dg.operationStatus) { case OperationStatus.Finished: { return { - txState: TransactionState.Done, - txSubstate: TransactionSubstate.None, + major: TransactionMajorState.Done, }; } case OperationStatus.Pending: { @@ -110,10 +112,10 @@ export async function computeDepositTransactionStatus( numDeposited++; } switch (dg.transactionPerCoin[i]) { - case TransactionStatus.KycRequired: + case DepositElementStatus.KycRequired: numKycRequired++; break; - case TransactionStatus.Wired: + case DepositElementStatus.Wired: numWired++; break; } @@ -121,21 +123,21 @@ export async function computeDepositTransactionStatus( if (numKycRequired > 0) { return { - txState: TransactionState.Pending, - txSubstate: TransactionSubstate.DepositKycRequired, + major: TransactionMajorState.Pending, + minor: TransactionMinorState.KycRequired, }; } if (numDeposited == numTotal) { return { - txState: TransactionState.Pending, - txSubstate: TransactionSubstate.DepositPendingTrack, + major: TransactionMajorState.Pending, + minor: TransactionMinorState.Track, }; } return { - txState: TransactionState.Pending, - txSubstate: TransactionSubstate.DepositPendingInitial, + major: TransactionMajorState.Pending, + minor: TransactionMinorState.Deposit, }; } default: @@ -221,6 +223,13 @@ export async function processDepositGroup( return OperationAttemptResult.finishedEmpty(); } + const transactionId = constructTransactionIdentifier({ + tag: TransactionType.Deposit, + depositGroupId, + }); + + const txStateOld = computeDepositTransactionStatus(depositGroup); + const contractData = extractContractData( depositGroup.contractTermsRaw, depositGroup.contractTermsHash, @@ -239,7 +248,7 @@ export async function processDepositGroup( for (let i = 0; i < depositPermissions.length; i++) { const perm = depositPermissions[i]; - let updatedDeposit: boolean | undefined = undefined; + let updatedDeposit: boolean = false; if (!depositGroup.depositedPerCoin[i]) { const requestBody: ExchangeDepositRequest = { @@ -270,7 +279,7 @@ export async function processDepositGroup( updatedDeposit = true; } - let updatedTxStatus: TransactionStatus | undefined = undefined; + let updatedTxStatus: DepositElementStatus | undefined = undefined; type ValueOf<T> = T[keyof T]; let newWiredTransaction: @@ -280,12 +289,12 @@ export async function processDepositGroup( } | undefined; - if (depositGroup.transactionPerCoin[i] !== TransactionStatus.Wired) { - const track = await trackDepositPermission(ws, depositGroup, perm); + if (depositGroup.transactionPerCoin[i] !== DepositElementStatus.Wired) { + const track = await trackDeposit(ws, depositGroup, perm); if (track.type === "accepted") { if (!track.kyc_ok && track.requirement_row !== undefined) { - updatedTxStatus = TransactionStatus.KycRequired; + updatedTxStatus = DepositElementStatus.KycRequired; const { requirement_row: requirementRow } = track; const paytoHash = encodeCrock( hashTruncate32(stringToBytes(depositGroup.wire.payto_uri + "\0")), @@ -297,10 +306,10 @@ export async function processDepositGroup( "individual", ); } else { - updatedTxStatus = TransactionStatus.Accepted; + updatedTxStatus = DepositElementStatus.Accepted; } } else if (track.type === "wired") { - updatedTxStatus = TransactionStatus.Wired; + updatedTxStatus = DepositElementStatus.Wired; const payto = parsePaytoUri(depositGroup.wire.payto_uri); if (!payto) { @@ -327,11 +336,11 @@ export async function processDepositGroup( id: track.exchange_sig, }; } else { - updatedTxStatus = TransactionStatus.Unknown; + updatedTxStatus = DepositElementStatus.Unknown; } } - if (updatedTxStatus !== undefined || updatedDeposit !== undefined) { + if (updatedTxStatus !== undefined || updatedDeposit) { await ws.db .mktx((x) => [x.depositGroups]) .runReadWrite(async (tx) => { @@ -358,18 +367,18 @@ export async function processDepositGroup( } } - await ws.db + const txStatusNew = await ws.db .mktx((x) => [x.depositGroups]) .runReadWrite(async (tx) => { const dg = await tx.depositGroups.get(depositGroupId); if (!dg) { - return; + return undefined; } let allDepositedAndWired = true; for (let i = 0; i < depositGroup.depositedPerCoin.length; i++) { if ( !depositGroup.depositedPerCoin[i] || - depositGroup.transactionPerCoin[i] !== TransactionStatus.Wired + depositGroup.transactionPerCoin[i] !== DepositElementStatus.Wired ) { allDepositedAndWired = false; break; @@ -380,8 +389,36 @@ export async function processDepositGroup( dg.operationStatus = OperationStatus.Finished; await tx.depositGroups.put(dg); } + return computeDepositTransactionStatus(dg); + }); + + if (!txStatusNew) { + // Doesn't exist anymore! + return OperationAttemptResult.finishedEmpty(); + } + + // Notify if state transitioned + if ( + txStateOld.major !== txStatusNew.major || + txStateOld.minor !== txStatusNew.minor + ) { + ws.notify({ + type: NotificationType.TransactionStateTransition, + transactionId, + oldTxState: txStateOld, + newTxState: txStatusNew, }); - return OperationAttemptResult.finishedEmpty(); + } + + // FIXME: consider other cases like aborting, suspend, ... + if ( + txStatusNew.major === TransactionMajorState.Pending || + txStatusNew.major === TransactionMajorState.Aborting + ) { + return OperationAttemptResult.pendingEmpty(); + } else { + return OperationAttemptResult.finishedEmpty(); + } } async function getExchangeWireFee( @@ -428,7 +465,7 @@ async function getExchangeWireFee( return fee; } -async function trackDepositPermission( +async function trackDeposit( ws: InternalWalletState, depositGroup: DepositGroupRecord, dp: CoinDepositPermission, @@ -448,6 +485,7 @@ async function trackDepositPermission( }); url.searchParams.set("merchant_sig", sigResp.sig); const httpResp = await ws.http.fetch(url.href, { method: "GET" }); + logger.trace(`deposits response status: ${httpResp.status}`); switch (httpResp.status) { case HttpStatusCode.Accepted: { const accepted = await readSuccessResponseJsonOrThrow( @@ -710,7 +748,7 @@ export async function createDepositGroup( timestampCreated: AbsoluteTime.toTimestamp(now), timestampFinished: undefined, transactionPerCoin: payCoinSel.coinSel.coinPubs.map( - () => TransactionStatus.Unknown, + () => DepositElementStatus.Unknown, ), payCoinSelection: payCoinSel.coinSel, payCoinSelectionUid: encodeCrock(getRandomBytes(32)), @@ -733,7 +771,7 @@ export async function createDepositGroup( depositGroupId, }); - await ws.db + const newTxState = await ws.db .mktx((x) => [ x.depositGroups, x.coins, @@ -752,8 +790,18 @@ export async function createDepositGroup( refreshReason: RefreshReason.PayDeposit, }); await tx.depositGroups.put(depositGroup); + return computeDepositTransactionStatus(depositGroup); }); + ws.notify({ + type: NotificationType.TransactionStateTransition, + transactionId, + oldTxState: { + major: TransactionMajorState.None, + }, + newTxState, + }); + return { depositGroupId, transactionId, |