wallet-core: use testingWaitTransactionsFinal to wait for transactions
This commit is contained in:
parent
f93ab03a1b
commit
5695ae0a9f
@ -41,17 +41,21 @@ import {
|
|||||||
Logger,
|
Logger,
|
||||||
MerchantReserveCreateConfirmation,
|
MerchantReserveCreateConfirmation,
|
||||||
MerchantTemplateAddDetails,
|
MerchantTemplateAddDetails,
|
||||||
|
NotificationType,
|
||||||
parsePaytoUri,
|
parsePaytoUri,
|
||||||
stringToBytes,
|
stringToBytes,
|
||||||
TalerError,
|
TalerError,
|
||||||
TalerProtocolDuration,
|
TalerProtocolDuration,
|
||||||
|
TransactionMajorState,
|
||||||
WalletNotification,
|
WalletNotification,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import {
|
import {
|
||||||
BankApi,
|
BankApi,
|
||||||
BankServiceHandle,
|
BankServiceHandle,
|
||||||
HarnessExchangeBankAccount,
|
HarnessExchangeBankAccount,
|
||||||
|
OpenedPromise,
|
||||||
openPromise,
|
openPromise,
|
||||||
|
WalletApiOperation,
|
||||||
WalletCoreApiClient,
|
WalletCoreApiClient,
|
||||||
WalletCoreRequestType,
|
WalletCoreRequestType,
|
||||||
WalletCoreResponseType,
|
WalletCoreResponseType,
|
||||||
@ -934,7 +938,12 @@ export class FakebankService
|
|||||||
);
|
);
|
||||||
await this.pingUntilAvailable();
|
await this.pingUntilAvailable();
|
||||||
for (const acc of this.accounts) {
|
for (const acc of this.accounts) {
|
||||||
await BankApi.registerAccount(this, acc.accountName, acc.accountPassword, {});
|
await BankApi.registerAccount(
|
||||||
|
this,
|
||||||
|
acc.accountName,
|
||||||
|
acc.accountPassword,
|
||||||
|
{},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2246,9 +2255,26 @@ export interface WalletClientArgs {
|
|||||||
onNotification?(n: WalletNotification): void;
|
onNotification?(n: WalletNotification): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CancelFn = () => void;
|
||||||
|
export type NotificationHandler = (n: WalletNotification) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience wrapper around a (remote) wallet handle.
|
||||||
|
*/
|
||||||
export class WalletClient {
|
export class WalletClient {
|
||||||
remoteWallet: RemoteWallet | undefined = undefined;
|
remoteWallet: RemoteWallet | undefined = undefined;
|
||||||
private waiter: WalletNotificationWaiter = makeNotificationWaiter();
|
private waiter: WalletNotificationWaiter = makeNotificationWaiter();
|
||||||
|
notificationHandlers: NotificationHandler[] = [];
|
||||||
|
|
||||||
|
addNotificationListener(f: NotificationHandler): CancelFn {
|
||||||
|
this.notificationHandlers.push(f);
|
||||||
|
return () => {
|
||||||
|
const idx = this.notificationHandlers.indexOf(f);
|
||||||
|
if (idx >= 0) {
|
||||||
|
this.notificationHandlers.splice(idx, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async call<Op extends keyof WalletOperations>(
|
async call<Op extends keyof WalletOperations>(
|
||||||
operation: Op,
|
operation: Op,
|
||||||
@ -2260,6 +2286,7 @@ export class WalletClient {
|
|||||||
const client = getClientFromRemoteWallet(this.remoteWallet);
|
const client = getClientFromRemoteWallet(this.remoteWallet);
|
||||||
return client.call(operation, payload);
|
return client.call(operation, payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(private args: WalletClientArgs) {}
|
constructor(private args: WalletClientArgs) {}
|
||||||
|
|
||||||
async connect(): Promise<void> {
|
async connect(): Promise<void> {
|
||||||
@ -2272,6 +2299,9 @@ export class WalletClient {
|
|||||||
walletClient.args.onNotification(n);
|
walletClient.args.onNotification(n);
|
||||||
}
|
}
|
||||||
waiter.notify(n);
|
waiter.notify(n);
|
||||||
|
for (const h of walletClient.notificationHandlers) {
|
||||||
|
h(n);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
this.remoteWallet = w;
|
this.remoteWallet = w;
|
||||||
|
@ -689,3 +689,73 @@ export async function makeTestPayment(
|
|||||||
|
|
||||||
t.assertTrue(orderStatus.order_status === "paid");
|
t.assertTrue(orderStatus.order_status === "paid");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a simple payment and check that it succeeded.
|
||||||
|
*/
|
||||||
|
export async function makeTestPaymentV2(
|
||||||
|
t: GlobalTestState,
|
||||||
|
args: {
|
||||||
|
merchant: MerchantServiceInterface;
|
||||||
|
walletClient: WalletClient;
|
||||||
|
order: Partial<MerchantContractTerms>;
|
||||||
|
instance?: string;
|
||||||
|
},
|
||||||
|
auth: WithAuthorization = {},
|
||||||
|
): Promise<void> {
|
||||||
|
// Set up order.
|
||||||
|
|
||||||
|
const { walletClient, merchant } = args;
|
||||||
|
const instance = args.instance ?? "default";
|
||||||
|
|
||||||
|
const orderResp = await MerchantPrivateApi.createOrder(
|
||||||
|
merchant,
|
||||||
|
instance,
|
||||||
|
{
|
||||||
|
order: args.order,
|
||||||
|
},
|
||||||
|
auth,
|
||||||
|
);
|
||||||
|
|
||||||
|
let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(
|
||||||
|
merchant,
|
||||||
|
{
|
||||||
|
orderId: orderResp.order_id,
|
||||||
|
},
|
||||||
|
auth,
|
||||||
|
);
|
||||||
|
|
||||||
|
t.assertTrue(orderStatus.order_status === "unpaid");
|
||||||
|
|
||||||
|
// Make wallet pay for the order
|
||||||
|
|
||||||
|
const preparePayResult = await walletClient.call(
|
||||||
|
WalletApiOperation.PreparePayForUri,
|
||||||
|
{
|
||||||
|
talerPayUri: orderStatus.taler_pay_uri,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
t.assertTrue(
|
||||||
|
preparePayResult.status === PreparePayResultType.PaymentPossible,
|
||||||
|
);
|
||||||
|
|
||||||
|
const r2 = await walletClient.call(WalletApiOperation.ConfirmPay, {
|
||||||
|
proposalId: preparePayResult.proposalId,
|
||||||
|
});
|
||||||
|
|
||||||
|
t.assertTrue(r2.type === ConfirmPayResultType.Done);
|
||||||
|
|
||||||
|
// Check if payment was successful.
|
||||||
|
|
||||||
|
orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(
|
||||||
|
merchant,
|
||||||
|
{
|
||||||
|
orderId: orderResp.order_id,
|
||||||
|
instance,
|
||||||
|
},
|
||||||
|
auth,
|
||||||
|
);
|
||||||
|
|
||||||
|
t.assertTrue(orderStatus.order_status === "paid");
|
||||||
|
}
|
||||||
|
@ -20,9 +20,9 @@
|
|||||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { GlobalTestState } from "../harness/harness.js";
|
import { GlobalTestState } from "../harness/harness.js";
|
||||||
import {
|
import {
|
||||||
createSimpleTestkudosEnvironment,
|
createSimpleTestkudosEnvironmentV2,
|
||||||
withdrawViaBank,
|
withdrawViaBankV2,
|
||||||
makeTestPayment,
|
makeTestPaymentV2,
|
||||||
} from "../harness/helpers.js";
|
} from "../harness/helpers.js";
|
||||||
import { j2s } from "@gnu-taler/taler-util";
|
import { j2s } from "@gnu-taler/taler-util";
|
||||||
|
|
||||||
@ -32,12 +32,14 @@ import { j2s } from "@gnu-taler/taler-util";
|
|||||||
export async function runPaymentTest(t: GlobalTestState) {
|
export async function runPaymentTest(t: GlobalTestState) {
|
||||||
// Set up test environment
|
// Set up test environment
|
||||||
|
|
||||||
const { wallet, bank, exchange, merchant } =
|
const { walletClient, bank, exchange, merchant } =
|
||||||
await createSimpleTestkudosEnvironment(t);
|
await createSimpleTestkudosEnvironmentV2(t);
|
||||||
|
|
||||||
// Withdraw digital cash into the wallet.
|
// Withdraw digital cash into the wallet.
|
||||||
|
|
||||||
await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
|
await withdrawViaBankV2(t, { walletClient, bank, exchange, amount: "TESTKUDOS:20" });
|
||||||
|
|
||||||
|
await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {});
|
||||||
|
|
||||||
const order = {
|
const order = {
|
||||||
summary: "Buy me!",
|
summary: "Buy me!",
|
||||||
@ -45,8 +47,8 @@ export async function runPaymentTest(t: GlobalTestState) {
|
|||||||
fulfillment_url: "taler://fulfillment-success/thx",
|
fulfillment_url: "taler://fulfillment-success/thx",
|
||||||
};
|
};
|
||||||
|
|
||||||
await makeTestPayment(t, { wallet, merchant, order });
|
await makeTestPaymentV2(t, { walletClient, merchant, order });
|
||||||
await wallet.runUntilDone();
|
await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {});
|
||||||
|
|
||||||
// Test JSON normalization of contract terms: Does the wallet
|
// Test JSON normalization of contract terms: Does the wallet
|
||||||
// agree with the merchant?
|
// agree with the merchant?
|
||||||
@ -56,8 +58,8 @@ export async function runPaymentTest(t: GlobalTestState) {
|
|||||||
fulfillment_url: "taler://fulfillment-success/thx",
|
fulfillment_url: "taler://fulfillment-success/thx",
|
||||||
};
|
};
|
||||||
|
|
||||||
await makeTestPayment(t, { wallet, merchant, order: order2 });
|
await makeTestPaymentV2(t, { walletClient, merchant, order: order2 });
|
||||||
await wallet.runUntilDone();
|
await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {});
|
||||||
|
|
||||||
// Test JSON normalization of contract terms: Does the wallet
|
// Test JSON normalization of contract terms: Does the wallet
|
||||||
// agree with the merchant?
|
// agree with the merchant?
|
||||||
@ -67,11 +69,10 @@ export async function runPaymentTest(t: GlobalTestState) {
|
|||||||
fulfillment_url: "taler://fulfillment-success/thx",
|
fulfillment_url: "taler://fulfillment-success/thx",
|
||||||
};
|
};
|
||||||
|
|
||||||
await makeTestPayment(t, { wallet, merchant, order: order3 });
|
await makeTestPaymentV2(t, { walletClient, merchant, order: order3 });
|
||||||
|
await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {});
|
||||||
|
|
||||||
await wallet.runUntilDone();
|
const bal = await walletClient.call(WalletApiOperation.GetBalances, {});
|
||||||
|
|
||||||
const bal = await wallet.client.call(WalletApiOperation.GetBalances, {});
|
|
||||||
console.log(`balance after 3 payments: ${j2s(bal)}`);
|
console.log(`balance after 3 payments: ${j2s(bal)}`);
|
||||||
t.assertAmountEquals(bal.balances[0].available, "TESTKUDOS:3.8");
|
t.assertAmountEquals(bal.balances[0].available, "TESTKUDOS:3.8");
|
||||||
t.assertAmountEquals(bal.balances[0].pendingIncoming, "TESTKUDOS:0");
|
t.assertAmountEquals(bal.balances[0].pendingIncoming, "TESTKUDOS:0");
|
||||||
|
@ -263,22 +263,25 @@ async function refreshCreateSession(
|
|||||||
availableAmount,
|
availableAmount,
|
||||||
)} too small`,
|
)} too small`,
|
||||||
);
|
);
|
||||||
// FIXME: State transition notification missing.
|
const transitionInfo = await ws.db
|
||||||
await ws.db
|
|
||||||
.mktx((x) => [x.coins, x.coinAvailability, x.refreshGroups])
|
.mktx((x) => [x.coins, x.coinAvailability, x.refreshGroups])
|
||||||
.runReadWrite(async (tx) => {
|
.runReadWrite(async (tx) => {
|
||||||
const rg = await tx.refreshGroups.get(refreshGroupId);
|
const rg = await tx.refreshGroups.get(refreshGroupId);
|
||||||
if (!rg) {
|
if (!rg) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const oldTxState = computeRefreshTransactionState(rg);
|
||||||
rg.statusPerCoin[coinIndex] = RefreshCoinStatus.Finished;
|
rg.statusPerCoin[coinIndex] = RefreshCoinStatus.Finished;
|
||||||
const updateRes = updateGroupStatus(rg);
|
const updateRes = updateGroupStatus(rg);
|
||||||
if (updateRes.final) {
|
if (updateRes.final) {
|
||||||
await makeCoinsVisible(ws, tx, transactionId);
|
await makeCoinsVisible(ws, tx, transactionId);
|
||||||
}
|
}
|
||||||
await tx.refreshGroups.put(rg);
|
await tx.refreshGroups.put(rg);
|
||||||
|
const newTxState = computeRefreshTransactionState(rg);
|
||||||
|
return { oldTxState, newTxState };
|
||||||
});
|
});
|
||||||
ws.notify({ type: NotificationType.BalanceChange });
|
ws.notify({ type: NotificationType.BalanceChange });
|
||||||
|
notifyTransition(ws, transactionId, transitionInfo);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,7 +441,7 @@ async function refreshMelt(
|
|||||||
|
|
||||||
if (resp.status === HttpStatusCode.NotFound) {
|
if (resp.status === HttpStatusCode.NotFound) {
|
||||||
const errDetails = await readUnexpectedResponseDetails(resp);
|
const errDetails = await readUnexpectedResponseDetails(resp);
|
||||||
await ws.db
|
const transitionInfo = await ws.db
|
||||||
.mktx((x) => [x.refreshGroups, x.coins, x.coinAvailability])
|
.mktx((x) => [x.refreshGroups, x.coins, x.coinAvailability])
|
||||||
.runReadWrite(async (tx) => {
|
.runReadWrite(async (tx) => {
|
||||||
const rg = await tx.refreshGroups.get(refreshGroupId);
|
const rg = await tx.refreshGroups.get(refreshGroupId);
|
||||||
@ -451,6 +454,7 @@ async function refreshMelt(
|
|||||||
if (rg.statusPerCoin[coinIndex] !== RefreshCoinStatus.Pending) {
|
if (rg.statusPerCoin[coinIndex] !== RefreshCoinStatus.Pending) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const oldTxState = computeRefreshTransactionState(rg);
|
||||||
rg.statusPerCoin[coinIndex] = RefreshCoinStatus.Failed;
|
rg.statusPerCoin[coinIndex] = RefreshCoinStatus.Failed;
|
||||||
rg.lastErrorPerCoin[coinIndex] = errDetails;
|
rg.lastErrorPerCoin[coinIndex] = errDetails;
|
||||||
const updateRes = updateGroupStatus(rg);
|
const updateRes = updateGroupStatus(rg);
|
||||||
@ -458,8 +462,14 @@ async function refreshMelt(
|
|||||||
await makeCoinsVisible(ws, tx, transactionId);
|
await makeCoinsVisible(ws, tx, transactionId);
|
||||||
}
|
}
|
||||||
await tx.refreshGroups.put(rg);
|
await tx.refreshGroups.put(rg);
|
||||||
|
const newTxState = computeRefreshTransactionState(rg);
|
||||||
|
return {
|
||||||
|
oldTxState,
|
||||||
|
newTxState,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
ws.notify({ type: NotificationType.BalanceChange });
|
ws.notify({ type: NotificationType.BalanceChange });
|
||||||
|
notifyTransition(ws, transactionId, transitionInfo);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -739,7 +749,7 @@ async function refreshReveal(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await ws.db
|
const transitionInfo = await ws.db
|
||||||
.mktx((x) => [
|
.mktx((x) => [
|
||||||
x.coins,
|
x.coins,
|
||||||
x.denominations,
|
x.denominations,
|
||||||
@ -756,6 +766,7 @@ async function refreshReveal(
|
|||||||
if (!rs) {
|
if (!rs) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const oldTxState = computeRefreshTransactionState(rg);
|
||||||
rg.statusPerCoin[coinIndex] = RefreshCoinStatus.Finished;
|
rg.statusPerCoin[coinIndex] = RefreshCoinStatus.Finished;
|
||||||
updateGroupStatus(rg);
|
updateGroupStatus(rg);
|
||||||
for (const coin of coins) {
|
for (const coin of coins) {
|
||||||
@ -763,7 +774,10 @@ async function refreshReveal(
|
|||||||
}
|
}
|
||||||
await makeCoinsVisible(ws, tx, transactionId);
|
await makeCoinsVisible(ws, tx, transactionId);
|
||||||
await tx.refreshGroups.put(rg);
|
await tx.refreshGroups.put(rg);
|
||||||
|
const newTxState = computeRefreshTransactionState(rg);
|
||||||
|
return { oldTxState, newTxState };
|
||||||
});
|
});
|
||||||
|
notifyTransition(ws, transactionId, transitionInfo);
|
||||||
logger.trace("refresh finished (end of reveal)");
|
logger.trace("refresh finished (end of reveal)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -778,7 +792,7 @@ export async function processRefreshGroup(
|
|||||||
.mktx((x) => [x.refreshGroups])
|
.mktx((x) => [x.refreshGroups])
|
||||||
.runReadOnly(async (tx) => tx.refreshGroups.get(refreshGroupId));
|
.runReadOnly(async (tx) => tx.refreshGroups.get(refreshGroupId));
|
||||||
if (!refreshGroup) {
|
if (!refreshGroup) {
|
||||||
return TaskRunResult.finished()
|
return TaskRunResult.finished();
|
||||||
}
|
}
|
||||||
if (refreshGroup.timestampFinished) {
|
if (refreshGroup.timestampFinished) {
|
||||||
return TaskRunResult.finished();
|
return TaskRunResult.finished();
|
||||||
@ -1235,10 +1249,6 @@ export async function suspendRefreshGroup(
|
|||||||
tag: TransactionType.Refresh,
|
tag: TransactionType.Refresh,
|
||||||
refreshGroupId,
|
refreshGroupId,
|
||||||
});
|
});
|
||||||
const retryTag = constructTaskIdentifier({
|
|
||||||
tag: PendingTaskType.Refresh,
|
|
||||||
refreshGroupId,
|
|
||||||
});
|
|
||||||
let res = await ws.db
|
let res = await ws.db
|
||||||
.mktx((x) => [x.refreshGroups])
|
.mktx((x) => [x.refreshGroups])
|
||||||
.runReadWrite(async (tx) => {
|
.runReadWrite(async (tx) => {
|
||||||
|
@ -450,7 +450,7 @@ export async function runIntegrationTest(
|
|||||||
logger.trace("integration test: all done!");
|
logger.trace("integration test: all done!");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function waitUntilDone(ws: InternalWalletState): Promise<void> {
|
export async function waitUntilDone(ws: InternalWalletState): Promise<void> {
|
||||||
logger.info("waiting until all transactions are in a final state");
|
logger.info("waiting until all transactions are in a final state");
|
||||||
ws.ensureTaskLoopRunning();
|
ws.ensureTaskLoopRunning();
|
||||||
let p: OpenedPromise<void> | undefined = undefined;
|
let p: OpenedPromise<void> | undefined = undefined;
|
||||||
@ -459,11 +459,13 @@ async function waitUntilDone(ws: InternalWalletState): Promise<void> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (notif.type === NotificationType.TransactionStateTransition) {
|
if (notif.type === NotificationType.TransactionStateTransition) {
|
||||||
p.resolve();
|
switch (notif.newTxState.major) {
|
||||||
}
|
case TransactionMajorState.Pending:
|
||||||
// Work-around, refresh transactions don't properly emit transition notifications yet.
|
case TransactionMajorState.Aborting:
|
||||||
if (notif.type === NotificationType.PendingOperationProcessed) {
|
break;
|
||||||
p.resolve();
|
default:
|
||||||
|
p.resolve();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -206,6 +206,7 @@ export enum WalletApiOperation {
|
|||||||
Recycle = "recycle",
|
Recycle = "recycle",
|
||||||
ApplyDevExperiment = "applyDevExperiment",
|
ApplyDevExperiment = "applyDevExperiment",
|
||||||
ValidateIban = "validateIban",
|
ValidateIban = "validateIban",
|
||||||
|
TestingWaitTransactionsFinal = "testingWaitTransactionsFinal",
|
||||||
}
|
}
|
||||||
|
|
||||||
// group: Initialization
|
// group: Initialization
|
||||||
@ -949,6 +950,15 @@ export type DumpCoinsOp = {
|
|||||||
response: CoinDumpJson;
|
response: CoinDumpJson;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait until all transactions are in a final state.
|
||||||
|
*/
|
||||||
|
export type TestingWaitTransactionsFinal = {
|
||||||
|
op: WalletApiOperation.TestingWaitTransactionsFinal;
|
||||||
|
request: EmptyObject;
|
||||||
|
response: EmptyObject;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a coin as (un-)suspended.
|
* Set a coin as (un-)suspended.
|
||||||
* Suspended coins won't be used for payments.
|
* Suspended coins won't be used for payments.
|
||||||
@ -1051,6 +1061,7 @@ export type WalletOperations = {
|
|||||||
[WalletApiOperation.Recycle]: RecycleOp;
|
[WalletApiOperation.Recycle]: RecycleOp;
|
||||||
[WalletApiOperation.ApplyDevExperiment]: ApplyDevExperimentOp;
|
[WalletApiOperation.ApplyDevExperiment]: ApplyDevExperimentOp;
|
||||||
[WalletApiOperation.ValidateIban]: ValidateIbanOp;
|
[WalletApiOperation.ValidateIban]: ValidateIbanOp;
|
||||||
|
[WalletApiOperation.TestingWaitTransactionsFinal]: TestingWaitTransactionsFinal;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type WalletCoreRequestType<
|
export type WalletCoreRequestType<
|
||||||
|
@ -242,6 +242,7 @@ import {
|
|||||||
runIntegrationTest,
|
runIntegrationTest,
|
||||||
runIntegrationTest2,
|
runIntegrationTest2,
|
||||||
testPay,
|
testPay,
|
||||||
|
waitUntilDone,
|
||||||
withdrawTestBalance,
|
withdrawTestBalance,
|
||||||
} from "./operations/testing.js";
|
} from "./operations/testing.js";
|
||||||
import {
|
import {
|
||||||
@ -1550,6 +1551,8 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
|
|||||||
case WalletApiOperation.GetVersion: {
|
case WalletApiOperation.GetVersion: {
|
||||||
return getVersion(ws);
|
return getVersion(ws);
|
||||||
}
|
}
|
||||||
|
case WalletApiOperation.TestingWaitTransactionsFinal:
|
||||||
|
return await waitUntilDone(ws);
|
||||||
// default:
|
// default:
|
||||||
// assertUnreachable(operation);
|
// assertUnreachable(operation);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user