diff options
Diffstat (limited to 'packages/taler-wallet-core')
15 files changed, 751 insertions, 232 deletions
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index febc5f8fa..a95db9ca3 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -130,10 +130,10 @@ export enum OperationStatusRange {    // Operations that need to be actively processed.    ACTIVE_START = 10,    ACTIVE_END = 29, -  // Operations that need user input, but nothing can be done -  // automatically. -  USER_ATTENTION_START = 30, -  USER_ATTENTION_END = 49, +  // Operations that are suspended and might +  // expire, but nothing else can be done. +  SUSPENDED_START = 30, +  SUSPENDED_END = 49,    // Operations that don't need any attention or processing.    DORMANT_START = 50,    DORMANT_END = 69, @@ -146,24 +146,24 @@ export enum WithdrawalGroupStatus {    /**     * Reserve must be registered with the bank.     */ -  RegisteringBank = 10, +  PendingRegisteringBank = 10,    /**     * We've registered reserve's information with the bank     * and are now waiting for the user to confirm the withdraw     * with the bank (typically 2nd factor auth).     */ -  WaitConfirmBank = 11, +  PendingWaitConfirmBank = 11,    /**     * Querying reserve status with the exchange.     */ -  QueryingStatus = 12, +  PendingQueryingStatus = 12,    /**     * Ready for withdrawal.     */ -  Ready = 13, +  PendingReady = 13,    /**     * We are telling the bank that we don't want to complete @@ -174,12 +174,20 @@ export enum WithdrawalGroupStatus {    /**     * Exchange wants KYC info from the user.     */ -  Kyc = 16, +  PendingKyc = 16,    /**     * Exchange is doing AML checks.     */ -  Aml = 17, +  PendingAml = 17, + +  SuspendedRegisteringBank = 30, +  SuspendedWaitConfirmBank = 31, +  SuspendedQueryingStatus = 32, +  SuspendedReady = 33, +  SuspendedAbortingBank = 34, +  SuspendedKyc = 35, +  SuspendedAml = 36,    /**     * The corresponding withdraw record has been created. @@ -191,16 +199,16 @@ export enum WithdrawalGroupStatus {    /**     * The bank aborted the withdrawal.     */ -  BankAborted = 51, +  FailedBankAborted = 51, -  SuspendedRegisteringBank = 52, -  SuspendedWaitConfirmBank = 53, -  SuspendedQueryingStatus = 54, -  SuspendedReady = 55, -  SuspendedAbortingBank = 56, -  SuspendedKyc = 57, -  SuspendedAml = 58,    FailedAbortingBank = 59, + +  /** +   * Aborted in a state where we were supposed to +   * talk to the exchange.  Money might have been +   * wired or not. +   */ +  AbortedExchange = 60  }  /** @@ -1790,8 +1798,18 @@ export enum PeerPushPaymentInitiationStatus {    /**     * Initiated, but no purse created yet.     */ -  Initiated = 10 /* ACTIVE_START */, -  PurseCreated = 50 /* DORMANT_START */, +  PendingCreatePurse = 10 /* ACTIVE_START */, +  PendingReady = 11, +  AbortingDeletePurse = 12, +  AbortingRefresh = 13, + +  SuspendedCreatePurse = 30, +  SuspendedReady = 31, +  SuspendedAbortingDeletePurse = 32, +  SuspendedAbortingRefresh = 33, + +  Done = 50 /* DORMANT_START */, +  Aborted = 51,  }  export interface PeerPushPaymentCoinSelection { @@ -1856,14 +1874,18 @@ export interface PeerPushPaymentInitiationRecord {  }  export enum PeerPullPaymentInitiationStatus { -  Initial = 10 /* ACTIVE_START */, +  PendingCreatePurse = 10 /* ACTIVE_START */,    /**     * Purse created, waiting for the other party to accept the     * invoice and deposit money into it.     */ -  PurseCreated = 11 /* ACTIVE_START + 1 */, -  KycRequired = 12 /* ACTIVE_START + 2 */, -  PurseDeposited = 50 /* DORMANT_START */, +  PendingReady = 11 /* ACTIVE_START + 1 */, +  PendingMergeKycRequired = 12 /* ACTIVE_START + 2 */, +  PendingWithdrawing = 13, +  SuspendedCreatePurse = 30, +  SuspendedReady = 31, +  SuspendedWithdrawing = 32, +  DonePurseDeposited = 50 /* DORMANT_START */,  }  export interface PeerPullPaymentInitiationRecord { @@ -1921,12 +1943,13 @@ export interface PeerPullPaymentInitiationRecord {  export enum PeerPushPaymentIncomingStatus {    Proposed = 30 /* USER_ATTENTION_START */,    Accepted = 10 /* ACTIVE_START */, -  KycRequired = 11 /* ACTIVE_START + 1 */, +  MergeKycRequired = 11 /* ACTIVE_START + 1 */,    /**     * Merge was successful and withdrawal group has been created, now     * everything is in the hand of the withdrawal group.     */ -  WithdrawalCreated = 50 /* DORMANT_START */, +  Withdrawing = 12, +  Done = 50 /* DORMANT_START */,  }  /** diff --git a/packages/taler-wallet-core/src/internal-wallet-state.ts b/packages/taler-wallet-core/src/internal-wallet-state.ts index e59781471..760f40d6c 100644 --- a/packages/taler-wallet-core/src/internal-wallet-state.ts +++ b/packages/taler-wallet-core/src/internal-wallet-state.ts @@ -177,7 +177,7 @@ export interface InternalWalletState {     *     * Used to allow processing of new work faster.     */ -  latch: AsyncCondition; +  workAvailable: AsyncCondition;    listeners: NotificationListener[]; diff --git a/packages/taler-wallet-core/src/operations/backup/import.ts b/packages/taler-wallet-core/src/operations/backup/import.ts index 32b90e126..296517162 100644 --- a/packages/taler-wallet-core/src/operations/backup/import.ts +++ b/packages/taler-wallet-core/src/operations/backup/import.ts @@ -553,7 +553,7 @@ export async function importBackup(            reservePub,            status: backupWg.timestamp_finish              ? WithdrawalGroupStatus.Finished -            : WithdrawalGroupStatus.QueryingStatus, // FIXME! +            : WithdrawalGroupStatus.PendingQueryingStatus, // FIXME!            timestampStart: backupWg.timestamp_created,            wgInfo,            restrictAge: backupWg.restrict_age, diff --git a/packages/taler-wallet-core/src/operations/common.ts b/packages/taler-wallet-core/src/operations/common.ts index 539632b02..55015f2e0 100644 --- a/packages/taler-wallet-core/src/operations/common.ts +++ b/packages/taler-wallet-core/src/operations/common.ts @@ -492,7 +492,7 @@ export function runLongpollAsync(      if (!res.ready) {        await storeOperationPending(ws, retryTag);      } -    ws.latch.trigger(); +    ws.workAvailable.trigger();    };    asyncFn();  } diff --git a/packages/taler-wallet-core/src/operations/deposits.ts b/packages/taler-wallet-core/src/operations/deposits.ts index e1d699775..b08f03bd1 100644 --- a/packages/taler-wallet-core/src/operations/deposits.ts +++ b/packages/taler-wallet-core/src/operations/deposits.ts @@ -248,7 +248,7 @@ export async function resumeDepositGroup(        }        return undefined;      }); -  ws.latch.trigger(); +  ws.workAvailable.trigger();    if (res) {      ws.notify({        type: NotificationType.TransactionStateTransition, @@ -301,7 +301,7 @@ export async function abortDepositGroup(      });    stopLongpolling(ws, retryTag);    // Need to process the operation again. -  ws.latch.trigger(); +  ws.workAvailable.trigger();    if (res) {      ws.notify({        type: NotificationType.TransactionStateTransition, diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts b/packages/taler-wallet-core/src/operations/pay-merchant.ts index d2713dc9d..67343d69a 100644 --- a/packages/taler-wallet-core/src/operations/pay-merchant.ts +++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts @@ -2410,7 +2410,7 @@ export async function processPurchaseQueryRefund(    return OperationAttemptResult.finishedEmpty();  } -export async function abortPay( +export async function abortPayMerchant(    ws: InternalWalletState,    proposalId: string,    cancelImmediately?: boolean, @@ -2499,6 +2499,7 @@ export function computePayMerchantTransactionState(      case PurchaseStatus.Proposed:        return {          major: TransactionMajorState.Dialog, +        minor: TransactionMinorState.MerchantOrderProposed,        };      case PurchaseStatus.ProposalDownloadFailed:        return { diff --git a/packages/taler-wallet-core/src/operations/pay-peer.ts b/packages/taler-wallet-core/src/operations/pay-peer.ts index 33659afe0..31e395cab 100644 --- a/packages/taler-wallet-core/src/operations/pay-peer.ts +++ b/packages/taler-wallet-core/src/operations/pay-peer.ts @@ -75,20 +75,21 @@ import {    NotificationType,    HttpStatusCode,    codecForWalletKycUuid, -  WalletKycUuid, +  TransactionState, +  TransactionMajorState, +  TransactionMinorState,  } from "@gnu-taler/taler-util";  import { SpendCoinDetails } from "../crypto/cryptoImplementation.js";  import {    DenominationRecord, -  KycPendingInfo, -  KycUserType, -  OperationStatus, +  PeerPullPaymentIncomingRecord,    PeerPullPaymentIncomingStatus,    PeerPullPaymentInitiationRecord,    PeerPullPaymentInitiationStatus,    PeerPushPaymentCoinSelection,    PeerPushPaymentIncomingRecord,    PeerPushPaymentIncomingStatus, +  PeerPushPaymentInitiationRecord,    PeerPushPaymentInitiationStatus,    ReserveRecord,    WithdrawalGroupStatus, @@ -98,7 +99,6 @@ import { TalerError } from "@gnu-taler/taler-util";  import { InternalWalletState } from "../internal-wallet-state.js";  import {    LongpollResult, -  makeTransactionId,    resetOperationTimeout,    runLongpollAsync,    runOperationWithErrorReporting, @@ -128,8 +128,10 @@ import {  import { PendingTaskType } from "../pending-types.js";  import {    constructTransactionIdentifier, +  notifyTransition,    stopLongpolling,  } from "./transactions.js"; +import { assertUnreachable } from "../util/assertUnreachable.js";  const logger = new Logger("operations/peer-to-peer.ts"); @@ -451,19 +453,11 @@ export async function checkPeerPushDebit(    };  } -export async function processPeerPushInitiation( +async function processPeerPushDebitCreateReserve(    ws: InternalWalletState, -  pursePub: string, +  peerPushInitiation: PeerPushPaymentInitiationRecord,  ): Promise<OperationAttemptResult> { -  const peerPushInitiation = await ws.db -    .mktx((x) => [x.peerPushPaymentInitiations]) -    .runReadOnly(async (tx) => { -      return tx.peerPushPaymentInitiations.get(pursePub); -    }); -  if (!peerPushInitiation) { -    throw Error("peer push payment not found"); -  } - +  const pursePub = peerPushInitiation.pursePub;    const purseExpiration = peerPushInitiation.purseExpiration;    const hContractTerms = peerPushInitiation.contractTermsHash; @@ -501,22 +495,25 @@ export async function processPeerPushInitiation(      peerPushInitiation.exchangeBaseUrl,    ); -  const httpResp = await ws.http.postJson(createPurseUrl.href, { -    amount: peerPushInitiation.amount, -    merge_pub: peerPushInitiation.mergePub, -    purse_sig: purseSigResp.sig, -    h_contract_terms: hContractTerms, -    purse_expiration: purseExpiration, -    deposits: depositSigsResp.deposits, -    min_age: 0, -    econtract: econtractResp.econtract, +  const httpResp = await ws.http.fetch(createPurseUrl.href, { +    method: "POST", +    body: { +      amount: peerPushInitiation.amount, +      merge_pub: peerPushInitiation.mergePub, +      purse_sig: purseSigResp.sig, +      h_contract_terms: hContractTerms, +      purse_expiration: purseExpiration, +      deposits: depositSigsResp.deposits, +      min_age: 0, +      econtract: econtractResp.econtract, +    },    });    const resp = await httpResp.json();    logger.info(`resp: ${j2s(resp)}`); -  if (httpResp.status !== 200) { +  if (httpResp.status !== HttpStatusCode.Ok) {      throw Error("got error response from exchange");    } @@ -527,7 +524,7 @@ export async function processPeerPushInitiation(        if (!ppi) {          return;        } -      ppi.status = PeerPushPaymentInitiationStatus.PurseCreated; +      ppi.status = PeerPushPaymentInitiationStatus.Done;        await tx.peerPushPaymentInitiations.put(ppi);      }); @@ -537,6 +534,122 @@ export async function processPeerPushInitiation(    };  } +async function transitionPeerPushDebitFromReadyToDone( +  ws: InternalWalletState, +  pursePub: string, +): Promise<void> { +  const transactionId = constructTransactionIdentifier({ +    tag: TransactionType.PeerPushDebit, +    pursePub, +  }); +  const transitionInfo = await ws.db +    .mktx((x) => [x.peerPushPaymentInitiations]) +    .runReadWrite(async (tx) => { +      const ppiRec = await tx.peerPushPaymentInitiations.get(pursePub); +      if (!ppiRec) { +        return undefined; +      } +      if (ppiRec.status !== PeerPushPaymentInitiationStatus.PendingReady) { +        return undefined; +      } +      const oldTxState = computePeerPushDebitTransactionState(ppiRec); +      ppiRec.status = PeerPushPaymentInitiationStatus.Done; +      const newTxState = computePeerPushDebitTransactionState(ppiRec); +      return { +        oldTxState, +        newTxState, +      }; +    }); +  notifyTransition(ws, transactionId, transitionInfo); +} + +/** + * Process the "pending(ready)" state of a peer-push-debit transaction. + */ +async function processPeerPushDebitReady( +  ws: InternalWalletState, +  peerPushInitiation: PeerPushPaymentInitiationRecord, +): Promise<OperationAttemptResult> { +  const pursePub = peerPushInitiation.pursePub; +  const retryTag = constructTaskIdentifier({ +    tag: PendingTaskType.PeerPushDebit, +    pursePub, +  }); +  runLongpollAsync(ws, retryTag, async (ct) => { +    const mergeUrl = new URL(`purses/${pursePub}/merge`); +    mergeUrl.searchParams.set("timeout_ms", "30000"); +    const resp = await ws.http.fetch(mergeUrl.href, { +      // timeout: getReserveRequestTimeout(withdrawalGroup), +      cancellationToken: ct, +    }); +    if (resp.status === HttpStatusCode.Ok) { +      const purseStatus = await readSuccessResponseJsonOrThrow( +        resp, +        codecForExchangePurseStatus(), +      ); +      if (purseStatus.deposit_timestamp) { +        await transitionPeerPushDebitFromReadyToDone( +          ws, +          peerPushInitiation.pursePub, +        ); +        return { +          ready: true, +        }; +      } +    } else if (resp.status === HttpStatusCode.Gone) { +      // FIXME: transition the reserve into the expired state +    } +    return { +      ready: false, +    }; +  }); +  logger.trace( +    "returning early from withdrawal for long-polling in background", +  ); +  return { +    type: OperationAttemptResultType.Longpoll, +  }; +} + +export async function processPeerPushDebit( +  ws: InternalWalletState, +  pursePub: string, +): Promise<OperationAttemptResult> { +  const peerPushInitiation = await ws.db +    .mktx((x) => [x.peerPushPaymentInitiations]) +    .runReadOnly(async (tx) => { +      return tx.peerPushPaymentInitiations.get(pursePub); +    }); +  if (!peerPushInitiation) { +    throw Error("peer push payment not found"); +  } + +  const retryTag = constructTaskIdentifier({ +    tag: PendingTaskType.PeerPushDebit, +    pursePub, +  }); + +  // We're already running! +  if (ws.activeLongpoll[retryTag]) { +    logger.info("peer-push-debit task already in long-polling, returning!"); +    return { +      type: OperationAttemptResultType.Longpoll, +    }; +  } + +  switch (peerPushInitiation.status) { +    case PeerPushPaymentInitiationStatus.PendingCreatePurse: +      return processPeerPushDebitCreateReserve(ws, peerPushInitiation); +    case PeerPushPaymentInitiationStatus.PendingReady: +      return processPeerPushDebitReady(ws, peerPushInitiation); +  } + +  return { +    type: OperationAttemptResultType.Finished, +    result: undefined, +  }; +} +  /**   * Initiate sending a peer-to-peer push payment.   */ @@ -612,7 +725,7 @@ export async function initiatePeerPushPayment(          pursePriv: pursePair.priv,          pursePub: pursePair.pub,          timestampCreated: TalerProtocolTimestamp.now(), -        status: PeerPushPaymentInitiationStatus.Initiated, +        status: PeerPushPaymentInitiationStatus.PendingCreatePurse,          contractTerms: contractTerms,          coinSel: {            coinPubs: sel.coins.map((x) => x.coinPub), @@ -628,12 +741,12 @@ export async function initiatePeerPushPayment(      });    const taskId = constructTaskIdentifier({ -    tag: PendingTaskType.PeerPushInitiation, +    tag: PendingTaskType.PeerPushDebit,      pursePub: pursePair.pub,    });    await runOperationWithErrorReporting(ws, taskId, async () => { -    return await processPeerPushInitiation(ws, pursePair.pub); +    return await processPeerPushDebit(ws, pursePair.pub);    });    return { @@ -645,22 +758,24 @@ export async function initiatePeerPushPayment(        exchangeBaseUrl: coinSelRes.result.exchangeBaseUrl,        contractPriv: contractKeyPair.priv,      }), -    transactionId: makeTransactionId( -      TransactionType.PeerPushDebit, -      pursePair.pub, -    ), +    transactionId: constructTransactionIdentifier({ +      tag: TransactionType.PeerPushDebit, +      pursePub: pursePair.pub, +    }),    };  }  interface ExchangePurseStatus {    balance: AmountString;    deposit_timestamp?: TalerProtocolTimestamp; +  merge_timestamp?: TalerProtocolTimestamp;  }  export const codecForExchangePurseStatus = (): Codec<ExchangePurseStatus> =>    buildCodecForObject<ExchangePurseStatus>()      .property("balance", codecForAmountString())      .property("deposit_timestamp", codecOptional(codecForTimestamp)) +    .property("merge_timestamp", codecOptional(codecForTimestamp))      .build("ExchangePurseStatus");  export async function preparePeerPushCredit( @@ -879,13 +994,13 @@ export async function processPeerPushCredit(    const amount = Amounts.parseOrThrow(contractTerms.amount);    if ( -    peerInc.status === PeerPushPaymentIncomingStatus.KycRequired && +    peerInc.status === PeerPushPaymentIncomingStatus.MergeKycRequired &&      peerInc.kycInfo    ) { -    const txId = makeTransactionId( -      TransactionType.PeerPushCredit, -      peerInc.peerPushPaymentIncomingId, -    ); +    const txId = constructTransactionIdentifier({ +      tag: TransactionType.PeerPushCredit, +      peerPushPaymentIncomingId: peerInc.peerPushPaymentIncomingId, +    });      await checkWithdrawalKycStatus(        ws,        peerInc.exchangeBaseUrl, @@ -951,7 +1066,7 @@ export async function processPeerPushCredit(            paytoHash: kycPending.h_payto,            requirementRow: kycPending.requirement_row,          }; -        peerInc.status = PeerPushPaymentIncomingStatus.KycRequired; +        peerInc.status = PeerPushPaymentIncomingStatus.MergeKycRequired;          await tx.peerPushPaymentIncoming.put(peerInc);        });      return { @@ -975,7 +1090,7 @@ export async function processPeerPushCredit(      },      forcedWithdrawalGroupId: peerInc.withdrawalGroupId,      exchangeBaseUrl: peerInc.exchangeBaseUrl, -    reserveStatus: WithdrawalGroupStatus.QueryingStatus, +    reserveStatus: WithdrawalGroupStatus.PendingQueryingStatus,      reserveKeyPair: {        priv: mergeReserveInfo.reservePriv,        pub: mergeReserveInfo.reservePub, @@ -993,9 +1108,9 @@ export async function processPeerPushCredit(        }        if (          peerInc.status === PeerPushPaymentIncomingStatus.Accepted || -        peerInc.status === PeerPushPaymentIncomingStatus.KycRequired +        peerInc.status === PeerPushPaymentIncomingStatus.MergeKycRequired        ) { -        peerInc.status = PeerPushPaymentIncomingStatus.WithdrawalCreated; +        peerInc.status = PeerPushPaymentIncomingStatus.Done;        }        await tx.peerPushPaymentIncoming.put(peerInc);      }); @@ -1011,7 +1126,7 @@ export async function confirmPeerPushCredit(    req: ConfirmPeerPushCreditRequest,  ): Promise<AcceptPeerPushPaymentResponse> {    let peerInc: PeerPushPaymentIncomingRecord | undefined; -  let contractTerms: PeerContractTerms | undefined; +    await ws.db      .mktx((x) => [x.contractTerms, x.peerPushPaymentIncoming])      .runReadWrite(async (tx) => { @@ -1021,10 +1136,6 @@ export async function confirmPeerPushCredit(        if (!peerInc) {          return;        } -      const ctRec = await tx.contractTerms.get(peerInc.contractTermsHash); -      if (ctRec) { -        contractTerms = ctRec.contractTermsRaw; -      }        if (peerInc.status === PeerPushPaymentIncomingStatus.Proposed) {          peerInc.status = PeerPushPaymentIncomingStatus.Accepted;        } @@ -1037,21 +1148,15 @@ export async function confirmPeerPushCredit(      );    } -  checkDbInvariant(!!contractTerms); - -  await updateExchangeFromUrl(ws, peerInc.exchangeBaseUrl); - -  const retryTag = TaskIdentifiers.forPeerPushCredit(peerInc); +  ws.workAvailable.trigger(); -  await runOperationWithErrorReporting(ws, retryTag, () => -    processPeerPushCredit(ws, req.peerPushPaymentIncomingId), -  ); +  const transactionId = constructTransactionIdentifier({ +    tag: TransactionType.PeerPushCredit, +    peerPushPaymentIncomingId: req.peerPushPaymentIncomingId, +  });    return { -    transactionId: makeTransactionId( -      TransactionType.PeerPushCredit, -      req.peerPushPaymentIncomingId, -    ), +    transactionId,    };  } @@ -1209,11 +1314,13 @@ export async function confirmPeerPullDebit(      },    ); +  const transactionId = constructTransactionIdentifier({ +    tag: TransactionType.PeerPullDebit, +    peerPullPaymentIncomingId: req.peerPullPaymentIncomingId, +  }); +    return { -    transactionId: makeTransactionId( -      TransactionType.PeerPullDebit, -      req.peerPullPaymentIncomingId, -    ), +    transactionId,    };  } @@ -1395,7 +1502,7 @@ export async function queryPurseForPeerPullCredit(      },      forcedWithdrawalGroupId: pullIni.withdrawalGroupId,      exchangeBaseUrl: pullIni.exchangeBaseUrl, -    reserveStatus: WithdrawalGroupStatus.QueryingStatus, +    reserveStatus: WithdrawalGroupStatus.PendingQueryingStatus,      reserveKeyPair: {        priv: reserve.reservePriv,        pub: reserve.reservePub, @@ -1410,8 +1517,8 @@ export async function queryPurseForPeerPullCredit(          logger.warn("peerPullPaymentInitiation not found anymore");          return;        } -      if (finPi.status === PeerPullPaymentInitiationStatus.PurseCreated) { -        finPi.status = PeerPullPaymentInitiationStatus.PurseDeposited; +      if (finPi.status === PeerPullPaymentInitiationStatus.PendingReady) { +        finPi.status = PeerPullPaymentInitiationStatus.DonePurseDeposited;        }        await tx.peerPullPaymentInitiations.put(finPi);      }); @@ -1434,7 +1541,7 @@ export async function processPeerPullCredit(    }    const retryTag = constructTaskIdentifier({ -    tag: PendingTaskType.PeerPullInitiation, +    tag: PendingTaskType.PeerPullCredit,      pursePub,    }); @@ -1449,7 +1556,7 @@ export async function processPeerPullCredit(    logger.trace(`processing ${retryTag}, status=${pullIni.status}`);    switch (pullIni.status) { -    case PeerPullPaymentInitiationStatus.PurseDeposited: { +    case PeerPullPaymentInitiationStatus.DonePurseDeposited: {        // We implement this case so that the "retry" action on a peer-pull-credit transaction        // also retries the withdrawal task. @@ -1475,7 +1582,7 @@ export async function processPeerPullCredit(          result: undefined,        };      } -    case PeerPullPaymentInitiationStatus.PurseCreated: +    case PeerPullPaymentInitiationStatus.PendingReady:        runLongpollAsync(ws, retryTag, async (cancellationToken) =>          queryPurseForPeerPullCredit(ws, pullIni, cancellationToken),        ); @@ -1485,23 +1592,23 @@ export async function processPeerPullCredit(        return {          type: OperationAttemptResultType.Longpoll,        }; -    case PeerPullPaymentInitiationStatus.KycRequired: { +    case PeerPullPaymentInitiationStatus.PendingMergeKycRequired: { +      const transactionId = constructTransactionIdentifier({ +        tag: TransactionType.PeerPullCredit, +        pursePub: pullIni.pursePub, +      });        if (pullIni.kycInfo) { -        const txId = makeTransactionId( -          TransactionType.PeerPullCredit, -          pullIni.pursePub, -        );          await checkWithdrawalKycStatus(            ws,            pullIni.exchangeBaseUrl, -          txId, +          transactionId,            pullIni.kycInfo,            "individual",          );        }        break;      } -    case PeerPullPaymentInitiationStatus.Initial: +    case PeerPullPaymentInitiationStatus.PendingCreatePurse:        break;      default:        throw Error(`unknown PeerPullPaymentInitiationStatus ${pullIni.status}`); @@ -1590,7 +1697,8 @@ export async function processPeerPullCredit(            paytoHash: kycPending.h_payto,            requirementRow: kycPending.requirement_row,          }; -        peerIni.status = PeerPullPaymentInitiationStatus.KycRequired; +        peerIni.status = +          PeerPullPaymentInitiationStatus.PendingMergeKycRequired;          await tx.peerPullPaymentInitiations.put(peerIni);        });      return { @@ -1610,7 +1718,7 @@ export async function processPeerPullCredit(        if (!pi2) {          return;        } -      pi2.status = PeerPullPaymentInitiationStatus.PurseCreated; +      pi2.status = PeerPullPaymentInitiationStatus.PendingReady;        await tx.peerPullPaymentInitiations.put(pi2);      }); @@ -1776,7 +1884,7 @@ export async function initiatePeerPullPayment(          pursePub: pursePair.pub,          mergePriv: mergePair.priv,          mergePub: mergePair.pub, -        status: PeerPullPaymentInitiationStatus.Initial, +        status: PeerPullPaymentInitiationStatus.PendingCreatePurse,          contractTerms: contractTerms,          mergeTimestamp,          mergeReserveRowId: mergeReserveRowId, @@ -1796,7 +1904,7 @@ export async function initiatePeerPullPayment(    // check this asynchronously from the transaction status?    const taskId = constructTaskIdentifier({ -    tag: PendingTaskType.PeerPullInitiation, +    tag: PendingTaskType.PeerPullCredit,      pursePub: pursePair.pub,    }); @@ -1804,14 +1912,408 @@ export async function initiatePeerPullPayment(      return processPeerPullCredit(ws, pursePair.pub);    }); +  const transactionId = constructTransactionIdentifier({ +    tag: TransactionType.PeerPullCredit, +    pursePub: pursePair.pub, +  }); +    return {      talerUri: constructPayPullUri({        exchangeBaseUrl: exchangeBaseUrl,        contractPriv: contractKeyPair.priv,      }), -    transactionId: makeTransactionId( -      TransactionType.PeerPullCredit, -      pursePair.pub, -    ), +    transactionId,    };  } + +export function computePeerPushDebitTransactionState( +  ppiRecord: PeerPushPaymentInitiationRecord, +): TransactionState { +  switch (ppiRecord.status) { +    case PeerPushPaymentInitiationStatus.PendingCreatePurse: +      return { +        major: TransactionMajorState.Pending, +        minor: TransactionMinorState.CreatePurse, +      }; +    case PeerPushPaymentInitiationStatus.PendingReady: +      return { +        major: TransactionMajorState.Pending, +        minor: TransactionMinorState.Ready, +      }; +    case PeerPushPaymentInitiationStatus.Aborted: +      return { +        major: TransactionMajorState.Aborted, +      }; +    case PeerPushPaymentInitiationStatus.AbortingDeletePurse: +      return { +        major: TransactionMajorState.Aborting, +        minor: TransactionMinorState.DeletePurse, +      }; +    case PeerPushPaymentInitiationStatus.AbortingRefresh: +      return { +        major: TransactionMajorState.Aborting, +        minor: TransactionMinorState.Refresh, +      }; +    case PeerPushPaymentInitiationStatus.SuspendedAbortingDeletePurse: +      return { +        major: TransactionMajorState.SuspendedAborting, +        minor: TransactionMinorState.DeletePurse, +      }; +    case PeerPushPaymentInitiationStatus.SuspendedAbortingRefresh: +      return { +        major: TransactionMajorState.SuspendedAborting, +        minor: TransactionMinorState.Refresh, +      }; +    case PeerPushPaymentInitiationStatus.SuspendedCreatePurse: +      return { +        major: TransactionMajorState.Suspended, +        minor: TransactionMinorState.CreatePurse, +      }; +    case PeerPushPaymentInitiationStatus.SuspendedReady: +      return { +        major: TransactionMajorState.Suspended, +        minor: TransactionMinorState.Ready, +      }; +    case PeerPushPaymentInitiationStatus.Done: +      return { +        major: TransactionMajorState.Done, +      }; +  } +} + +export async function abortPeerPushDebitTransaction( +  ws: InternalWalletState, +  pursePub: string, +) { +  const taskId = constructTaskIdentifier({ +    tag: PendingTaskType.PeerPushDebit, +    pursePub, +  }); +  const transactionId = constructTransactionIdentifier({ +    tag: TransactionType.PeerPushDebit, +    pursePub, +  }); +  stopLongpolling(ws, taskId); +  const transitionInfo = await ws.db +    .mktx((x) => [x.peerPushPaymentInitiations]) +    .runReadWrite(async (tx) => { +      const pushDebitRec = await tx.peerPushPaymentInitiations.get(pursePub); +      if (!pushDebitRec) { +        logger.warn(`peer push debit ${pursePub} not found`); +        return; +      } +      let newStatus: PeerPushPaymentInitiationStatus | undefined = undefined; +      switch (pushDebitRec.status) { +        case PeerPushPaymentInitiationStatus.PendingReady: +        case PeerPushPaymentInitiationStatus.SuspendedReady: +          newStatus = PeerPushPaymentInitiationStatus.AbortingDeletePurse; +          break; +        case PeerPushPaymentInitiationStatus.SuspendedCreatePurse: +        case PeerPushPaymentInitiationStatus.PendingCreatePurse: +          // Network request might already be in-flight! +          newStatus = PeerPushPaymentInitiationStatus.AbortingDeletePurse; +          break; +        case PeerPushPaymentInitiationStatus.SuspendedAbortingRefresh: +        case PeerPushPaymentInitiationStatus.SuspendedAbortingDeletePurse: +        case PeerPushPaymentInitiationStatus.AbortingRefresh: +        case PeerPushPaymentInitiationStatus.Done: +        case PeerPushPaymentInitiationStatus.AbortingDeletePurse: +        case PeerPushPaymentInitiationStatus.Aborted: +          // Do nothing +          break; +        default: +          assertUnreachable(pushDebitRec.status); +      } +      if (newStatus != null) { +        const oldTxState = computePeerPushDebitTransactionState(pushDebitRec); +        pushDebitRec.status = newStatus; +        const newTxState = computePeerPushDebitTransactionState(pushDebitRec); +        await tx.peerPushPaymentInitiations.put(pushDebitRec); +        return { +          oldTxState, +          newTxState, +        }; +      } +      return undefined; +    }); +  notifyTransition(ws, transactionId, transitionInfo); +} + +export async function cancelAbortingPeerPushDebitTransaction( +  ws: InternalWalletState, +  pursePub: string, +) { +  const taskId = constructTaskIdentifier({ +    tag: PendingTaskType.PeerPushDebit, +    pursePub, +  }); +  const transactionId = constructTransactionIdentifier({ +    tag: TransactionType.PeerPushDebit, +    pursePub, +  }); +  stopLongpolling(ws, taskId); +  const transitionInfo = await ws.db +    .mktx((x) => [x.peerPushPaymentInitiations]) +    .runReadWrite(async (tx) => { +      const pushDebitRec = await tx.peerPushPaymentInitiations.get(pursePub); +      if (!pushDebitRec) { +        logger.warn(`peer push debit ${pursePub} not found`); +        return; +      } +      let newStatus: PeerPushPaymentInitiationStatus | undefined = undefined; +      switch (pushDebitRec.status) { +        case PeerPushPaymentInitiationStatus.AbortingRefresh: +        case PeerPushPaymentInitiationStatus.SuspendedAbortingRefresh: +          // FIXME: We also need to abort the refresh group! +          newStatus = PeerPushPaymentInitiationStatus.Aborted; +          break; +        case PeerPushPaymentInitiationStatus.AbortingDeletePurse: +        case PeerPushPaymentInitiationStatus.SuspendedAbortingDeletePurse: +          newStatus = PeerPushPaymentInitiationStatus.Aborted; +          break; +        case PeerPushPaymentInitiationStatus.PendingReady: +        case PeerPushPaymentInitiationStatus.SuspendedReady: +        case PeerPushPaymentInitiationStatus.SuspendedCreatePurse: +        case PeerPushPaymentInitiationStatus.PendingCreatePurse: +        case PeerPushPaymentInitiationStatus.Done: +        case PeerPushPaymentInitiationStatus.Aborted: +          // Do nothing +          break; +        default: +          assertUnreachable(pushDebitRec.status); +      } +      if (newStatus != null) { +        const oldTxState = computePeerPushDebitTransactionState(pushDebitRec); +        pushDebitRec.status = newStatus; +        const newTxState = computePeerPushDebitTransactionState(pushDebitRec); +        await tx.peerPushPaymentInitiations.put(pushDebitRec); +        return { +          oldTxState, +          newTxState, +        }; +      } +      return undefined; +    }); +  notifyTransition(ws, transactionId, transitionInfo); +} + +export async function suspendPeerPushDebitTransaction( +  ws: InternalWalletState, +  pursePub: string, +) { +  const taskId = constructTaskIdentifier({ +    tag: PendingTaskType.PeerPushDebit, +    pursePub, +  }); +  const transactionId = constructTransactionIdentifier({ +    tag: TransactionType.PeerPushDebit, +    pursePub, +  }); +  stopLongpolling(ws, taskId); +  const transitionInfo = await ws.db +    .mktx((x) => [x.peerPushPaymentInitiations]) +    .runReadWrite(async (tx) => { +      const pushDebitRec = await tx.peerPushPaymentInitiations.get(pursePub); +      if (!pushDebitRec) { +        logger.warn(`peer push debit ${pursePub} not found`); +        return; +      } +      let newStatus: PeerPushPaymentInitiationStatus | undefined = undefined; +      switch (pushDebitRec.status) { +        case PeerPushPaymentInitiationStatus.PendingCreatePurse: +          newStatus = PeerPushPaymentInitiationStatus.SuspendedCreatePurse; +          break; +        case PeerPushPaymentInitiationStatus.AbortingRefresh: +          newStatus = PeerPushPaymentInitiationStatus.SuspendedAbortingRefresh; +          break; +        case PeerPushPaymentInitiationStatus.AbortingDeletePurse: +          newStatus = +            PeerPushPaymentInitiationStatus.SuspendedAbortingDeletePurse; +          break; +        case PeerPushPaymentInitiationStatus.PendingReady: +          newStatus = PeerPushPaymentInitiationStatus.SuspendedReady; +          break; +        case PeerPushPaymentInitiationStatus.SuspendedAbortingDeletePurse: +        case PeerPushPaymentInitiationStatus.SuspendedAbortingRefresh: +        case PeerPushPaymentInitiationStatus.SuspendedReady: +        case PeerPushPaymentInitiationStatus.SuspendedCreatePurse: +        case PeerPushPaymentInitiationStatus.Done: +        case PeerPushPaymentInitiationStatus.Aborted: +          // Do nothing +          break; +        default: +          assertUnreachable(pushDebitRec.status); +      } +      if (newStatus != null) { +        const oldTxState = computePeerPushDebitTransactionState(pushDebitRec); +        pushDebitRec.status = newStatus; +        const newTxState = computePeerPushDebitTransactionState(pushDebitRec); +        await tx.peerPushPaymentInitiations.put(pushDebitRec); +        return { +          oldTxState, +          newTxState, +        }; +      } +      return undefined; +    }); +  notifyTransition(ws, transactionId, transitionInfo); +} + +export async function resumePeerPushDebitTransaction( +  ws: InternalWalletState, +  pursePub: string, +) { +  const taskId = constructTaskIdentifier({ +    tag: PendingTaskType.PeerPushDebit, +    pursePub, +  }); +  const transactionId = constructTransactionIdentifier({ +    tag: TransactionType.PeerPushDebit, +    pursePub, +  }); +  stopLongpolling(ws, taskId); +  const transitionInfo = await ws.db +    .mktx((x) => [x.peerPushPaymentInitiations]) +    .runReadWrite(async (tx) => { +      const pushDebitRec = await tx.peerPushPaymentInitiations.get(pursePub); +      if (!pushDebitRec) { +        logger.warn(`peer push debit ${pursePub} not found`); +        return; +      } +      let newStatus: PeerPushPaymentInitiationStatus | undefined = undefined; +      switch (pushDebitRec.status) { +        case PeerPushPaymentInitiationStatus.SuspendedAbortingDeletePurse: +          newStatus = PeerPushPaymentInitiationStatus.AbortingDeletePurse; +          break; +        case PeerPushPaymentInitiationStatus.SuspendedAbortingRefresh: +          newStatus = PeerPushPaymentInitiationStatus.AbortingRefresh; +          break; +        case PeerPushPaymentInitiationStatus.SuspendedReady: +          newStatus = PeerPushPaymentInitiationStatus.PendingReady; +          break; +        case PeerPushPaymentInitiationStatus.SuspendedCreatePurse: +          newStatus = PeerPushPaymentInitiationStatus.PendingCreatePurse; +          break; +        case PeerPushPaymentInitiationStatus.PendingCreatePurse: +        case PeerPushPaymentInitiationStatus.AbortingRefresh: +        case PeerPushPaymentInitiationStatus.AbortingDeletePurse: +        case PeerPushPaymentInitiationStatus.PendingReady: +        case PeerPushPaymentInitiationStatus.Done: +        case PeerPushPaymentInitiationStatus.Aborted: +          // Do nothing +          break; +        default: +          assertUnreachable(pushDebitRec.status); +      } +      if (newStatus != null) { +        const oldTxState = computePeerPushDebitTransactionState(pushDebitRec); +        pushDebitRec.status = newStatus; +        const newTxState = computePeerPushDebitTransactionState(pushDebitRec); +        await tx.peerPushPaymentInitiations.put(pushDebitRec); +        return { +          oldTxState, +          newTxState, +        }; +      } +      return undefined; +    }); +  notifyTransition(ws, transactionId, transitionInfo); +} + +export function computePeerPushCreditTransactionState( +  pushCreditRecord: PeerPushPaymentIncomingRecord, +): TransactionState { +  switch (pushCreditRecord.status) { +    case PeerPushPaymentIncomingStatus.Proposed: +      return { +        major: TransactionMajorState.Dialog, +        minor: TransactionMinorState.Proposed, +      }; +    case PeerPushPaymentIncomingStatus.Accepted: +      return { +        major: TransactionMajorState.Pending, +        minor: TransactionMinorState.Merge, +      }; +    case PeerPushPaymentIncomingStatus.Done: +      return { +        major: TransactionMajorState.Done, +      }; +    case PeerPushPaymentIncomingStatus.MergeKycRequired: +      return { +        major: TransactionMajorState.Pending, +        minor: TransactionMinorState.KycRequired, +      }; +    case PeerPushPaymentIncomingStatus.Withdrawing: +      return { +        major: TransactionMajorState.Pending, +        minor: TransactionMinorState.Withdraw, +      }; +  } +} + +export function computePeerPullCreditTransactionState( +  pullCreditRecord: PeerPullPaymentInitiationRecord, +): TransactionState { +  switch (pullCreditRecord.status) { +    case PeerPullPaymentInitiationStatus.PendingCreatePurse: +      return { +        major: TransactionMajorState.Pending, +        minor: TransactionMinorState.CreatePurse, +      }; +    case PeerPullPaymentInitiationStatus.PendingMergeKycRequired: +      return { +        major: TransactionMajorState.Pending, +        minor: TransactionMinorState.MergeKycRequired, +      }; +    case PeerPullPaymentInitiationStatus.PendingReady: +      return { +        major: TransactionMajorState.Pending, +        minor: TransactionMinorState.Ready, +      }; +    case PeerPullPaymentInitiationStatus.DonePurseDeposited: +      return { +        major: TransactionMajorState.Done, +      }; +    case PeerPullPaymentInitiationStatus.PendingWithdrawing: +      return { +        major: TransactionMajorState.Pending, +        minor: TransactionMinorState.Withdraw, +      }; +    case PeerPullPaymentInitiationStatus.SuspendedCreatePurse: +      return { +        major: TransactionMajorState.Suspended, +        minor: TransactionMinorState.CreatePurse, +      }; +    case PeerPullPaymentInitiationStatus.SuspendedReady: +      return { +        major: TransactionMajorState.Suspended, +        minor: TransactionMinorState.Ready, +      }; +    case PeerPullPaymentInitiationStatus.SuspendedWithdrawing: +      return { +        major: TransactionMajorState.Pending, +        minor: TransactionMinorState.Withdraw, +      }; +  } +} + +export function computePeerPullDebitTransactionState( +  pullDebitRecord: PeerPullPaymentIncomingRecord, +): TransactionState { +  switch (pullDebitRecord.status) { +    case PeerPullPaymentIncomingStatus.Proposed: +      return { +        major: TransactionMajorState.Dialog, +        minor: TransactionMinorState.Proposed, +      }; +    case PeerPullPaymentIncomingStatus.Accepted: +      return { +        major: TransactionMajorState.Pending, +        minor: TransactionMinorState.Deposit, +      }; +    case PeerPullPaymentIncomingStatus.Paid: +      return { +        major: TransactionMajorState.Done, +      }; +  } +} diff --git a/packages/taler-wallet-core/src/operations/pending.ts b/packages/taler-wallet-core/src/operations/pending.ts index 5e14721f8..084f807f2 100644 --- a/packages/taler-wallet-core/src/operations/pending.ts +++ b/packages/taler-wallet-core/src/operations/pending.ts @@ -364,14 +364,14 @@ async function gatherPeerPullInitiationPending(    resp: PendingOperationsResponse,  ): Promise<void> {    await tx.peerPullPaymentInitiations.iter().forEachAsync(async (pi) => { -    if (pi.status === PeerPullPaymentInitiationStatus.PurseDeposited) { +    if (pi.status === PeerPullPaymentInitiationStatus.DonePurseDeposited) {        return;      }      const opId = TaskIdentifiers.forPeerPullPaymentInitiation(pi);      const retryRecord = await tx.operationRetries.get(opId);      const timestampDue = retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now();      resp.pendingOperations.push({ -      type: PendingTaskType.PeerPullInitiation, +      type: PendingTaskType.PeerPullCredit,        ...getPendingCommon(ws, opId, timestampDue),        givesLifeness: true,        retryInfo: retryRecord?.retryInfo, @@ -421,14 +421,14 @@ async function gatherPeerPushInitiationPending(    resp: PendingOperationsResponse,  ): Promise<void> {    await tx.peerPushPaymentInitiations.iter().forEachAsync(async (pi) => { -    if (pi.status === PeerPushPaymentInitiationStatus.PurseCreated) { +    if (pi.status === PeerPushPaymentInitiationStatus.Done) {        return;      }      const opId = TaskIdentifiers.forPeerPushPaymentInitiation(pi);      const retryRecord = await tx.operationRetries.get(opId);      const timestampDue = retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now();      resp.pendingOperations.push({ -      type: PendingTaskType.PeerPushInitiation, +      type: PendingTaskType.PeerPushDebit,        ...getPendingCommon(ws, opId, timestampDue),        givesLifeness: true,        retryInfo: retryRecord?.retryInfo, @@ -450,7 +450,7 @@ async function gatherPeerPushCreditPending(      switch (pi.status) {        case PeerPushPaymentIncomingStatus.Proposed:          return; -      case PeerPushPaymentIncomingStatus.WithdrawalCreated: +      case PeerPushPaymentIncomingStatus.Done:          return;      }      const opId = TaskIdentifiers.forPeerPushCredit(pi); diff --git a/packages/taler-wallet-core/src/operations/recoup.ts b/packages/taler-wallet-core/src/operations/recoup.ts index 3b423474b..982f3cf8c 100644 --- a/packages/taler-wallet-core/src/operations/recoup.ts +++ b/packages/taler-wallet-core/src/operations/recoup.ts @@ -400,7 +400,7 @@ export async function processRecoupGroupHandler(      await internalCreateWithdrawalGroup(ws, {        amount: Amounts.parseOrThrow(result.balance),        exchangeBaseUrl: recoupGroup.exchangeBaseUrl, -      reserveStatus: WithdrawalGroupStatus.QueryingStatus, +      reserveStatus: WithdrawalGroupStatus.PendingQueryingStatus,        reserveKeyPair: {          pub: reservePub,          priv: reservePrivMap[reservePub], diff --git a/packages/taler-wallet-core/src/operations/refresh.ts b/packages/taler-wallet-core/src/operations/refresh.ts index 748c929c2..fda9a886a 100644 --- a/packages/taler-wallet-core/src/operations/refresh.ts +++ b/packages/taler-wallet-core/src/operations/refresh.ts @@ -1125,7 +1125,7 @@ export async function autoRefresh(    return OperationAttemptResult.finishedEmpty();  } -export function computeRefreshTransactionStatus( +export function computeRefreshTransactionState(    rg: RefreshGroupRecord,  ): TransactionState {    switch (rg.operationStatus) { @@ -1170,7 +1170,7 @@ export async function suspendRefreshGroup(          );          return undefined;        } -      const oldState = computeRefreshTransactionStatus(dg); +      const oldState = computeRefreshTransactionState(dg);        switch (dg.operationStatus) {          case RefreshOperationStatus.Finished:            return undefined; @@ -1179,7 +1179,7 @@ export async function suspendRefreshGroup(            await tx.refreshGroups.put(dg);            return {              oldTxState: oldState, -            newTxState: computeRefreshTransactionStatus(dg), +            newTxState: computeRefreshTransactionState(dg),            };          }          case RefreshOperationStatus.Suspended: @@ -1215,7 +1215,7 @@ export async function resumeRefreshGroup(          );          return;        } -      const oldState = computeRefreshTransactionStatus(dg); +      const oldState = computeRefreshTransactionState(dg);        switch (dg.operationStatus) {          case RefreshOperationStatus.Finished:            return; @@ -1227,12 +1227,12 @@ export async function resumeRefreshGroup(            await tx.refreshGroups.put(dg);            return {              oldTxState: oldState, -            newTxState: computeRefreshTransactionStatus(dg), +            newTxState: computeRefreshTransactionState(dg),            };        }        return undefined;      }); -  ws.latch.trigger(); +  ws.workAvailable.trigger();    if (res) {      ws.notify({        type: NotificationType.TransactionStateTransition, diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts index c122bb651..02f11d82d 100644 --- a/packages/taler-wallet-core/src/operations/transactions.ts +++ b/packages/taler-wallet-core/src/operations/transactions.ts @@ -87,14 +87,14 @@ import {  } from "./deposits.js";  import { getExchangeDetails } from "./exchanges.js";  import { -  abortPay, +  abortPayMerchant,    computePayMerchantTransactionState,    expectProposalDownload,    extractContractData,    processPurchasePay,  } from "./pay-merchant.js"; -import { processPeerPullCredit } from "./pay-peer.js"; -import { processRefreshGroup } from "./refresh.js"; +import { computePeerPullCreditTransactionState, computePeerPullDebitTransactionState, computePeerPushCreditTransactionState, computePeerPushDebitTransactionState, processPeerPullCredit } from "./pay-peer.js"; +import { computeRefreshTransactionState, processRefreshGroup } from "./refresh.js";  import { computeTipTransactionStatus, processTip } from "./tip.js";  import {    abortWithdrawalTransaction, @@ -445,7 +445,7 @@ function buildTransactionForPushPaymentDebit(  ): Transaction {    return {      type: TransactionType.PeerPushDebit, -    txState: mkTxStateUnknown(), +    txState: computePeerPushDebitTransactionState(pi),      amountEffective: pi.totalCost,      amountRaw: pi.amount,      exchangeBaseUrl: pi.exchangeBaseUrl, @@ -455,10 +455,10 @@ function buildTransactionForPushPaymentDebit(      },      frozen: false,      extendedStatus: -      pi.status != PeerPushPaymentInitiationStatus.PurseCreated +      pi.status != PeerPushPaymentInitiationStatus.Done          ? ExtendedStatus.Pending          : ExtendedStatus.Done, -    pending: pi.status != PeerPushPaymentInitiationStatus.PurseCreated, +    pending: pi.status != PeerPushPaymentInitiationStatus.Done,      timestamp: pi.timestampCreated,      talerUri: constructPayPushUri({        exchangeBaseUrl: pi.exchangeBaseUrl, @@ -478,7 +478,7 @@ function buildTransactionForPullPaymentDebit(  ): Transaction {    return {      type: TransactionType.PeerPullDebit, -    txState: mkTxStateUnknown(), +    txState: computePeerPullDebitTransactionState(pi),      amountEffective: pi.coinSel?.totalCost        ? pi.coinSel?.totalCost        : Amounts.stringify(pi.contractTerms.amount), @@ -528,7 +528,7 @@ function buildTransactionForPeerPullCredit(        });      return {        type: TransactionType.PeerPullCredit, -      txState: mkTxStateUnknown(), +      txState: computePeerPullCreditTransactionState(pullCredit),        amountEffective: Amounts.stringify(wsr.denomsSel.totalCoinValue),        amountRaw: Amounts.stringify(wsr.instructedAmount),        exchangeBaseUrl: wsr.exchangeBaseUrl, @@ -563,7 +563,7 @@ function buildTransactionForPeerPullCredit(    return {      type: TransactionType.PeerPullCredit, -    txState: mkTxStateUnknown(), +    txState: computePeerPullCreditTransactionState(pullCredit),      amountEffective: Amounts.stringify(pullCredit.estimatedAmountEffective),      amountRaw: Amounts.stringify(peerContractTerms.amount),      exchangeBaseUrl: pullCredit.exchangeBaseUrl, @@ -602,7 +602,7 @@ function buildTransactionForPeerPushCredit(      return {        type: TransactionType.PeerPushCredit, -      txState: mkTxStateUnknown(), +      txState: computePeerPushCreditTransactionState(pushInc),        amountEffective: Amounts.stringify(wsr.denomsSel.totalCoinValue),        amountRaw: Amounts.stringify(wsr.instructedAmount),        exchangeBaseUrl: wsr.exchangeBaseUrl, @@ -626,7 +626,7 @@ function buildTransactionForPeerPushCredit(    return {      type: TransactionType.PeerPushCredit, -    txState: mkTxStateUnknown(), +    txState: computePeerPushCreditTransactionState(pushInc),      // FIXME: This is wrong, needs to consider fees!      amountEffective: Amounts.stringify(peerContractTerms.amount),      amountRaw: Amounts.stringify(peerContractTerms.amount), @@ -666,7 +666,7 @@ function buildTransactionForBankIntegratedWithdraw(        bankConfirmationUrl: wgRecord.wgInfo.bankInfo.confirmUrl,        reserveIsReady:          wgRecord.status === WithdrawalGroupStatus.Finished || -        wgRecord.status === WithdrawalGroupStatus.Ready, +        wgRecord.status === WithdrawalGroupStatus.PendingReady,      },      exchangeBaseUrl: wgRecord.exchangeBaseUrl,      extendedStatus: wgRecord.timestampFinish @@ -713,7 +713,7 @@ function buildTransactionForManualWithdraw(        exchangePaytoUris,        reserveIsReady:          withdrawalGroup.status === WithdrawalGroupStatus.Finished || -        withdrawalGroup.status === WithdrawalGroupStatus.Ready, +        withdrawalGroup.status === WithdrawalGroupStatus.PendingReady,      },      exchangeBaseUrl: withdrawalGroup.exchangeBaseUrl,      extendedStatus: withdrawalGroup.timestampFinish @@ -753,7 +753,7 @@ function buildTransactionForRefresh(    ).amount;    return {      type: TransactionType.Refresh, -    txState: mkTxStateUnknown(), +    txState: computeRefreshTransactionState(refreshGroupRecord),      refreshReason: refreshGroupRecord.reason,      amountEffective: Amounts.stringify(        Amounts.zeroOfCurrency(refreshGroupRecord.currency), @@ -1538,7 +1538,7 @@ export async function retryTransaction(    switch (parsedTx.tag) {      case TransactionType.PeerPullCredit: {        const taskId = constructTaskIdentifier({ -        tag: PendingTaskType.PeerPullInitiation, +        tag: PendingTaskType.PeerPullCredit,          pursePub: parsedTx.pursePub,        });        await resetOperationTimeout(ws, taskId); @@ -1866,7 +1866,7 @@ export async function abortTransaction(    switch (txId.tag) {      case TransactionType.Payment: { -      await abortPay(ws, txId.proposalId); +      await abortPayMerchant(ws, txId.proposalId);        break;      }      case TransactionType.Withdrawal: { diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts index d1816de03..d0c4d453f 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.ts @@ -135,6 +135,7 @@ import {    notifyTransition,    stopLongpolling,  } from "./transactions.js"; +import { assertUnreachable } from "../util/assertUnreachable.js";  /**   * Logger for this file. @@ -160,25 +161,25 @@ export async function suspendWithdrawalTransaction(        }        let newStatus: WithdrawalGroupStatus | undefined = undefined;        switch (wg.status) { -        case WithdrawalGroupStatus.Ready: +        case WithdrawalGroupStatus.PendingReady:            newStatus = WithdrawalGroupStatus.SuspendedReady;            break;          case WithdrawalGroupStatus.AbortingBank:            newStatus = WithdrawalGroupStatus.SuspendedAbortingBank;            break; -        case WithdrawalGroupStatus.WaitConfirmBank: +        case WithdrawalGroupStatus.PendingWaitConfirmBank:            newStatus = WithdrawalGroupStatus.SuspendedWaitConfirmBank;            break; -        case WithdrawalGroupStatus.RegisteringBank: +        case WithdrawalGroupStatus.PendingRegisteringBank:            newStatus = WithdrawalGroupStatus.SuspendedRegisteringBank;            break; -        case WithdrawalGroupStatus.QueryingStatus: -          newStatus = WithdrawalGroupStatus.QueryingStatus; +        case WithdrawalGroupStatus.PendingQueryingStatus: +          newStatus = WithdrawalGroupStatus.SuspendedQueryingStatus;            break; -        case WithdrawalGroupStatus.Kyc: +        case WithdrawalGroupStatus.PendingKyc:            newStatus = WithdrawalGroupStatus.SuspendedKyc;            break; -        case WithdrawalGroupStatus.Aml: +        case WithdrawalGroupStatus.PendingAml:            newStatus = WithdrawalGroupStatus.SuspendedAml;            break;          default: @@ -221,25 +222,25 @@ export async function resumeWithdrawalTransaction(        let newStatus: WithdrawalGroupStatus | undefined = undefined;        switch (wg.status) {          case WithdrawalGroupStatus.SuspendedReady: -          newStatus = WithdrawalGroupStatus.Ready; +          newStatus = WithdrawalGroupStatus.PendingReady;            break;          case WithdrawalGroupStatus.SuspendedAbortingBank:            newStatus = WithdrawalGroupStatus.AbortingBank;            break;          case WithdrawalGroupStatus.SuspendedWaitConfirmBank: -          newStatus = WithdrawalGroupStatus.WaitConfirmBank; +          newStatus = WithdrawalGroupStatus.PendingWaitConfirmBank;            break;          case WithdrawalGroupStatus.SuspendedQueryingStatus: -          newStatus = WithdrawalGroupStatus.QueryingStatus; +          newStatus = WithdrawalGroupStatus.PendingQueryingStatus;            break;          case WithdrawalGroupStatus.SuspendedRegisteringBank: -          newStatus = WithdrawalGroupStatus.RegisteringBank; +          newStatus = WithdrawalGroupStatus.PendingRegisteringBank;            break;          case WithdrawalGroupStatus.SuspendedAml: -          newStatus = WithdrawalGroupStatus.Aml; +          newStatus = WithdrawalGroupStatus.PendingAml;            break;          case WithdrawalGroupStatus.SuspendedKyc: -          newStatus = WithdrawalGroupStatus.Kyc; +          newStatus = WithdrawalGroupStatus.PendingKyc;            break;          default:            logger.warn( @@ -289,21 +290,21 @@ export async function abortWithdrawalTransaction(        }        let newStatus: WithdrawalGroupStatus | undefined = undefined;        switch (wg.status) { -        case WithdrawalGroupStatus.WaitConfirmBank: -        case WithdrawalGroupStatus.RegisteringBank: +        case WithdrawalGroupStatus.PendingWaitConfirmBank: +        case WithdrawalGroupStatus.PendingRegisteringBank:          case WithdrawalGroupStatus.AbortingBank:            newStatus = WithdrawalGroupStatus.AbortingBank;            break; -        case WithdrawalGroupStatus.Aml: +        case WithdrawalGroupStatus.PendingAml:            newStatus = WithdrawalGroupStatus.SuspendedAml;            break; -        case WithdrawalGroupStatus.Kyc: +        case WithdrawalGroupStatus.PendingKyc:            newStatus = WithdrawalGroupStatus.SuspendedKyc;            break; -        case WithdrawalGroupStatus.QueryingStatus: +        case WithdrawalGroupStatus.PendingQueryingStatus:            newStatus = WithdrawalGroupStatus.SuspendedQueryingStatus;            break; -        case WithdrawalGroupStatus.Ready: +        case WithdrawalGroupStatus.PendingReady:            newStatus = WithdrawalGroupStatus.SuspendedReady;            break;          case WithdrawalGroupStatus.SuspendedAbortingBank: @@ -316,9 +317,13 @@ export async function abortWithdrawalTransaction(          case WithdrawalGroupStatus.SuspendedRegisteringBank:          case WithdrawalGroupStatus.SuspendedWaitConfirmBank:          case WithdrawalGroupStatus.Finished: -        case WithdrawalGroupStatus.BankAborted: +        case WithdrawalGroupStatus.FailedBankAborted: +        case WithdrawalGroupStatus.AbortedExchange: +        case WithdrawalGroupStatus.FailedAbortingBank:            // Not allowed            break; +        default: +          assertUnreachable(wg.status);        }        if (newStatus != null) {          const oldTxState = computeWithdrawalTransactionStatus(wg); @@ -385,7 +390,7 @@ export function computeWithdrawalTransactionStatus(    wgRecord: WithdrawalGroupRecord,  ): TransactionState {    switch (wgRecord.status) { -    case WithdrawalGroupStatus.BankAborted: +    case WithdrawalGroupStatus.FailedBankAborted:        return {          major: TransactionMajorState.Aborted,        }; @@ -393,22 +398,22 @@ export function computeWithdrawalTransactionStatus(        return {          major: TransactionMajorState.Done,        }; -    case WithdrawalGroupStatus.RegisteringBank: +    case WithdrawalGroupStatus.PendingRegisteringBank:        return {          major: TransactionMajorState.Pending,          minor: TransactionMinorState.BankRegisterReserve,        }; -    case WithdrawalGroupStatus.Ready: +    case WithdrawalGroupStatus.PendingReady:        return {          major: TransactionMajorState.Pending,          minor: TransactionMinorState.WithdrawCoins,        }; -    case WithdrawalGroupStatus.QueryingStatus: +    case WithdrawalGroupStatus.PendingQueryingStatus:        return {          major: TransactionMajorState.Pending,          minor: TransactionMinorState.ExchangeWaitReserve,        }; -    case WithdrawalGroupStatus.WaitConfirmBank: +    case WithdrawalGroupStatus.PendingWaitConfirmBank:        return {          major: TransactionMajorState.Pending,          minor: TransactionMinorState.BankConfirmTransfer, @@ -444,13 +449,13 @@ export function computeWithdrawalTransactionStatus(          minor: TransactionMinorState.WithdrawCoins,        };      } -    case WithdrawalGroupStatus.Aml: { +    case WithdrawalGroupStatus.PendingAml: {        return {          major: TransactionMajorState.Pending,          minor: TransactionMinorState.AmlRequired,        };      } -    case WithdrawalGroupStatus.Kyc: { +    case WithdrawalGroupStatus.PendingKyc: {        return {          major: TransactionMajorState.Pending,          minor: TransactionMinorState.KycRequired, @@ -473,6 +478,11 @@ export function computeWithdrawalTransactionStatus(          major: TransactionMajorState.Failed,          minor: TransactionMinorState.AbortingBank,        }; +    case WithdrawalGroupStatus.AbortedExchange: +      return { +        major: TransactionMajorState.Aborted, +        minor: TransactionMinorState.Exchange, +      }    }  } @@ -1122,7 +1132,7 @@ async function queryReserve(      withdrawalGroupId,    });    checkDbInvariant(!!withdrawalGroup); -  if (withdrawalGroup.status !== WithdrawalGroupStatus.QueryingStatus) { +  if (withdrawalGroup.status !== WithdrawalGroupStatus.PendingQueryingStatus) {      return { ready: true };    }    const reservePub = withdrawalGroup.reservePub; @@ -1135,7 +1145,7 @@ async function queryReserve(    logger.info(`querying reserve status via ${reserveUrl.href}`); -  const resp = await ws.http.get(reserveUrl.href, { +  const resp = await ws.http.fetch(reserveUrl.href, {      timeout: getReserveRequestTimeout(withdrawalGroup),      cancellationToken,    }); @@ -1177,7 +1187,7 @@ async function queryReserve(          return undefined;        }        const txStateOld = computeWithdrawalTransactionStatus(wg); -      wg.status = WithdrawalGroupStatus.Ready; +      wg.status = WithdrawalGroupStatus.PendingReady;        const txStateNew = computeWithdrawalTransactionStatus(wg);        wg.reserveBalanceAmount = Amounts.stringify(result.response.balance);        await tx.withdrawalGroups.put(wg); @@ -1250,12 +1260,12 @@ export async function processWithdrawalGroup(    }    switch (withdrawalGroup.status) { -    case WithdrawalGroupStatus.RegisteringBank: +    case WithdrawalGroupStatus.PendingRegisteringBank:        await processReserveBankStatus(ws, withdrawalGroupId);        return await processWithdrawalGroup(ws, withdrawalGroupId, {          forceNow: true,        }); -    case WithdrawalGroupStatus.QueryingStatus: { +    case WithdrawalGroupStatus.PendingQueryingStatus: {        runLongpollAsync(ws, retryTag, (ct) => {          return queryReserve(ws, withdrawalGroupId, ct);        }); @@ -1266,7 +1276,7 @@ export async function processWithdrawalGroup(          type: OperationAttemptResultType.Longpoll,        };      } -    case WithdrawalGroupStatus.WaitConfirmBank: { +    case WithdrawalGroupStatus.PendingWaitConfirmBank: {        const res = await processReserveBankStatus(ws, withdrawalGroupId);        switch (res.status) {          case BankStatusResultCode.Aborted: @@ -1284,7 +1294,7 @@ export async function processWithdrawalGroup(        }        break;      } -    case WithdrawalGroupStatus.BankAborted: { +    case WithdrawalGroupStatus.FailedBankAborted: {        // FIXME        return {          type: OperationAttemptResultType.Pending, @@ -1294,7 +1304,7 @@ export async function processWithdrawalGroup(      case WithdrawalGroupStatus.Finished:        // We can try to withdraw, nothing needs to be done with the reserve.        break; -    case WithdrawalGroupStatus.Ready: +    case WithdrawalGroupStatus.PendingReady:        // Continue with the actual withdrawal!        break;      default: @@ -1847,8 +1857,8 @@ async function registerReserveWithBank(      withdrawalGroupId,    });    switch (withdrawalGroup?.status) { -    case WithdrawalGroupStatus.WaitConfirmBank: -    case WithdrawalGroupStatus.RegisteringBank: +    case WithdrawalGroupStatus.PendingWaitConfirmBank: +    case WithdrawalGroupStatus.PendingRegisteringBank:        break;      default:        return; @@ -1885,8 +1895,8 @@ async function registerReserveWithBank(          return undefined;        }        switch (r.status) { -        case WithdrawalGroupStatus.RegisteringBank: -        case WithdrawalGroupStatus.WaitConfirmBank: +        case WithdrawalGroupStatus.PendingRegisteringBank: +        case WithdrawalGroupStatus.PendingWaitConfirmBank:            break;          default:            return; @@ -1898,7 +1908,7 @@ async function registerReserveWithBank(          AbsoluteTime.now(),        );        const oldTxState = computeWithdrawalTransactionStatus(r); -      r.status = WithdrawalGroupStatus.WaitConfirmBank; +      r.status = WithdrawalGroupStatus.PendingWaitConfirmBank;        const newTxState = computeWithdrawalTransactionStatus(r);        await tx.withdrawalGroups.put(r);        return { @@ -1928,8 +1938,8 @@ async function processReserveBankStatus(      withdrawalGroupId,    });    switch (withdrawalGroup?.status) { -    case WithdrawalGroupStatus.WaitConfirmBank: -    case WithdrawalGroupStatus.RegisteringBank: +    case WithdrawalGroupStatus.PendingWaitConfirmBank: +    case WithdrawalGroupStatus.PendingRegisteringBank:        break;      default:        return { @@ -1969,8 +1979,8 @@ async function processReserveBankStatus(            return;          }          switch (r.status) { -          case WithdrawalGroupStatus.RegisteringBank: -          case WithdrawalGroupStatus.WaitConfirmBank: +          case WithdrawalGroupStatus.PendingRegisteringBank: +          case WithdrawalGroupStatus.PendingWaitConfirmBank:              break;            default:              return; @@ -1981,7 +1991,7 @@ async function processReserveBankStatus(          const now = AbsoluteTime.toTimestamp(AbsoluteTime.now());          const oldTxState = computeWithdrawalTransactionStatus(r);          r.wgInfo.bankInfo.timestampBankConfirmed = now; -        r.status = WithdrawalGroupStatus.BankAborted; +        r.status = WithdrawalGroupStatus.FailedBankAborted;          const newTxState = computeWithdrawalTransactionStatus(r);          await tx.withdrawalGroups.put(r);          return { @@ -2002,7 +2012,7 @@ async function processReserveBankStatus(    }    // FIXME: Why do we do this?! -  if (withdrawalGroup.status === WithdrawalGroupStatus.RegisteringBank) { +  if (withdrawalGroup.status === WithdrawalGroupStatus.PendingRegisteringBank) {      await registerReserveWithBank(ws, withdrawalGroupId);      return await processReserveBankStatus(ws, withdrawalGroupId);    } @@ -2016,8 +2026,8 @@ async function processReserveBankStatus(        }        // Re-check reserve status within transaction        switch (r.status) { -        case WithdrawalGroupStatus.RegisteringBank: -        case WithdrawalGroupStatus.WaitConfirmBank: +        case WithdrawalGroupStatus.PendingRegisteringBank: +        case WithdrawalGroupStatus.PendingWaitConfirmBank:            break;          default:            return undefined; @@ -2030,7 +2040,7 @@ async function processReserveBankStatus(          logger.info("withdrawal: transfer confirmed by bank.");          const now = AbsoluteTime.toTimestamp(AbsoluteTime.now());          r.wgInfo.bankInfo.timestampBankConfirmed = now; -        r.status = WithdrawalGroupStatus.QueryingStatus; +        r.status = WithdrawalGroupStatus.PendingQueryingStatus;          // FIXME: Notification is deprecated with DD37.          ws.notify({            type: NotificationType.WithdrawalGroupBankConfirmed, @@ -2276,7 +2286,7 @@ export async function acceptWithdrawalFromUri(      },      restrictAge: req.restrictAge,      forcedDenomSel: req.forcedDenomSel, -    reserveStatus: WithdrawalGroupStatus.RegisteringBank, +    reserveStatus: WithdrawalGroupStatus.PendingRegisteringBank,    });    const withdrawalGroupId = withdrawalGroup.withdrawalGroupId; @@ -2291,19 +2301,14 @@ export async function acceptWithdrawalFromUri(    const processedWithdrawalGroup = await getWithdrawalGroupRecordTx(ws.db, {      withdrawalGroupId,    }); -  if (processedWithdrawalGroup?.status === WithdrawalGroupStatus.BankAborted) { +  if (processedWithdrawalGroup?.status === WithdrawalGroupStatus.FailedBankAborted) {      throw TalerError.fromDetail(        TalerErrorCode.WALLET_WITHDRAWAL_OPERATION_ABORTED_BY_BANK,        {},      );    } -  // Start withdrawal in the background -  processWithdrawalGroup(ws, withdrawalGroupId, { -    forceNow: true, -  }).catch((err) => { -    logger.error("Processing withdrawal (after creation) failed:", err); -  }); +  ws.workAvailable.trigger();    return {      reservePub: withdrawalGroup.reservePub, @@ -2337,7 +2342,7 @@ export async function createManualWithdrawal(      exchangeBaseUrl: req.exchangeBaseUrl,      forcedDenomSel: req.forcedDenomSel,      restrictAge: req.restrictAge, -    reserveStatus: WithdrawalGroupStatus.QueryingStatus, +    reserveStatus: WithdrawalGroupStatus.PendingQueryingStatus,    });    const withdrawalGroupId = withdrawalGroup.withdrawalGroupId; @@ -2357,18 +2362,7 @@ export async function createManualWithdrawal(        return await getFundingPaytoUris(tx, withdrawalGroup.withdrawalGroupId);      }); -  // Start withdrawal in the background (do not await!) -  // FIXME: We could also interrupt the task look if it is waiting and -  // rely on retry handling to re-process the withdrawal group. -  runOperationWithErrorReporting( -    ws, -    TaskIdentifiers.forWithdrawal(withdrawalGroup), -    async () => { -      return await processWithdrawalGroup(ws, withdrawalGroupId, { -        forceNow: true, -      }); -    }, -  ); +  ws.workAvailable.trigger();    return {      reservePub: withdrawalGroup.reservePub, diff --git a/packages/taler-wallet-core/src/pending-types.ts b/packages/taler-wallet-core/src/pending-types.ts index 0e83ef38c..23f9ae21f 100644 --- a/packages/taler-wallet-core/src/pending-types.ts +++ b/packages/taler-wallet-core/src/pending-types.ts @@ -37,9 +37,8 @@ export enum PendingTaskType {    Withdraw = "withdraw",    Deposit = "deposit",    Backup = "backup", -  // FIXME: Rename to peer-push-debit and peer-pull-debit -  PeerPushInitiation = "peer-push-initiation", -  PeerPullInitiation = "peer-pull-initiation", +  PeerPushDebit = "peer-push-debit", +  PeerPullCredit = "peer-pull-credit",    PeerPushCredit = "peer-push-credit",    PeerPullDebit = "peer-pull-debit",  } @@ -83,7 +82,7 @@ export interface PendingExchangeUpdateTask {   * The wallet wants to send a peer push payment.   */  export interface PendingPeerPushInitiationTask { -  type: PendingTaskType.PeerPushInitiation; +  type: PendingTaskType.PeerPushDebit;    pursePub: string;  } @@ -91,7 +90,7 @@ export interface PendingPeerPushInitiationTask {   * The wallet wants to send a peer pull payment.   */  export interface PendingPeerPullInitiationTask { -  type: PendingTaskType.PeerPullInitiation; +  type: PendingTaskType.PeerPullCredit;    pursePub: string;  } diff --git a/packages/taler-wallet-core/src/util/retries.ts b/packages/taler-wallet-core/src/util/retries.ts index a021087be..12e1df7e9 100644 --- a/packages/taler-wallet-core/src/util/retries.ts +++ b/packages/taler-wallet-core/src/util/retries.ts @@ -197,9 +197,9 @@ export type ParsedTaskIdentifier =    | { tag: PendingTaskType.ExchangeCheckRefresh; exchangeBaseUrl: string }    | { tag: PendingTaskType.ExchangeUpdate; exchangeBaseUrl: string }    | { tag: PendingTaskType.PeerPullDebit; peerPullPaymentIncomingId: string } -  | { tag: PendingTaskType.PeerPullInitiation; pursePub: string } +  | { tag: PendingTaskType.PeerPullCredit; pursePub: string }    | { tag: PendingTaskType.PeerPushCredit; peerPushPaymentIncomingId: string } -  | { tag: PendingTaskType.PeerPushInitiation; pursePub: string } +  | { tag: PendingTaskType.PeerPushDebit; pursePub: string }    | { tag: PendingTaskType.Purchase; proposalId: string }    | { tag: PendingTaskType.Recoup; recoupGroupId: string }    | { tag: PendingTaskType.TipPickup; walletTipId: string } @@ -223,9 +223,9 @@ export function constructTaskIdentifier(p: ParsedTaskIdentifier): string {        return `${p.tag}:${p.peerPullPaymentIncomingId}`;      case PendingTaskType.PeerPushCredit:        return `${p.tag}:${p.peerPushPaymentIncomingId}`; -    case PendingTaskType.PeerPullInitiation: +    case PendingTaskType.PeerPullCredit:        return `${p.tag}:${p.pursePub}`; -    case PendingTaskType.PeerPushInitiation: +    case PendingTaskType.PeerPushDebit:        return `${p.tag}:${p.pursePub}`;      case PendingTaskType.Purchase:        return `${p.tag}:${p.proposalId}`; @@ -276,12 +276,12 @@ export namespace TaskIdentifiers {    export function forPeerPushPaymentInitiation(      ppi: PeerPushPaymentInitiationRecord,    ): string { -    return `${PendingTaskType.PeerPushInitiation}:${ppi.pursePub}`; +    return `${PendingTaskType.PeerPushDebit}:${ppi.pursePub}`;    }    export function forPeerPullPaymentInitiation(      ppi: PeerPullPaymentInitiationRecord,    ): string { -    return `${PendingTaskType.PeerPullInitiation}:${ppi.pursePub}`; +    return `${PendingTaskType.PeerPullCredit}:${ppi.pursePub}`;    }    export function forPeerPullPaymentDebit(      ppi: PeerPullPaymentIncomingRecord, diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index 733c239f9..ed174e33b 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -208,7 +208,7 @@ import {    processPeerPullCredit,    processPeerPullDebit,    processPeerPushCredit, -  processPeerPushInitiation, +  processPeerPushDebit,  } from "./operations/pay-peer.js";  import { getPendingOperations } from "./operations/pending.js";  import { @@ -314,9 +314,9 @@ async function callOperationHandler(      }      case PendingTaskType.Backup:        return await processBackupForProvider(ws, pending.backupProviderBaseUrl); -    case PendingTaskType.PeerPushInitiation: -      return await processPeerPushInitiation(ws, pending.pursePub); -    case PendingTaskType.PeerPullInitiation: +    case PendingTaskType.PeerPushDebit: +      return await processPeerPushDebit(ws, pending.pursePub); +    case PendingTaskType.PeerPullCredit:        return await processPeerPullCredit(ws, pending.pursePub);      case PendingTaskType.PeerPullDebit:        return await processPeerPullDebit(ws, pending.peerPullPaymentIncomingId); @@ -439,7 +439,7 @@ async function runTaskLoop(        });        // Wait until either the timeout, or we are notified (via the latch)        // that more work might be available. -      await Promise.race([timeout, ws.latch.wait()]); +      await Promise.race([timeout, ws.workAvailable.wait()]);      } else {        logger.trace(          `running ${pending.pendingOperations.length} pending operations`, @@ -1659,7 +1659,7 @@ class InternalWalletStateImpl implements InternalWalletState {    merchantInfoCache: Record<string, MerchantInfo> = {};    readonly timerGroup: TimerGroup; -  latch = new AsyncCondition(); +  workAvailable = new AsyncCondition();    stopped = false;    listeners: NotificationListener[] = [];  | 
