gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: wallet-core,harness: let runI


From: gnunet
Subject: [taler-wallet-core] branch master updated: wallet-core,harness: let runIntegrationTest wait for its own transactions
Date: Mon, 29 Jan 2024 21:29:35 +0100

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new 61e3484d6 wallet-core,harness: let runIntegrationTest wait for its own 
transactions
61e3484d6 is described below

commit 61e3484d6ce1db846c435d84cbf5b9c3711a30f2
Author: Florian Dold <florian@dold.me>
AuthorDate: Mon Jan 29 21:29:26 2024 +0100

    wallet-core,harness: let runIntegrationTest wait for its own transactions
---
 .../src/integrationtests/test-wallettesting.ts     |  10 +
 packages/taler-util/src/transactions-types.ts      |  25 ++-
 packages/taler-util/src/wallet-types.ts            |  13 +-
 packages/taler-wallet-core/src/db.ts               |  22 +-
 .../taler-wallet-core/src/internal-wallet-state.ts |  28 +--
 .../taler-wallet-core/src/operations/common.ts     |   7 +-
 .../taler-wallet-core/src/operations/deposits.ts   |   4 +
 .../src/operations/pay-merchant.ts                 |  22 +-
 .../src/operations/pay-peer-pull-debit.ts          |   1 +
 .../src/operations/pay-peer-push-debit.ts          |   2 +
 .../taler-wallet-core/src/operations/recoup.ts     |  49 ++++-
 .../taler-wallet-core/src/operations/refresh.ts    |  30 ++-
 .../taler-wallet-core/src/operations/testing.ts    | 227 +++++++++++++++++----
 .../src/operations/transactions.ts                 |  18 +-
 packages/taler-wallet-core/src/wallet-api-types.ts |  38 ++--
 packages/taler-wallet-core/src/wallet.ts           |  34 ++-
 16 files changed, 391 insertions(+), 139 deletions(-)

diff --git a/packages/taler-harness/src/integrationtests/test-wallettesting.ts 
b/packages/taler-harness/src/integrationtests/test-wallettesting.ts
index ec393204f..932284d62 100644
--- a/packages/taler-harness/src/integrationtests/test-wallettesting.ts
+++ b/packages/taler-harness/src/integrationtests/test-wallettesting.ts
@@ -232,6 +232,16 @@ export async function runWallettestingTest(t: 
GlobalTestState) {
     merchantBaseUrl: merchant.makeInstanceBaseUrl(),
     summary: "foo",
   });
+
+  await walletClient.call(WalletApiOperation.ClearDb, {});
+  await walletClient.call(WalletApiOperation.RunIntegrationTestV2, {
+    amountToSpend: "TESTKUDOS:5" as AmountString,
+    amountToWithdraw: "TESTKUDOS:10" as AmountString,
+    corebankApiBaseUrl: bank.corebankApiBaseUrl,
+    exchangeBaseUrl: exchange.baseUrl,
+    merchantAuthToken: merchantAuthToken,
+    merchantBaseUrl: merchant.makeInstanceBaseUrl(),
+  });
 }
 
 runWallettestingTest.suites = ["wallet"];
diff --git a/packages/taler-util/src/transactions-types.ts 
b/packages/taler-util/src/transactions-types.ts
index 00802577a..a0bc2a89d 100644
--- a/packages/taler-util/src/transactions-types.ts
+++ b/packages/taler-util/src/transactions-types.ts
@@ -207,7 +207,8 @@ export type Transaction =
   | TransactionPeerPullDebit
   | TransactionPeerPushCredit
   | TransactionPeerPushDebit
-  | TransactionInternalWithdrawal;
+  | TransactionInternalWithdrawal
+  | TransactionRecoup;
 
 export enum TransactionType {
   Withdrawal = "withdrawal",
@@ -221,6 +222,7 @@ export enum TransactionType {
   PeerPushCredit = "peer-push-credit",
   PeerPullDebit = "peer-pull-debit",
   PeerPullCredit = "peer-pull-credit",
+  Recoup = "recoup",
 }
 
 export enum WithdrawalType {
@@ -446,6 +448,13 @@ export interface TransactionPeerPushCredit extends 
TransactionCommon {
   amountEffective: AmountString;
 }
 
+/**
+ * The exchange revoked a key and the wallet recoups funds.
+ */
+export interface TransactionRecoup extends TransactionCommon {
+  type: TransactionType.Recoup;
+}
+
 export enum PaymentStatus {
   /**
    * Explicitly aborted after timeout / failure
@@ -754,3 +763,17 @@ export const codecForOrderShortInfo = (): 
Codec<OrderShortInfo> =>
     .property("summary", codecForString())
     .property("summary_i18n", codecOptional(codecForInternationalizedString()))
     .build("OrderShortInfo");
+
+export interface ListAssociatedRefreshesRequest {
+  transactionId: string;
+}
+
+export const codecForListAssociatedRefreshesRequest =
+  (): Codec<ListAssociatedRefreshesRequest> =>
+    buildCodecForObject<ListAssociatedRefreshesRequest>()
+      .property("transactionId", codecForString())
+      .build("ListAssociatedRefreshesRequest");
+
+export interface ListAssociatedRefreshesResponse {
+  transactionIds: string[];
+}
diff --git a/packages/taler-util/src/wallet-types.ts 
b/packages/taler-util/src/wallet-types.ts
index 806e2f22b..6fcd43fc5 100644
--- a/packages/taler-util/src/wallet-types.ts
+++ b/packages/taler-util/src/wallet-types.ts
@@ -577,11 +577,11 @@ export interface CoinDumpJson {
     withdrawal_reserve_pub: string | undefined;
     coin_status: CoinStatus;
     spend_allocation:
-    | {
-      id: string;
-      amount: AmountString;
-    }
-    | undefined;
+      | {
+          id: string;
+          amount: AmountString;
+        }
+      | undefined;
     /**
      * Information about the age restriction
      */
@@ -2095,6 +2095,9 @@ export interface PrepareRefundRequest {
 }
 
 export interface StartRefundQueryForUriResponse {
+  /**
+   * Transaction id of the *payment* where the refund query was started.
+   */
   transactionId: TransactionIdStr;
 }
 
diff --git a/packages/taler-wallet-core/src/db.ts 
b/packages/taler-wallet-core/src/db.ts
index a0613fd39..b0605cb1d 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -151,7 +151,7 @@ export const CURRENT_DB_CONFIG_KEY = "currentMainDbName";
  * backwards-compatible way or object stores and indices
  * are added.
  */
-export const WALLET_DB_MINOR_VERSION = 4;
+export const WALLET_DB_MINOR_VERSION = 5;
 
 declare const symDbProtocolTimestamp: unique symbol;
 
@@ -996,14 +996,6 @@ export enum DepositElementStatus {
   RefundFailed = 0x0501_0000,
 }
 
-/**
- * Additional information about the reason of a refresh.
- */
-export interface RefreshReasonDetails {
-  originatingTransactionId?: string;
-  proposalId?: string;
-}
-
 export interface RefreshGroupPerExchangeInfo {
   /**
    * (Expected) output once the refresh group succeeded.
@@ -1035,10 +1027,7 @@ export interface RefreshGroupRecord {
    */
   reason: RefreshReason;
 
-  /**
-   * Extra information depending on the reason.
-   */
-  reasonDetails?: RefreshReasonDetails;
+  originatingTransactionId?: string;
 
   oldCoinPubs: string[];
 
@@ -2461,6 +2450,13 @@ export const WalletStoresV1 = {
     }),
     {
       byStatus: describeIndex("byStatus", "operationStatus"),
+      byOriginatingTransactionId: describeIndex(
+        "byOriginatingTransactionId",
+        "originatingTransactionId",
+        {
+          versionAdded: 5,
+        },
+      ),
     },
   ),
   refreshSessions: describeStore(
diff --git a/packages/taler-wallet-core/src/internal-wallet-state.ts 
b/packages/taler-wallet-core/src/internal-wallet-state.ts
index 8c49f8e5e..fdf04a65f 100644
--- a/packages/taler-wallet-core/src/internal-wallet-state.ts
+++ b/packages/taler-wallet-core/src/internal-wallet-state.ts
@@ -29,8 +29,8 @@
 /**
  * Imports.
  */
+import { IDBFactory } from "@gnu-taler/idb-bridge";
 import {
-  CancellationToken,
   CoinRefreshRequest,
   DenominationInfo,
   RefreshGroupId,
@@ -40,12 +40,7 @@ import {
 } from "@gnu-taler/taler-util";
 import { HttpRequestLibrary } from "@gnu-taler/taler-util/http";
 import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js";
-import {
-  ExchangeDetailsRecord,
-  ExchangeEntryRecord,
-  RefreshReasonDetails,
-  WalletStoresV1,
-} from "./db.js";
+import { WalletStoresV1 } from "./db.js";
 import { AsyncCondition } from "./util/promiseUtils.js";
 import {
   DbAccess,
@@ -54,8 +49,6 @@ import {
 } from "./util/query.js";
 import { TimerGroup } from "./util/timer.js";
 import { WalletConfig } from "./wallet-api-types.js";
-import { IDBFactory } from "@gnu-taler/idb-bridge";
-import { ReadyExchangeSummary } from "./index.js";
 
 export const EXCHANGE_COINS_LOCK = "exchange-coins-lock";
 export const EXCHANGE_RESERVES_LOCK = "exchange-reserves-lock";
@@ -69,22 +62,6 @@ export interface MerchantInfo {
   protocolVersionCurrent: number;
 }
 
-export interface RefreshOperations {
-  createRefreshGroup(
-    ws: InternalWalletState,
-    tx: GetReadWriteAccess<{
-      denominations: typeof WalletStoresV1.denominations;
-      coins: typeof WalletStoresV1.coins;
-      refreshGroups: typeof WalletStoresV1.refreshGroups;
-      coinAvailability: typeof WalletStoresV1.coinAvailability;
-    }>,
-    currency: string,
-    oldCoinPubs: CoinRefreshRequest[],
-    reason: RefreshReason,
-    reasonDetails?: RefreshReasonDetails,
-  ): Promise<RefreshGroupId>;
-}
-
 export interface RecoupOperations {
   createRecoupGroup(
     ws: InternalWalletState,
@@ -144,7 +121,6 @@ export interface InternalWalletState {
   merchantInfoCache: Record<string, MerchantInfo>;
 
   recoupOps: RecoupOperations;
-  refreshOps: RefreshOperations;
 
   isTaskLoopRunning: boolean;
 
diff --git a/packages/taler-wallet-core/src/operations/common.ts 
b/packages/taler-wallet-core/src/operations/common.ts
index d626f0056..460a32666 100644
--- a/packages/taler-wallet-core/src/operations/common.ts
+++ b/packages/taler-wallet-core/src/operations/common.ts
@@ -70,6 +70,7 @@ import { PendingTaskType, TaskId } from "../pending-types.js";
 import { assertUnreachable } from "../util/assertUnreachable.js";
 import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
 import { GetReadOnlyAccess, GetReadWriteAccess } from "../util/query.js";
+import { createRefreshGroup } from "./refresh.js";
 import { constructTransactionIdentifier } from "./transactions.js";
 
 const logger = new Logger("operations/common.ts");
@@ -240,15 +241,13 @@ export async function spendCoins(
     await tx.coinAvailability.put(coinAvailability);
   }
 
-  await ws.refreshOps.createRefreshGroup(
+  await createRefreshGroup(
     ws,
     tx,
     Amounts.currencyOf(csi.contributions[0]),
     refreshCoinPubs,
     csi.refreshReason,
-    {
-      originatingTransactionId: csi.allocationId,
-    },
+    csi.allocationId,
   );
 }
 
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts 
b/packages/taler-wallet-core/src/operations/deposits.ts
index 62c1e406c..4a6791922 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -558,6 +558,10 @@ async function refundDepositGroup(
           currency,
           refreshCoins,
           RefreshReason.AbortDeposit,
+          constructTransactionIdentifier({
+            tag: TransactionType.Deposit,
+            depositGroupId: newDg.depositGroupId,
+          }),
         );
         newDg.abortRefreshGroupId = rgid.refreshGroupId;
       }
diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts 
b/packages/taler-wallet-core/src/operations/pay-merchant.ts
index f6bbe5b9f..c71dd7d90 100644
--- a/packages/taler-wallet-core/src/operations/pay-merchant.ts
+++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts
@@ -146,6 +146,7 @@ import {
 import {
   constructTransactionIdentifier,
   notifyTransition,
+  parseTransactionIdentifier,
   stopLongpolling,
 } from "./transactions.js";
 
@@ -319,6 +320,7 @@ export class PayMerchantTransactionContext implements 
TransactionContext {
                 currency,
                 refreshCoins,
                 RefreshReason.AbortPay,
+                this.transactionId,
               );
             }
             break;
@@ -1669,10 +1671,15 @@ async function runPayForConfirmPay(
  */
 export async function confirmPay(
   ws: InternalWalletState,
-  proposalId: string,
+  transactionId: string,
   sessionIdOverride?: string,
   forcedCoinSel?: ForcedCoinSel,
 ): Promise<ConfirmPayResult> {
+  const parsedTx = parseTransactionIdentifier(transactionId);
+  if (parsedTx?.tag !== TransactionType.Payment) {
+    throw Error("expected payment transaction ID");
+  }
+  const proposalId = parsedTx.proposalId;
   logger.trace(
     `executing confirmPay with proposalId ${proposalId} and sessionIdOverride 
${sessionIdOverride}`,
   );
@@ -1686,11 +1693,6 @@ export async function confirmPay(
     throw Error(`proposal with id ${proposalId} not found`);
   }
 
-  const transactionId = constructTransactionIdentifier({
-    tag: TransactionType.Payment,
-    proposalId,
-  });
-
   const d = await expectProposalDownload(ws, proposal);
   if (!d) {
     throw Error("proposal is in invalid state");
@@ -1815,6 +1817,8 @@ export async function confirmPay(
     hintTransactionId: transactionId,
   });
 
+  // We directly make a first attempt to pay.
+  // FIXME: In the future we should just wait for the right event
   return runPayForConfirmPay(ws, proposalId);
 }
 
@@ -3082,6 +3086,12 @@ async function storeRefunds(
             Amounts.currencyOf(download.contractData.amount),
             refreshCoins,
             RefreshReason.Refund,
+            // Since refunds are really just pseudo-transactions,
+            // the originating transaction for the refresh is the payment 
transaction.
+            constructTransactionIdentifier({
+              tag: TransactionType.Payment,
+              proposalId: myPurchase.proposalId,
+            }),
           );
         }
       }
diff --git a/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts 
b/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts
index 0f9f29fb5..c7e447dab 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts
@@ -267,6 +267,7 @@ export class PeerPullDebitTransactionContext implements 
TransactionContext {
           currency,
           coinPubs,
           RefreshReason.AbortPeerPullDebit,
+          this.transactionId,
         );
 
         pi.status = PeerPullDebitRecordStatus.AbortingRefresh;
diff --git a/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts 
b/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts
index 4fd1ef3b2..2e5af4e78 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts
@@ -615,6 +615,7 @@ async function processPeerPushDebitAbortingDeletePurse(
         currency,
         coinPubs,
         RefreshReason.AbortPeerPushDebit,
+        transactionId,
       );
       ppiRec.status = PeerPushDebitStatus.AbortingRefreshDeleted;
       ppiRec.abortRefreshGroupId = refresh.refreshGroupId;
@@ -847,6 +848,7 @@ async function processPeerPushDebitReady(
             currency,
             coinPubs,
             RefreshReason.AbortPeerPushDebit,
+            transactionId,
           );
           ppiRec.status = PeerPushDebitStatus.AbortingRefreshExpired;
           ppiRec.abortRefreshGroupId = refresh.refreshGroupId;
diff --git a/packages/taler-wallet-core/src/operations/recoup.ts 
b/packages/taler-wallet-core/src/operations/recoup.ts
index 782e98d1c..0ae873125 100644
--- a/packages/taler-wallet-core/src/operations/recoup.ts
+++ b/packages/taler-wallet-core/src/operations/recoup.ts
@@ -30,6 +30,7 @@ import {
   Logger,
   RefreshReason,
   TalerPreciseTimestamp,
+  TransactionType,
   URL,
   codecForRecoupConfirmation,
   codecForReserveStatus,
@@ -52,9 +53,15 @@ import {
 import { InternalWalletState } from "../internal-wallet-state.js";
 import { checkDbInvariant } from "../util/invariants.js";
 import { GetReadWriteAccess } from "../util/query.js";
-import { TaskRunResult } from "./common.js";
+import {
+  TaskRunResult,
+  TransactionContext,
+  constructTaskIdentifier,
+} from "./common.js";
 import { createRefreshGroup } from "./refresh.js";
 import { internalCreateWithdrawalGroup } from "./withdraw.js";
+import { constructTransactionIdentifier } from "./transactions.js";
+import { PendingTaskType } from "../pending-types.js";
 
 const logger = new Logger("operations/recoup.ts");
 
@@ -394,12 +401,16 @@ export async function processRecoupGroup(
       }
       rg2.timestampFinished = 
timestampPreciseToDb(TalerPreciseTimestamp.now());
       if (rg2.scheduleRefreshCoins.length > 0) {
-        const refreshGroupId = await createRefreshGroup(
+        await createRefreshGroup(
           ws,
           tx,
           Amounts.currencyOf(rg2.scheduleRefreshCoins[0].amount),
           rg2.scheduleRefreshCoins,
           RefreshReason.Recoup,
+          constructTransactionIdentifier({
+            tag: TransactionType.Recoup,
+            recoupGroupId: rg2.recoupGroupId,
+          }),
         );
       }
       await tx.recoupGroups.put(rg2);
@@ -407,6 +418,40 @@ export async function processRecoupGroup(
   return TaskRunResult.finished();
 }
 
+export class RewardTransactionContext implements TransactionContext {
+  abortTransaction(): Promise<void> {
+    throw new Error("Method not implemented.");
+  }
+  suspendTransaction(): Promise<void> {
+    throw new Error("Method not implemented.");
+  }
+  resumeTransaction(): Promise<void> {
+    throw new Error("Method not implemented.");
+  }
+  failTransaction(): Promise<void> {
+    throw new Error("Method not implemented.");
+  }
+  deleteTransaction(): Promise<void> {
+    throw new Error("Method not implemented.");
+  }
+  public transactionId: string;
+  public retryTag: string;
+
+  constructor(
+    public ws: InternalWalletState,
+    private recoupGroupId: string,
+  ) {
+    this.transactionId = constructTransactionIdentifier({
+      tag: TransactionType.Recoup,
+      recoupGroupId,
+    });
+    this.retryTag = constructTaskIdentifier({
+      tag: PendingTaskType.Recoup,
+      recoupGroupId,
+    });
+  }
+}
+
 export async function createRecoupGroup(
   ws: InternalWalletState,
   tx: GetReadWriteAccess<{
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts 
b/packages/taler-wallet-core/src/operations/refresh.ts
index efaeeefb1..39c6ef906 100644
--- a/packages/taler-wallet-core/src/operations/refresh.ts
+++ b/packages/taler-wallet-core/src/operations/refresh.ts
@@ -75,7 +75,6 @@ import {
   RefreshCoinStatus,
   RefreshGroupRecord,
   RefreshOperationStatus,
-  RefreshReasonDetails,
   WalletStoresV1,
 } from "../db.js";
 import {
@@ -84,7 +83,6 @@ import {
   RefreshSessionRecord,
   timestampPreciseToDb,
   timestampProtocolFromDb,
-  WalletDbReadWriteTransaction,
   WalletDbReadWriteTransactionArr,
 } from "../index.js";
 import {
@@ -1268,8 +1266,8 @@ export async function createRefreshGroup(
   >,
   currency: string,
   oldCoinPubs: CoinRefreshRequest[],
-  reason: RefreshReason,
-  reasonDetails?: RefreshReasonDetails,
+  refreshReason: RefreshReason,
+  originatingTransactionId: string | undefined,
 ): Promise<CreateRefreshGroupResult> {
   const refreshGroupId = encodeCrock(getRandomBytes(32));
 
@@ -1285,8 +1283,8 @@ export async function createRefreshGroup(
     timestampFinished: undefined,
     statusPerCoin: oldCoinPubs.map(() => RefreshCoinStatus.Pending),
     oldCoinPubs: oldCoinPubs.map((x) => x.coinPub),
-    reasonDetails,
-    reason,
+    originatingTransactionId,
+    reason: refreshReason,
     refreshGroupId,
     inputPerCoin: oldCoinPubs.map((x) => x.amount),
     expectedOutputPerCoin: estimatedOutputPerCoin.map((x) =>
@@ -1418,6 +1416,7 @@ export async function autoRefresh(
           exchange.detailsPointer?.currency,
           refreshCoins,
           RefreshReason.Scheduled,
+          undefined,
         );
         logger.trace(
           `created refresh group for auto-refresh (${res.refreshGroupId})`,
@@ -1476,6 +1475,24 @@ export function computeRefreshTransactionActions(
   }
 }
 
+export function getRefreshesForTransaction(
+  ws: InternalWalletState,
+  transactionId: string,
+): Promise<string[]> {
+  return ws.db.runReadOnlyTx(["refreshGroups"], async (tx) => {
+    const groups =
+      await tx.refreshGroups.indexes.byOriginatingTransactionId.getAll(
+        transactionId,
+      );
+    return groups.map((x) =>
+      constructTransactionIdentifier({
+        tag: TransactionType.Refresh,
+        refreshGroupId: x.refreshGroupId,
+      }),
+    );
+  });
+}
+
 export async function forceRefresh(
   ws: InternalWalletState,
   req: ForceRefreshRequest,
@@ -1515,6 +1532,7 @@ export async function forceRefresh(
         Amounts.currencyOf(coinPubs[0].amount),
         coinPubs,
         RefreshReason.Manual,
+        undefined,
       );
     });
 
diff --git a/packages/taler-wallet-core/src/operations/testing.ts 
b/packages/taler-wallet-core/src/operations/testing.ts
index d75fb54a7..f2fb74bdb 100644
--- a/packages/taler-wallet-core/src/operations/testing.ts
+++ b/packages/taler-wallet-core/src/operations/testing.ts
@@ -54,7 +54,11 @@ import {
   HttpRequestLibrary,
   readSuccessResponseJsonOrThrow,
 } from "@gnu-taler/taler-util/http";
-import { OpenedPromise, openPromise } from "../index.js";
+import {
+  getRefreshesForTransaction,
+  OpenedPromise,
+  openPromise,
+} from "../index.js";
 import { InternalWalletState } from "../internal-wallet-state.js";
 import { checkLogicInvariant } from "../util/invariants.js";
 import { getBalances } from "./balance.js";
@@ -85,10 +89,17 @@ interface MerchantBackendInfo {
   authToken?: string;
 }
 
+export interface WithdrawTestBalanceResult {
+  /**
+   * Transaction ID of the newly created withdrawal transaction.
+   */
+  transactionId: string;
+}
+
 export async function withdrawTestBalance(
   ws: InternalWalletState,
   req: WithdrawTestBalanceRequest,
-): Promise<void> {
+): Promise<WithdrawTestBalanceResult> {
   const amount = req.amount;
   const exchangeBaseUrl = req.exchangeBaseUrl;
   const corebankApiBaseUrl = req.corebankApiBaseUrl;
@@ -109,7 +120,7 @@ export async function withdrawTestBalance(
     amount,
   );
 
-  await acceptWithdrawalFromUri(ws, {
+  const acceptResp = await acceptWithdrawalFromUri(ws, {
     talerWithdrawUri: wresp.taler_withdraw_uri,
     selectedExchange: exchangeBaseUrl,
     forcedDenomSel: req.forcedDenomSel,
@@ -118,6 +129,10 @@ export async function withdrawTestBalance(
   await corebankClient.confirmWithdrawalOperation(bankUser.username, {
     withdrawalOperationId: wresp.withdrawal_id,
   });
+
+  return {
+    transactionId: acceptResp.transactionId,
+  };
 }
 
 /**
@@ -151,7 +166,9 @@ async function refund(
     reason,
     refund: refundAmount,
   };
-  const resp = await http.postJson(reqUrl.href, refundReq, {
+  const resp = await http.fetch(reqUrl.href, {
+    method: "POST",
+    body: refundReq,
     headers: getMerchantAuthHeader(merchantBackend),
   });
   const r = await readSuccessResponseJsonOrThrow(resp, codecForAny());
@@ -210,12 +227,17 @@ async function checkPayment(
   return readSuccessResponseJsonOrThrow(resp, codecForCheckPaymentResponse());
 }
 
+interface MakePaymentResult {
+  orderId: string;
+  paymentTransactionId: string;
+}
+
 async function makePayment(
   ws: InternalWalletState,
   merchant: MerchantBackendInfo,
   amount: string,
   summary: string,
-): Promise<{ orderId: string }> {
+): Promise<MakePaymentResult> {
   const orderResp = await createOrder(
     ws.http,
     merchant,
@@ -245,7 +267,7 @@ async function makePayment(
 
   const confirmPayResult = await confirmPay(
     ws,
-    preparePayResult.proposalId,
+    preparePayResult.transactionId,
     undefined,
   );
 
@@ -261,6 +283,7 @@ async function makePayment(
 
   return {
     orderId: orderResp.orderId,
+    paymentTransactionId: preparePayResult.transactionId,
   };
 }
 
@@ -274,12 +297,12 @@ export async function runIntegrationTest(
   const currency = parsedSpendAmount.currency;
 
   logger.info("withdrawing test balance");
-  await withdrawTestBalance(ws, {
+  const withdrawRes1 = await withdrawTestBalance(ws, {
     amount: args.amountToWithdraw,
     corebankApiBaseUrl: args.corebankApiBaseUrl,
     exchangeBaseUrl: args.exchangeBaseUrl,
   });
-  await waitUntilTransactionsFinal(ws);
+  await waitUntilGivenTransactionsFinal(ws, [withdrawRes1.transactionId]);
   logger.info("done withdrawing test balance");
 
   const balance = await getBalances(ws);
@@ -291,10 +314,17 @@ export async function runIntegrationTest(
     authToken: args.merchantAuthToken,
   };
 
-  await makePayment(ws, myMerchant, args.amountToSpend, "hello world");
+  const makePaymentRes = await makePayment(
+    ws,
+    myMerchant,
+    args.amountToSpend,
+    "hello world",
+  );
 
-  // Wait until the refresh is done
-  await waitUntilTransactionsFinal(ws);
+  await waitUntilTransactionWithAssociatedRefreshesFinal(
+    ws,
+    makePaymentRes.paymentTransactionId,
+  );
 
   logger.trace("withdrawing test balance for refund");
   const withdrawAmountTwo = Amounts.parseOrThrow(`${currency}:18`);
@@ -302,14 +332,13 @@ export async function runIntegrationTest(
   const refundAmount = Amounts.parseOrThrow(`${currency}:6`);
   const spendAmountThree = Amounts.parseOrThrow(`${currency}:3`);
 
-  await withdrawTestBalance(ws, {
+  const withdrawRes2 = await withdrawTestBalance(ws, {
     amount: Amounts.stringify(withdrawAmountTwo),
     corebankApiBaseUrl: args.corebankApiBaseUrl,
     exchangeBaseUrl: args.exchangeBaseUrl,
   });
 
-  // Wait until the withdraw is done
-  await waitUntilTransactionsFinal(ws);
+  await waitUntilGivenTransactionsFinal(ws, [withdrawRes2.transactionId]);
 
   const { orderId: refundOrderId } = await makePayment(
     ws,
@@ -328,16 +357,19 @@ export async function runIntegrationTest(
 
   logger.trace("refund URI", refundUri);
 
-  await startRefundQueryForUri(ws, refundUri);
+  const refundResp = await startRefundQueryForUri(ws, refundUri);
 
   logger.trace("integration test: applied refund");
 
   // Wait until the refund is done
-  await waitUntilTransactionsFinal(ws);
+  await waitUntilTransactionWithAssociatedRefreshesFinal(
+    ws,
+    refundResp.transactionId,
+  );
 
   logger.trace("integration test: making payment after refund");
 
-  await makePayment(
+  const paymentResp2 = await makePayment(
     ws,
     myMerchant,
     Amounts.stringify(spendAmountThree),
@@ -346,7 +378,13 @@ export async function runIntegrationTest(
 
   logger.trace("integration test: make payment done");
 
-  await waitUntilTransactionsFinal(ws);
+  await waitUntilGivenTransactionsFinal(ws, [
+    paymentResp2.paymentTransactionId,
+  ]);
+  await waitUntilGivenTransactionsFinal(
+    ws,
+    await getRefreshesForTransaction(ws, paymentResp2.paymentTransactionId),
+  );
 
   logger.trace("integration test: all done!");
 }
@@ -354,7 +392,7 @@ export async function runIntegrationTest(
 /**
  * Wait until all transactions are in a final state.
  */
-export async function waitUntilTransactionsFinal(
+export async function waitUntilAllTransactionsFinal(
   ws: InternalWalletState,
 ): Promise<void> {
   logger.info("waiting until all transactions are in a final state");
@@ -404,6 +442,76 @@ export async function waitUntilTransactionsFinal(
   logger.info("done waiting until all transactions are in a final state");
 }
 
+/**
+ * Wait until all chosen transactions are in a final state.
+ */
+export async function waitUntilGivenTransactionsFinal(
+  ws: InternalWalletState,
+  transactionIds: string[],
+): Promise<void> {
+  logger.info(
+    `waiting until given ${transactionIds.length} transactions are in a final 
state`,
+  );
+  logger.info(`transaction IDs are: ${j2s(transactionIds)}`);
+  if (transactionIds.length === 0) {
+    return;
+  }
+  ws.ensureTaskLoopRunning();
+  const txIdSet = new Set(transactionIds);
+  let p: OpenedPromise<void> | undefined = undefined;
+  const cancelNotifs = ws.addNotificationListener((notif) => {
+    if (!p) {
+      return;
+    }
+    if (notif.type === NotificationType.TransactionStateTransition) {
+      if (!txIdSet.has(notif.transactionId)) {
+        return;
+      }
+      switch (notif.newTxState.major) {
+        case TransactionMajorState.Pending:
+        case TransactionMajorState.Aborting:
+        case TransactionMajorState.Suspended:
+        case TransactionMajorState.SuspendedAborting:
+          break;
+        default:
+          p.resolve();
+      }
+    }
+  });
+  while (1) {
+    p = openPromise();
+    const txs = await getTransactions(ws, {
+      includeRefreshes: true,
+      filterByState: "nonfinal",
+    });
+    let finished = true;
+    for (const tx of txs.transactions) {
+      if (!txIdSet.has(tx.transactionId)) {
+        // Don't look at this transaction, we're not interested in it.
+        continue;
+      }
+      switch (tx.txState.major) {
+        case TransactionMajorState.Pending:
+        case TransactionMajorState.Aborting:
+        case TransactionMajorState.Suspended:
+        case TransactionMajorState.SuspendedAborting:
+          finished = false;
+          logger.info(
+            `continuing waiting, ${tx.transactionId} in 
${tx.txState.major}(${tx.txState.minor})`,
+          );
+          break;
+      }
+    }
+    if (finished) {
+      break;
+    }
+    // Wait until transaction state changed
+    await p.promise;
+  }
+  cancelNotifs();
+  logger.info("done waiting until given transactions are in a final state");
+}
+
 /**
  * Wait until pending work is processed.
  */
@@ -571,12 +679,29 @@ export async function waitTransactionState(
   cancelNotifs();
 }
 
+export async function waitUntilTransactionWithAssociatedRefreshesFinal(
+  ws: InternalWalletState,
+  transactionId: string,
+): Promise<void> {
+  await waitUntilGivenTransactionsFinal(ws, [transactionId]);
+  await waitUntilGivenTransactionsFinal(
+    ws,
+    await getRefreshesForTransaction(ws, transactionId),
+  );
+}
+
+export async function waitUntilTransactionFinal(
+  ws: InternalWalletState,
+  transactionId: string,
+): Promise<void> {
+  await waitUntilGivenTransactionsFinal(ws, [transactionId]);
+}
+
 export async function runIntegrationTest2(
   ws: InternalWalletState,
   args: IntegrationTestV2Args,
 ): Promise<void> {
-  // FIXME: Make sure that a task look is running, since we're
-  // waiting for notifications.
+  ws.ensureTaskLoopRunning();
   logger.info("running test with arguments", args);
 
   const exchangeInfo = await fetchFreshExchange(ws, args.exchangeBaseUrl);
@@ -587,12 +712,12 @@ export async function runIntegrationTest2(
   const amountToSpend = Amounts.parseOrThrow(`${currency}:2`);
 
   logger.info("withdrawing test balance");
-  await withdrawTestBalance(ws, {
+  const withdrawalRes = await withdrawTestBalance(ws, {
     amount: Amounts.stringify(amountToWithdraw),
     corebankApiBaseUrl: args.corebankApiBaseUrl,
     exchangeBaseUrl: args.exchangeBaseUrl,
   });
-  await waitUntilTransactionsFinal(ws);
+  await waitUntilTransactionFinal(ws, withdrawalRes.transactionId);
   logger.info("done withdrawing test balance");
 
   const balance = await getBalances(ws);
@@ -604,15 +729,17 @@ export async function runIntegrationTest2(
     authToken: args.merchantAuthToken,
   };
 
-  await makePayment(
+  const makePaymentRes = await makePayment(
     ws,
     myMerchant,
     Amounts.stringify(amountToSpend),
     "hello world",
   );
 
-  // Wait until the refresh is done
-  await waitUntilTransactionsFinal(ws);
+  await waitUntilTransactionWithAssociatedRefreshesFinal(
+    ws,
+    makePaymentRes.paymentTransactionId,
+  );
 
   logger.trace("withdrawing test balance for refund");
   const withdrawAmountTwo = Amounts.parseOrThrow(`${currency}:18`);
@@ -620,14 +747,14 @@ export async function runIntegrationTest2(
   const refundAmount = Amounts.parseOrThrow(`${currency}:6`);
   const spendAmountThree = Amounts.parseOrThrow(`${currency}:3`);
 
-  await withdrawTestBalance(ws, {
+  const withdrawalRes2 = await withdrawTestBalance(ws, {
     amount: Amounts.stringify(withdrawAmountTwo),
     corebankApiBaseUrl: args.corebankApiBaseUrl,
     exchangeBaseUrl: args.exchangeBaseUrl,
   });
 
   // Wait until the withdraw is done
-  await waitUntilTransactionsFinal(ws);
+  await waitUntilTransactionFinal(ws, withdrawalRes2.transactionId);
 
   const { orderId: refundOrderId } = await makePayment(
     ws,
@@ -646,25 +773,31 @@ export async function runIntegrationTest2(
 
   logger.trace("refund URI", refundUri);
 
-  await startRefundQueryForUri(ws, refundUri);
+  const refundResp = await startRefundQueryForUri(ws, refundUri);
 
   logger.trace("integration test: applied refund");
 
   // Wait until the refund is done
-  await waitUntilTransactionsFinal(ws);
+  await waitUntilTransactionWithAssociatedRefreshesFinal(
+    ws,
+    refundResp.transactionId,
+  );
 
   logger.trace("integration test: making payment after refund");
 
-  await makePayment(
+  const makePaymentRes2 = await makePayment(
     ws,
     myMerchant,
     Amounts.stringify(spendAmountThree),
     "payment after refund",
   );
 
-  logger.trace("integration test: make payment done");
+  await waitUntilTransactionWithAssociatedRefreshesFinal(
+    ws,
+    makePaymentRes2.paymentTransactionId,
+  );
 
-  await waitUntilTransactionsFinal(ws);
+  logger.trace("integration test: make payment done");
 
   const peerPushInit = await initiatePeerPushDebit(ws, {
     partialContractTerms: {
@@ -680,12 +813,6 @@ export async function runIntegrationTest2(
   });
 
   await waitUntilTransactionPendingReady(ws, peerPushInit.transactionId);
-  const talerUri = stringifyTalerUri({
-    type: TalerUriAction.PayPush,
-    exchangeBaseUrl: peerPushInit.exchangeBaseUrl,
-    contractPriv: peerPushInit.contractPriv,
-  });
-
   const txDetails = await getTransactionById(ws, {
     transactionId: peerPushInit.transactionId,
   });
@@ -729,7 +856,25 @@ export async function runIntegrationTest2(
     peerPullDebitId: peerPullInc.peerPullDebitId,
   });
 
-  await waitUntilTransactionsFinal(ws);
+  await waitUntilTransactionWithAssociatedRefreshesFinal(
+    ws,
+    peerPullInc.transactionId,
+  );
+
+  await waitUntilTransactionWithAssociatedRefreshesFinal(
+    ws,
+    peerPullInit.transactionId,
+  );
+
+  await waitUntilTransactionWithAssociatedRefreshesFinal(
+    ws,
+    peerPushCredit.transactionId,
+  );
+
+  await waitUntilTransactionWithAssociatedRefreshesFinal(
+    ws,
+    peerPushInit.transactionId,
+  );
 
   logger.trace("integration test: all done!");
 }
@@ -764,7 +909,7 @@ export async function testPay(
   }
   const r = await confirmPay(
     ws,
-    result.proposalId,
+    result.transactionId,
     undefined,
     args.forcedCoinSel,
   );
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts 
b/packages/taler-wallet-core/src/operations/transactions.ts
index 89f756ae9..8fd7afae6 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -192,6 +192,7 @@ const txOrder: { [t in TransactionType]: number } = {
   [TransactionType.Refund]: 8,
   [TransactionType.Deposit]: 9,
   [TransactionType.Refresh]: 10,
+  [TransactionType.Recoup]: 11,
   [TransactionType.InternalWithdrawal]: 12,
 };
 
@@ -248,6 +249,9 @@ export async function getTransactionById(
         });
     }
 
+    case TransactionType.Recoup:
+      throw new Error("not yet supported");
+
     case TransactionType.Payment: {
       const proposalId = parsedTx.proposalId;
       return await ws.db
@@ -791,8 +795,7 @@ function buildTransactionForRefresh(
     ),
     refreshInputAmount: Amounts.stringify(inputAmount),
     refreshOutputAmount: Amounts.stringify(outputAmount),
-    originatingTransactionId:
-      refreshGroupRecord.reasonDetails?.originatingTransactionId,
+    originatingTransactionId: refreshGroupRecord.originatingTransactionId,
     timestamp: timestampPreciseFromDb(refreshGroupRecord.timestampCreated),
     transactionId: constructTransactionIdentifier({
       tag: TransactionType.Refresh,
@@ -1391,7 +1394,8 @@ export type ParsedTransactionIdentifier =
   | { tag: TransactionType.Refund; refundGroupId: string }
   | { tag: TransactionType.Reward; walletRewardId: string }
   | { tag: TransactionType.Withdrawal; withdrawalGroupId: string }
-  | { tag: TransactionType.InternalWithdrawal; withdrawalGroupId: string };
+  | { tag: TransactionType.InternalWithdrawal; withdrawalGroupId: string }
+  | { tag: TransactionType.Recoup; recoupGroupId: string };
 
 export function constructTransactionIdentifier(
   pTxId: ParsedTransactionIdentifier,
@@ -1419,6 +1423,8 @@ export function constructTransactionIdentifier(
       return `txn:${pTxId.tag}:${pTxId.withdrawalGroupId}` as TransactionIdStr;
     case TransactionType.InternalWithdrawal:
       return `txn:${pTxId.tag}:${pTxId.withdrawalGroupId}` as TransactionIdStr;
+    case TransactionType.Recoup:
+      return `txn:${pTxId.tag}:${pTxId.recoupGroupId}` as TransactionIdStr;
     default:
       assertUnreachable(pTxId);
   }
@@ -1597,6 +1603,9 @@ export async function retryTransaction(
     case TransactionType.Refund:
       // Nothing to do for a refund transaction.
       break;
+    case TransactionType.Recoup:
+      // FIXME!
+      throw Error("not implemented");
     default:
       assertUnreachable(parsedTx);
   }
@@ -1632,6 +1641,9 @@ async function getContextForTransaction(
       return new RefundTransactionContext(ws, tx.refundGroupId);
     case TransactionType.Reward:
       return new RewardTransactionContext(ws, tx.walletRewardId);
+    case TransactionType.Recoup:
+      throw new Error("not yet supported");
+    //return new RecoupTransactionContext(ws, tx.recoupGroupId);
     default:
       assertUnreachable(tx);
   }
diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts 
b/packages/taler-wallet-core/src/wallet-api-types.ts
index cc67781ae..38b944475 100644
--- a/packages/taler-wallet-core/src/wallet-api-types.ts
+++ b/packages/taler-wallet-core/src/wallet-api-types.ts
@@ -33,6 +33,8 @@ import {
   AcceptTipResponse,
   AcceptWithdrawalResponse,
   AddExchangeRequest,
+  AddGlobalCurrencyAuditorRequest,
+  AddGlobalCurrencyExchangeRequest,
   AddKnownBankAccountsRequest,
   AmountResponse,
   ApplyDevExperimentRequest,
@@ -51,6 +53,7 @@ import {
   CreateDepositGroupRequest,
   CreateDepositGroupResponse,
   CreateStoredBackupResponse,
+  DeleteExchangeRequest,
   DeleteStoredBackupRequest,
   DeleteTransactionRequest,
   ExchangeDetailedResponse,
@@ -66,12 +69,15 @@ import {
   GetCurrencySpecificationResponse,
   GetExchangeEntryByUrlRequest,
   GetExchangeEntryByUrlResponse,
+  GetExchangeResourcesRequest,
+  GetExchangeResourcesResponse,
   GetExchangeTosRequest,
   GetExchangeTosResult,
   GetPlanForOperationRequest,
   GetPlanForOperationResponse,
   GetWithdrawalDetailsForAmountRequest,
   GetWithdrawalDetailsForUriRequest,
+  ImportDbRequest,
   InitRequest,
   InitResponse,
   InitiatePeerPullCreditRequest,
@@ -80,9 +86,12 @@ import {
   InitiatePeerPushDebitResponse,
   IntegrationTestArgs,
   KnownBankAccounts,
+  ListAssociatedRefreshesRequest,
+  ListAssociatedRefreshesResponse,
   ListExchangesForScopedCurrencyRequest,
+  ListGlobalCurrencyAuditorsResponse,
+  ListGlobalCurrencyExchangesResponse,
   ListKnownBankAccountsRequest,
-  WithdrawalDetailsForAmount,
   PrepareDepositRequest,
   PrepareDepositResponse,
   PreparePayRequest,
@@ -99,6 +108,8 @@ import {
   PrepareWithdrawExchangeResponse,
   RecoverStoredBackupRequest,
   RecoveryLoadRequest,
+  RemoveGlobalCurrencyAuditorRequest,
+  RemoveGlobalCurrencyExchangeRequest,
   RetryTransactionRequest,
   SetCoinSuspendedRequest,
   SetWalletDeviceIdRequest,
@@ -113,6 +124,7 @@ import {
   TestingWaitTransactionRequest,
   Transaction,
   TransactionByIdRequest,
+  TransactionWithdrawal,
   TransactionsRequest,
   TransactionsResponse,
   TxIdResponse,
@@ -125,21 +137,10 @@ import {
   ValidateIbanResponse,
   WalletContractData,
   WalletCoreVersion,
-  WalletCurrencyInfo,
   WithdrawTestBalanceRequest,
   WithdrawUriInfoResponse,
+  WithdrawalDetailsForAmount,
   WithdrawalTransactionByURIRequest,
-  TransactionWithdrawal,
-  GetExchangeResourcesRequest,
-  DeleteExchangeRequest,
-  GetExchangeResourcesResponse,
-  ListGlobalCurrencyExchangesResponse,
-  ListGlobalCurrencyAuditorsResponse,
-  AddGlobalCurrencyExchangeRequest,
-  AddGlobalCurrencyAuditorRequest,
-  RemoveGlobalCurrencyExchangeRequest,
-  RemoveGlobalCurrencyAuditorRequest,
-  ImportDbRequest,
 } from "@gnu-taler/taler-util";
 import {
   AddBackupProviderRequest,
@@ -255,6 +256,7 @@ export enum WalletApiOperation {
   RemoveGlobalCurrencyExchange = "removeGlobalCurrencyExchange",
   AddGlobalCurrencyAuditor = "addGlobalCurrencyAuditor",
   RemoveGlobalCurrencyAuditor = "removeGlobalCurrencyAuditor",
+  ListAssociatedRefreshes = "listAssociatedRefreshes",
 }
 
 // group: Initialization
@@ -382,6 +384,15 @@ export type GetTransactionsOp = {
   response: TransactionsResponse;
 };
 
+/**
+ * List refresh transactions associated with another transaction.
+ */
+export type ListAssociatedRefreshesOp = {
+  op: WalletApiOperation.ListAssociatedRefreshes;
+  request: ListAssociatedRefreshesRequest;
+  response: ListAssociatedRefreshesResponse;
+};
+
 /**
  * Get sample transactions.
  */
@@ -1277,6 +1288,7 @@ export type WalletOperations = {
   [WalletApiOperation.RemoveGlobalCurrencyAuditor]: 
RemoveGlobalCurrencyAuditorOp;
   [WalletApiOperation.AddGlobalCurrencyExchange]: AddGlobalCurrencyExchangeOp;
   [WalletApiOperation.RemoveGlobalCurrencyExchange]: 
RemoveGlobalCurrencyExchangeOp;
+  [WalletApiOperation.ListAssociatedRefreshes]: ListAssociatedRefreshesOp;
 };
 
 export type WalletCoreRequestType<
diff --git a/packages/taler-wallet-core/src/wallet.ts 
b/packages/taler-wallet-core/src/wallet.ts
index ea64ff1aa..005fac3c4 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -46,7 +46,6 @@ import {
   PrepareWithdrawExchangeRequest,
   PrepareWithdrawExchangeResponse,
   RecoverStoredBackupRequest,
-  ScopeType,
   StoredBackupList,
   TalerError,
   TalerErrorCode,
@@ -161,7 +160,6 @@ import {
   MerchantInfo,
   NotificationListener,
   RecoupOperations,
-  RefreshOperations,
 } from "./internal-wallet-state.js";
 import {
   getUserAttentions,
@@ -262,13 +260,14 @@ import {
   runIntegrationTest2,
   testPay,
   waitTransactionState,
+  waitUntilAllTransactionsFinal,
   waitUntilRefreshesDone,
   waitUntilTasksProcessed,
-  waitUntilTransactionsFinal,
   withdrawTestBalance,
 } from "./operations/testing.js";
 import {
   abortTransaction,
+  constructTransactionIdentifier,
   deleteTransaction,
   failTransaction,
   getTransactionById,
@@ -735,9 +734,9 @@ async function dumpCoins(ws: InternalWalletState): 
Promise<CoinDumpJson> {
           ageCommitmentProof: c.ageCommitmentProof,
           spend_allocation: c.spendAllocation
             ? {
-              amount: c.spendAllocation.amount,
-              id: c.spendAllocation.id,
-            }
+                amount: c.spendAllocation.amount,
+                id: c.spendAllocation.id,
+              }
             : undefined,
         });
       }
@@ -1125,20 +1124,19 @@ async function dispatchRequestInternal<Op extends 
WalletApiOperation>(
     }
     case WalletApiOperation.ConfirmPay: {
       const req = codecForConfirmPayRequest().decode(payload);
-      let proposalId;
+      let transactionId;
       if (req.proposalId) {
         // legacy client support
-        proposalId = req.proposalId;
+        transactionId = constructTransactionIdentifier({
+          tag: TransactionType.Payment,
+          proposalId: req.proposalId,
+        });
       } else if (req.transactionId) {
-        const txIdParsed = parseTransactionIdentifier(req.transactionId);
-        if (txIdParsed?.tag != TransactionType.Payment) {
-          throw Error("payment transaction ID required");
-        }
-        proposalId = txIdParsed.proposalId;
+        transactionId = req.transactionId;
       } else {
         throw Error("transactionId or (deprecated) proposalId required");
       }
-      return await confirmPay(ws, proposalId, req.sessionId);
+      return await confirmPay(ws, transactionId, req.sessionId);
     }
     case WalletApiOperation.AbortTransaction: {
       const req = codecForAbortTransaction().decode(payload);
@@ -1491,7 +1489,7 @@ async function dispatchRequestInternal<Op extends 
WalletApiOperation>(
       return getVersion(ws);
     }
     case WalletApiOperation.TestingWaitTransactionsFinal:
-      return await waitUntilTransactionsFinal(ws);
+      return await waitUntilAllTransactionsFinal(ws);
     case WalletApiOperation.TestingWaitRefreshesFinal:
       return await waitUntilRefreshesDone(ws);
     case WalletApiOperation.TestingSetTimetravel: {
@@ -1727,10 +1725,6 @@ class InternalWalletStateImpl implements 
InternalWalletState {
     createRecoupGroup,
   };
 
-  refreshOps: RefreshOperations = {
-    createRefreshGroup,
-  };
-
   // FIXME: Use an LRU cache here.
   private denomCache: Record<string, DenominationInfo> = {};
 
@@ -1864,6 +1858,8 @@ class InternalWalletStateImpl implements 
InternalWalletState {
         }
         return computeRewardTransactionStatus(rec);
       }
+      case TransactionType.Recoup:
+        throw Error("not yet supported");
       default:
         assertUnreachable(parsedTxId);
     }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]