separate wallet state from wallet client
This commit is contained in:
parent
4b16d7bd34
commit
d41ae5eb97
@ -622,11 +622,13 @@ export const codecForIntegrationTestArgs = (): Codec<IntegrationTestArgs> =>
|
||||
|
||||
export interface AddExchangeRequest {
|
||||
exchangeBaseUrl: string;
|
||||
forceUpdate?: boolean;
|
||||
}
|
||||
|
||||
export const codecForAddExchangeRequest = (): Codec<AddExchangeRequest> =>
|
||||
buildCodecForObject<AddExchangeRequest>()
|
||||
.property("exchangeBaseUrl", codecForString())
|
||||
.property("forceUpdate", codecOptional(codecForBoolean()))
|
||||
.build("AddExchangeRequest");
|
||||
|
||||
export interface ForceExchangeUpdateRequest {
|
||||
@ -962,3 +964,15 @@ export const codecForRetryTransactionRequest = (): Codec<RetryTransactionRequest
|
||||
buildCodecForObject<RetryTransactionRequest>()
|
||||
.property("transactionId", codecForString())
|
||||
.build("RetryTransactionRequest");
|
||||
|
||||
export interface SetWalletDeviceIdRequest {
|
||||
/**
|
||||
* New wallet device ID to set.
|
||||
*/
|
||||
walletDeviceId: string;
|
||||
}
|
||||
|
||||
export const codecForSetWalletDeviceIdRequest = (): Codec<SetWalletDeviceIdRequest> =>
|
||||
buildCodecForObject<SetWalletDeviceIdRequest>()
|
||||
.property("walletDeviceId", codecForString())
|
||||
.build("SetWalletDeviceIdRequest");
|
||||
|
@ -18,7 +18,6 @@
|
||||
* Imports.
|
||||
*/
|
||||
import {
|
||||
Wallet,
|
||||
getDefaultNodeWallet,
|
||||
DefaultNodeWalletArgs,
|
||||
NodeHttpLib,
|
||||
@ -33,7 +32,10 @@ import {
|
||||
Headers,
|
||||
WALLET_EXCHANGE_PROTOCOL_VERSION,
|
||||
WALLET_MERCHANT_PROTOCOL_VERSION,
|
||||
runRetryLoop,
|
||||
handleCoreApiRequest,
|
||||
} from "@gnu-taler/taler-wallet-core";
|
||||
import { InternalWalletState } from "@gnu-taler/taler-wallet-core/lib/operations/state";
|
||||
|
||||
import fs from "fs";
|
||||
import { WalletNotification } from "../../taler-wallet-core/node_modules/@gnu-taler/taler-util/lib/notifications.js";
|
||||
@ -154,8 +156,8 @@ function sendAkonoMessage(ev: CoreApiEnvelope): void {
|
||||
|
||||
class AndroidWalletMessageHandler {
|
||||
walletArgs: DefaultNodeWalletArgs | undefined;
|
||||
maybeWallet: Wallet | undefined;
|
||||
wp = openPromise<Wallet>();
|
||||
maybeWallet: InternalWalletState | undefined;
|
||||
wp = openPromise<InternalWalletState>();
|
||||
httpLib = new NodeHttpLib();
|
||||
|
||||
/**
|
||||
@ -174,6 +176,17 @@ class AndroidWalletMessageHandler {
|
||||
result,
|
||||
};
|
||||
};
|
||||
|
||||
const reinit = async () => {
|
||||
const w = await getDefaultNodeWallet(this.walletArgs);
|
||||
this.maybeWallet = w;
|
||||
await handleCoreApiRequest(w, "initWallet", "akono-init", {});
|
||||
runRetryLoop(w).catch((e) => {
|
||||
console.error("Error during wallet retry loop", e);
|
||||
});
|
||||
this.wp.resolve(w);
|
||||
};
|
||||
|
||||
switch (operation) {
|
||||
case "init": {
|
||||
this.walletArgs = {
|
||||
@ -183,12 +196,7 @@ class AndroidWalletMessageHandler {
|
||||
persistentStoragePath: args.persistentStoragePath,
|
||||
httpLib: this.httpLib,
|
||||
};
|
||||
const w = await getDefaultNodeWallet(this.walletArgs);
|
||||
this.maybeWallet = w;
|
||||
w.runRetryLoop().catch((e) => {
|
||||
console.error("Error during wallet retry loop", e);
|
||||
});
|
||||
this.wp.resolve(w);
|
||||
await reinit();
|
||||
return wrapResponse({
|
||||
supported_protocol_versions: {
|
||||
exchange: WALLET_EXCHANGE_PROTOCOL_VERSION,
|
||||
@ -196,9 +204,6 @@ class AndroidWalletMessageHandler {
|
||||
},
|
||||
});
|
||||
}
|
||||
case "getHistory": {
|
||||
return wrapResponse({ history: [] });
|
||||
}
|
||||
case "startTunnel": {
|
||||
// this.httpLib.useNfcTunnel = true;
|
||||
throw Error("not implemented");
|
||||
@ -225,19 +230,14 @@ class AndroidWalletMessageHandler {
|
||||
}
|
||||
const wallet = await this.wp.promise;
|
||||
wallet.stop();
|
||||
this.wp = openPromise<Wallet>();
|
||||
this.wp = openPromise<InternalWalletState>();
|
||||
this.maybeWallet = undefined;
|
||||
const w = await getDefaultNodeWallet(this.walletArgs);
|
||||
this.maybeWallet = w;
|
||||
w.runRetryLoop().catch((e) => {
|
||||
console.error("Error during wallet retry loop", e);
|
||||
});
|
||||
this.wp.resolve(w);
|
||||
await reinit();
|
||||
return wrapResponse({});
|
||||
}
|
||||
default: {
|
||||
const wallet = await this.wp.promise;
|
||||
return await wallet.handleCoreApiRequest(operation, id, args);
|
||||
return await handleCoreApiRequest(wallet, operation, id, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,9 +33,9 @@ import {
|
||||
codecForList,
|
||||
codecForString,
|
||||
Logger,
|
||||
WithdrawalType,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import {
|
||||
Wallet,
|
||||
NodeHttpLib,
|
||||
getDefaultNodeWallet,
|
||||
OperationFailedAndReportedError,
|
||||
@ -45,7 +45,14 @@ import {
|
||||
NodeThreadCryptoWorkerFactory,
|
||||
CryptoApi,
|
||||
walletCoreDebugFlags,
|
||||
WalletCoreApiClient,
|
||||
WalletApiOperation,
|
||||
handleCoreApiRequest,
|
||||
runPending,
|
||||
runUntilDone,
|
||||
getClientFromWalletState,
|
||||
} from "@gnu-taler/taler-wallet-core";
|
||||
import { InternalWalletState } from "@gnu-taler/taler-wallet-core/src/operations/state";
|
||||
|
||||
// This module also serves as the entry point for the crypto
|
||||
// thread worker, and thus must expose these two handlers.
|
||||
@ -63,11 +70,13 @@ function assertUnreachable(x: never): never {
|
||||
}
|
||||
|
||||
async function doPay(
|
||||
wallet: Wallet,
|
||||
wallet: WalletCoreApiClient,
|
||||
payUrl: string,
|
||||
options: { alwaysYes: boolean } = { alwaysYes: true },
|
||||
): Promise<void> {
|
||||
const result = await wallet.preparePayForUri(payUrl);
|
||||
const result = await wallet.call(WalletApiOperation.PreparePayForUri, {
|
||||
talerPayUri: payUrl,
|
||||
});
|
||||
if (result.status === PreparePayResultType.InsufficientBalance) {
|
||||
console.log("contract", result.contractTerms);
|
||||
console.error("insufficient balance");
|
||||
@ -111,7 +120,9 @@ async function doPay(
|
||||
}
|
||||
|
||||
if (pay) {
|
||||
await wallet.confirmPay(result.proposalId, undefined);
|
||||
await wallet.call(WalletApiOperation.ConfirmPay, {
|
||||
proposalId: result.proposalId,
|
||||
});
|
||||
} else {
|
||||
console.log("not paying");
|
||||
}
|
||||
@ -161,7 +172,10 @@ type WalletCliArgsType = clk.GetArgType<typeof walletCli>;
|
||||
|
||||
async function withWallet<T>(
|
||||
walletCliArgs: WalletCliArgsType,
|
||||
f: (w: Wallet) => Promise<T>,
|
||||
f: (w: {
|
||||
client: WalletCoreApiClient;
|
||||
ws: InternalWalletState;
|
||||
}) => Promise<T>,
|
||||
): Promise<T> {
|
||||
const dbPath = walletCliArgs.wallet.walletDbFile ?? defaultWalletDbPath;
|
||||
const myHttpLib = new NodeHttpLib();
|
||||
@ -174,8 +188,11 @@ async function withWallet<T>(
|
||||
});
|
||||
applyVerbose(walletCliArgs.wallet.verbose);
|
||||
try {
|
||||
await wallet.fillDefaults();
|
||||
const ret = await f(wallet);
|
||||
const w = {
|
||||
ws: wallet,
|
||||
client: await getClientFromWalletState(wallet),
|
||||
};
|
||||
const ret = await f(w);
|
||||
return ret;
|
||||
} catch (e) {
|
||||
if (
|
||||
@ -204,7 +221,10 @@ walletCli
|
||||
})
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const balance = await wallet.getBalances();
|
||||
const balance = await wallet.client.call(
|
||||
WalletApiOperation.GetBalances,
|
||||
{},
|
||||
);
|
||||
console.log(JSON.stringify(balance, undefined, 2));
|
||||
});
|
||||
});
|
||||
@ -222,7 +242,8 @@ walletCli
|
||||
console.error("Invalid JSON");
|
||||
process.exit(1);
|
||||
}
|
||||
const resp = await wallet.handleCoreApiRequest(
|
||||
const resp = await handleCoreApiRequest(
|
||||
wallet.ws,
|
||||
args.api.operation,
|
||||
"reqid-1",
|
||||
requestJson,
|
||||
@ -235,7 +256,10 @@ walletCli
|
||||
.subcommand("", "pending", { help: "Show pending operations." })
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const pending = await wallet.getPendingOperations();
|
||||
const pending = await wallet.client.call(
|
||||
WalletApiOperation.GetPendingOperations,
|
||||
{},
|
||||
);
|
||||
console.log(JSON.stringify(pending, undefined, 2));
|
||||
});
|
||||
});
|
||||
@ -246,10 +270,13 @@ walletCli
|
||||
.maybeOption("search", ["--search"], clk.STRING)
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const pending = await wallet.getTransactions({
|
||||
currency: args.transactions.currency,
|
||||
search: args.transactions.search,
|
||||
});
|
||||
const pending = await wallet.client.call(
|
||||
WalletApiOperation.GetTransactions,
|
||||
{
|
||||
currency: args.transactions.currency,
|
||||
search: args.transactions.search,
|
||||
},
|
||||
);
|
||||
console.log(JSON.stringify(pending, undefined, 2));
|
||||
});
|
||||
});
|
||||
@ -267,7 +294,20 @@ walletCli
|
||||
.flag("forceNow", ["-f", "--force-now"])
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
await wallet.runPending(args.runPendingOpt.forceNow);
|
||||
await runPending(wallet.ws, args.runPendingOpt.forceNow);
|
||||
});
|
||||
});
|
||||
|
||||
walletCli
|
||||
.subcommand("retryTransaction", "retry-transaction", {
|
||||
help: "Retry a transaction.",
|
||||
})
|
||||
.requiredArgument("transactionId", clk.STRING)
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
await wallet.client.call(WalletApiOperation.RetryTransaction, {
|
||||
transactionId: args.retryTransaction.transactionId,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -278,10 +318,10 @@ walletCli
|
||||
.maybeOption("maxRetries", ["--max-retries"], clk.INT)
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
await wallet.runUntilDone({
|
||||
await runUntilDone(wallet.ws, {
|
||||
maxRetries: args.finishPendingOpt.maxRetries,
|
||||
});
|
||||
wallet.stop();
|
||||
wallet.ws.stop();
|
||||
});
|
||||
});
|
||||
|
||||
@ -294,7 +334,7 @@ walletCli
|
||||
})
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
await wallet.deleteTransaction({
|
||||
await wallet.client.call(WalletApiOperation.DeleteTransaction, {
|
||||
transactionId: args.deleteTransaction.transactionId,
|
||||
});
|
||||
});
|
||||
@ -312,29 +352,51 @@ walletCli
|
||||
const uriType = classifyTalerUri(uri);
|
||||
switch (uriType) {
|
||||
case TalerUriType.TalerPay:
|
||||
await doPay(wallet, uri, { alwaysYes: args.handleUri.autoYes });
|
||||
await doPay(wallet.client, uri, {
|
||||
alwaysYes: args.handleUri.autoYes,
|
||||
});
|
||||
break;
|
||||
case TalerUriType.TalerTip:
|
||||
{
|
||||
const res = await wallet.prepareTip(uri);
|
||||
const res = await wallet.client.call(
|
||||
WalletApiOperation.PrepareTip,
|
||||
{
|
||||
talerTipUri: uri,
|
||||
},
|
||||
);
|
||||
console.log("tip status", res);
|
||||
await wallet.acceptTip(res.walletTipId);
|
||||
await wallet.client.call(WalletApiOperation.AcceptTip, {
|
||||
walletTipId: res.walletTipId,
|
||||
});
|
||||
}
|
||||
break;
|
||||
case TalerUriType.TalerRefund:
|
||||
await wallet.applyRefund(uri);
|
||||
await wallet.client.call(WalletApiOperation.ApplyRefund, {
|
||||
talerRefundUri: uri,
|
||||
});
|
||||
break;
|
||||
case TalerUriType.TalerWithdraw:
|
||||
{
|
||||
const withdrawInfo = await wallet.getWithdrawalDetailsForUri(uri);
|
||||
const withdrawInfo = await wallet.client.call(
|
||||
WalletApiOperation.GetWithdrawalDetailsForUri,
|
||||
{
|
||||
talerWithdrawUri: uri,
|
||||
},
|
||||
);
|
||||
console.log("withdrawInfo", withdrawInfo);
|
||||
const selectedExchange = withdrawInfo.defaultExchangeBaseUrl;
|
||||
if (!selectedExchange) {
|
||||
console.error("no suggested exchange!");
|
||||
process.exit(1);
|
||||
return;
|
||||
}
|
||||
const res = await wallet.acceptWithdrawal(uri, selectedExchange);
|
||||
await wallet.processReserve(res.reservePub);
|
||||
const res = await wallet.client.call(
|
||||
WalletApiOperation.AcceptBankIntegratedWithdrawal,
|
||||
{
|
||||
exchangeBaseUrl: selectedExchange,
|
||||
talerWithdrawUri: uri,
|
||||
},
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -356,7 +418,10 @@ exchangesCli
|
||||
.action(async (args) => {
|
||||
console.log("Listing exchanges ...");
|
||||
await withWallet(args, async (wallet) => {
|
||||
const exchanges = await wallet.getExchanges();
|
||||
const exchanges = await wallet.client.call(
|
||||
WalletApiOperation.ListExchanges,
|
||||
{},
|
||||
);
|
||||
console.log(JSON.stringify(exchanges, undefined, 2));
|
||||
});
|
||||
});
|
||||
@ -371,10 +436,10 @@ exchangesCli
|
||||
.flag("force", ["-f", "--force"])
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
await wallet.updateExchangeFromUrl(
|
||||
args.exchangesUpdateCmd.url,
|
||||
args.exchangesUpdateCmd.force,
|
||||
);
|
||||
await wallet.client.call(WalletApiOperation.AddExchange, {
|
||||
exchangeBaseUrl: args.exchangesUpdateCmd.url,
|
||||
forceUpdate: args.exchangesUpdateCmd.force,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -387,7 +452,9 @@ exchangesCli
|
||||
})
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
await wallet.updateExchangeFromUrl(args.exchangesAddCmd.url);
|
||||
await wallet.client.call(WalletApiOperation.AddExchange, {
|
||||
exchangeBaseUrl: args.exchangesAddCmd.url,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -403,10 +470,10 @@ exchangesCli
|
||||
})
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
await wallet.acceptExchangeTermsOfService(
|
||||
args.exchangesAcceptTosCmd.url,
|
||||
args.exchangesAcceptTosCmd.etag,
|
||||
);
|
||||
await wallet.client.call(WalletApiOperation.SetExchangeTosAccepted, {
|
||||
etag: args.exchangesAcceptTosCmd.etag,
|
||||
exchangeBaseUrl: args.exchangesAcceptTosCmd.url,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -419,7 +486,12 @@ exchangesCli
|
||||
})
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const tosResult = await wallet.getExchangeTos(args.exchangesTosCmd.url);
|
||||
const tosResult = await wallet.client.call(
|
||||
WalletApiOperation.GetExchangeTos,
|
||||
{
|
||||
exchangeBaseUrl: args.exchangesTosCmd.url,
|
||||
},
|
||||
);
|
||||
console.log(JSON.stringify(tosResult, undefined, 2));
|
||||
});
|
||||
});
|
||||
@ -435,65 +507,44 @@ backupCli
|
||||
})
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const backup = await wallet.setDeviceId(args.setDeviceId.deviceId);
|
||||
console.log(JSON.stringify(backup, undefined, 2));
|
||||
await wallet.client.call(WalletApiOperation.SetWalletDeviceId, {
|
||||
walletDeviceId: args.setDeviceId.deviceId,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
backupCli.subcommand("exportPlain", "export-plain").action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const backup = await wallet.exportBackupPlain();
|
||||
const backup = await wallet.client.call(
|
||||
WalletApiOperation.ExportBackupPlain,
|
||||
{},
|
||||
);
|
||||
console.log(JSON.stringify(backup, undefined, 2));
|
||||
});
|
||||
});
|
||||
|
||||
backupCli
|
||||
.subcommand("export", "export")
|
||||
.requiredArgument("filename", clk.STRING, {
|
||||
help: "backup filename",
|
||||
})
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const backup = await wallet.exportBackupEncrypted();
|
||||
fs.writeFileSync(args.export.filename, backup);
|
||||
});
|
||||
});
|
||||
|
||||
backupCli
|
||||
.subcommand("import", "import")
|
||||
.requiredArgument("filename", clk.STRING, {
|
||||
help: "backup filename",
|
||||
})
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const backupEncBlob = fs.readFileSync(args.import.filename);
|
||||
await wallet.importBackupEncrypted(backupEncBlob);
|
||||
});
|
||||
});
|
||||
|
||||
backupCli.subcommand("importPlain", "import-plain").action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const data = JSON.parse(await read(process.stdin));
|
||||
await wallet.importBackupPlain(data);
|
||||
});
|
||||
});
|
||||
|
||||
backupCli.subcommand("recoverySave", "save-recovery").action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const recoveryJson = await wallet.getBackupRecovery();
|
||||
const recoveryJson = await wallet.client.call(
|
||||
WalletApiOperation.ExportBackupRecovery,
|
||||
{},
|
||||
);
|
||||
console.log(JSON.stringify(recoveryJson, undefined, 2));
|
||||
});
|
||||
});
|
||||
|
||||
backupCli.subcommand("run", "run").action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
await wallet.runBackupCycle();
|
||||
await wallet.client.call(WalletApiOperation.RunBackupCycle, {});
|
||||
});
|
||||
});
|
||||
|
||||
backupCli.subcommand("status", "status").action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const status = await wallet.getBackupStatus();
|
||||
const status = await wallet.client.call(
|
||||
WalletApiOperation.GetBackupInfo,
|
||||
{},
|
||||
);
|
||||
console.log(JSON.stringify(status, undefined, 2));
|
||||
});
|
||||
});
|
||||
@ -518,7 +569,7 @@ backupCli
|
||||
throw Error("invalid recovery strategy");
|
||||
}
|
||||
}
|
||||
await wallet.loadBackupRecovery({
|
||||
await wallet.client.call(WalletApiOperation.ImportBackupRecovery, {
|
||||
recovery: data,
|
||||
strategy,
|
||||
});
|
||||
@ -531,7 +582,7 @@ backupCli
|
||||
.flag("activate", ["--activate"])
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
await wallet.addBackupProvider({
|
||||
await wallet.client.call(WalletApiOperation.AddBackupProvider, {
|
||||
backupProviderBaseUrl: args.addProvider.url,
|
||||
activate: args.addProvider.activate,
|
||||
});
|
||||
@ -548,12 +599,15 @@ depositCli
|
||||
.requiredArgument("targetPayto", clk.STRING)
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const resp = await wallet.createDepositGroup({
|
||||
amount: args.createDepositArgs.amount,
|
||||
depositPaytoUri: args.createDepositArgs.targetPayto,
|
||||
});
|
||||
const resp = await wallet.client.call(
|
||||
WalletApiOperation.CreateDepositGroup,
|
||||
{
|
||||
amount: args.createDepositArgs.amount,
|
||||
depositPaytoUri: args.createDepositArgs.targetPayto,
|
||||
},
|
||||
);
|
||||
console.log(`Created deposit ${resp.depositGroupId}`);
|
||||
await wallet.runPending();
|
||||
await runPending(wallet.ws);
|
||||
});
|
||||
});
|
||||
|
||||
@ -562,9 +616,12 @@ depositCli
|
||||
.requiredArgument("depositGroupId", clk.STRING)
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const resp = await wallet.trackDepositGroup({
|
||||
depositGroupId: args.trackDepositArgs.depositGroupId,
|
||||
});
|
||||
const resp = await wallet.client.call(
|
||||
WalletApiOperation.TrackDepositGroup,
|
||||
{
|
||||
depositGroupId: args.trackDepositArgs.depositGroupId,
|
||||
},
|
||||
);
|
||||
console.log(JSON.stringify(resp, undefined, 2));
|
||||
});
|
||||
});
|
||||
@ -582,9 +639,12 @@ advancedCli
|
||||
.requiredArgument("amount", clk.STRING)
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const details = await wallet.getWithdrawalDetailsForAmount(
|
||||
args.manualWithdrawalDetails.exchange,
|
||||
Amounts.parseOrThrow(args.manualWithdrawalDetails.amount),
|
||||
const details = await wallet.client.call(
|
||||
WalletApiOperation.GetWithdrawalDetailsForAmount,
|
||||
{
|
||||
amount: args.manualWithdrawalDetails.amount,
|
||||
exchangeBaseUrl: args.manualWithdrawalDetails.exchange,
|
||||
},
|
||||
);
|
||||
console.log(JSON.stringify(details, undefined, 2));
|
||||
});
|
||||
@ -611,23 +671,33 @@ advancedCli
|
||||
})
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const { exchange, exchangeDetails } = await wallet.updateExchangeFromUrl(
|
||||
args.withdrawManually.exchange,
|
||||
const exchangeBaseUrl = args.withdrawManually.exchange;
|
||||
const amount = args.withdrawManually.amount;
|
||||
const d = await wallet.client.call(
|
||||
WalletApiOperation.GetWithdrawalDetailsForAmount,
|
||||
{
|
||||
amount: args.withdrawManually.amount,
|
||||
exchangeBaseUrl: exchangeBaseUrl,
|
||||
},
|
||||
);
|
||||
const acct = exchangeDetails.wireInfo.accounts[0];
|
||||
const acct = d.paytoUris[0];
|
||||
if (!acct) {
|
||||
console.log("exchange has no accounts");
|
||||
return;
|
||||
}
|
||||
const reserve = await wallet.acceptManualWithdrawal(
|
||||
exchange.baseUrl,
|
||||
Amounts.parseOrThrow(args.withdrawManually.amount),
|
||||
const resp = await wallet.client.call(
|
||||
WalletApiOperation.AcceptManualWithdrawal,
|
||||
{
|
||||
amount,
|
||||
exchangeBaseUrl,
|
||||
},
|
||||
);
|
||||
const completePaytoUri = addPaytoQueryParams(acct.payto_uri, {
|
||||
const reservePub = resp.reservePub;
|
||||
const completePaytoUri = addPaytoQueryParams(acct, {
|
||||
amount: args.withdrawManually.amount,
|
||||
message: `Taler top-up ${reserve.reservePub}`,
|
||||
message: `Taler top-up ${reservePub}`,
|
||||
});
|
||||
console.log("Created reserve", reserve.reservePub);
|
||||
console.log("Created reserve", reservePub);
|
||||
console.log("Payto URI", completePaytoUri);
|
||||
});
|
||||
});
|
||||
@ -640,37 +710,14 @@ currenciesCli
|
||||
.subcommand("show", "show", { help: "Show currencies." })
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const currencies = await wallet.getCurrencies();
|
||||
const currencies = await wallet.client.call(
|
||||
WalletApiOperation.ListCurrencies,
|
||||
{},
|
||||
);
|
||||
console.log(JSON.stringify(currencies, undefined, 2));
|
||||
});
|
||||
});
|
||||
|
||||
const reservesCli = advancedCli.subcommand("reserves", "reserves", {
|
||||
help: "Manage reserves.",
|
||||
});
|
||||
|
||||
reservesCli
|
||||
.subcommand("list", "list", {
|
||||
help: "List reserves.",
|
||||
})
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const reserves = await wallet.getReservesForExchange();
|
||||
console.log(JSON.stringify(reserves, undefined, 2));
|
||||
});
|
||||
});
|
||||
|
||||
reservesCli
|
||||
.subcommand("update", "update", {
|
||||
help: "Update reserve status via exchange.",
|
||||
})
|
||||
.requiredArgument("reservePub", clk.STRING)
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
await wallet.updateReserve(args.update.reservePub);
|
||||
});
|
||||
});
|
||||
|
||||
advancedCli
|
||||
.subcommand("payPrepare", "pay-prepare", {
|
||||
help: "Claim an order but don't pay yet.",
|
||||
@ -678,7 +725,12 @@ advancedCli
|
||||
.requiredArgument("url", clk.STRING)
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const res = await wallet.preparePayForUri(args.payPrepare.url);
|
||||
const res = await wallet.client.call(
|
||||
WalletApiOperation.PreparePayForUri,
|
||||
{
|
||||
talerPayUri: args.payPrepare.url,
|
||||
},
|
||||
);
|
||||
switch (res.status) {
|
||||
case PreparePayResultType.InsufficientBalance:
|
||||
console.log("insufficient balance");
|
||||
@ -707,10 +759,10 @@ advancedCli
|
||||
.maybeOption("sessionIdOverride", ["--session-id"], clk.STRING)
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
wallet.confirmPay(
|
||||
args.payConfirm.proposalId,
|
||||
args.payConfirm.sessionIdOverride,
|
||||
);
|
||||
await wallet.client.call(WalletApiOperation.ConfirmPay, {
|
||||
proposalId: args.payConfirm.proposalId,
|
||||
sessionId: args.payConfirm.sessionIdOverride,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -721,7 +773,9 @@ advancedCli
|
||||
.requiredArgument("coinPub", clk.STRING)
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
await wallet.refresh(args.refresh.coinPub);
|
||||
await wallet.client.call(WalletApiOperation.ForceRefresh, {
|
||||
coinPubList: [args.refresh.coinPub],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -731,7 +785,10 @@ advancedCli
|
||||
})
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const coinDump = await wallet.dumpCoins();
|
||||
const coinDump = await wallet.client.call(
|
||||
WalletApiOperation.DumpCoins,
|
||||
{},
|
||||
);
|
||||
console.log(JSON.stringify(coinDump, undefined, 2));
|
||||
});
|
||||
});
|
||||
@ -755,7 +812,10 @@ advancedCli
|
||||
process.exit(1);
|
||||
}
|
||||
for (const c of coinPubList) {
|
||||
await wallet.setCoinSuspended(c, true);
|
||||
await wallet.client.call(WalletApiOperation.SetCoinSuspended, {
|
||||
coinPub: c,
|
||||
suspended: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -777,7 +837,10 @@ advancedCli
|
||||
process.exit(1);
|
||||
}
|
||||
for (const c of coinPubList) {
|
||||
await wallet.setCoinSuspended(c, false);
|
||||
await wallet.client.call(WalletApiOperation.SetCoinSuspended, {
|
||||
coinPub: c,
|
||||
suspended: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -788,43 +851,18 @@ advancedCli
|
||||
})
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const coins = await wallet.getCoins();
|
||||
for (const coin of coins) {
|
||||
console.log(`coin ${coin.coinPub}`);
|
||||
console.log(` status ${coin.status}`);
|
||||
console.log(` exchange ${coin.exchangeBaseUrl}`);
|
||||
console.log(` denomPubHash ${coin.denomPubHash}`);
|
||||
const coins = await wallet.client.call(WalletApiOperation.DumpCoins, {});
|
||||
for (const coin of coins.coins) {
|
||||
console.log(`coin ${coin.coin_pub}`);
|
||||
console.log(` exchange ${coin.exchange_base_url}`);
|
||||
console.log(` denomPubHash ${coin.denom_pub_hash}`);
|
||||
console.log(
|
||||
` remaining amount ${Amounts.stringify(coin.currentAmount)}`,
|
||||
` remaining amount ${Amounts.stringify(coin.remaining_value)}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
advancedCli
|
||||
.subcommand("updateReserve", "update-reserve", {
|
||||
help: "Update reserve status.",
|
||||
})
|
||||
.requiredArgument("reservePub", clk.STRING)
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const r = await wallet.updateReserve(args.updateReserve.reservePub);
|
||||
console.log("updated reserve:", JSON.stringify(r, undefined, 2));
|
||||
});
|
||||
});
|
||||
|
||||
advancedCli
|
||||
.subcommand("updateReserve", "show-reserve", {
|
||||
help: "Show the current reserve status.",
|
||||
})
|
||||
.requiredArgument("reservePub", clk.STRING)
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const r = await wallet.getReserve(args.updateReserve.reservePub);
|
||||
console.log("updated reserve:", JSON.stringify(r, undefined, 2));
|
||||
});
|
||||
});
|
||||
|
||||
const testCli = walletCli.subcommand("testingArgs", "testing", {
|
||||
help: "Subcommands for testing GNU Taler deployments.",
|
||||
});
|
||||
|
@ -1783,7 +1783,10 @@ export class WalletCli {
|
||||
}
|
||||
|
||||
async forceUpdateExchange(req: ForceExchangeUpdateRequest): Promise<void> {
|
||||
const resp = await this.apiRequest("forceUpdateExchange", req);
|
||||
const resp = await this.apiRequest("addExchange", {
|
||||
exchangeBaseUrl: req.exchangeBaseUrl,
|
||||
forceUpdate: true,
|
||||
});
|
||||
if (resp.type === "response") {
|
||||
return;
|
||||
}
|
||||
|
@ -213,4 +213,4 @@ export async function runPaymentFaultTest(t: GlobalTestState) {
|
||||
}
|
||||
|
||||
runPaymentFaultTest.suites = ["wallet"];
|
||||
runPaymentFaultTest.timeoutMs = 120000;
|
||||
runPaymentFaultTest.timeoutMs = 120000;
|
||||
|
@ -576,7 +576,7 @@ export interface ExchangeDetailsRecord {
|
||||
|
||||
/**
|
||||
* Timestamp when the ToS was accepted.
|
||||
*
|
||||
*
|
||||
* Used during backup merging.
|
||||
*/
|
||||
termsOfServiceAcceptedTimestamp: Timestamp | undefined;
|
||||
|
@ -22,7 +22,6 @@
|
||||
/**
|
||||
* Imports.
|
||||
*/
|
||||
import { Wallet } from "../wallet";
|
||||
import {
|
||||
MemoryBackend,
|
||||
BridgeIDBFactory,
|
||||
@ -36,6 +35,7 @@ import { Logger } from "@gnu-taler/taler-util";
|
||||
import { SynchronousCryptoWorkerFactory } from "../crypto/workers/synchronousWorker";
|
||||
import type { IDBFactory } from "@gnu-taler/idb-bridge";
|
||||
import { WalletNotification } from "@gnu-taler/taler-util";
|
||||
import { InternalWalletState } from "../operations/state.js";
|
||||
|
||||
const logger = new Logger("headless/helpers.ts");
|
||||
|
||||
@ -93,7 +93,7 @@ function makeId(length: number): string {
|
||||
*/
|
||||
export async function getDefaultNodeWallet(
|
||||
args: DefaultNodeWalletArgs = {},
|
||||
): Promise<Wallet> {
|
||||
): Promise<InternalWalletState> {
|
||||
BridgeIDBFactory.enableTracing = false;
|
||||
const myBackend = new MemoryBackend();
|
||||
myBackend.enableTracing = false;
|
||||
@ -172,7 +172,8 @@ export async function getDefaultNodeWallet(
|
||||
workerFactory = new SynchronousCryptoWorkerFactory();
|
||||
}
|
||||
|
||||
const w = new Wallet(myDb, myHttpLib, workerFactory);
|
||||
const w = new InternalWalletState(myDb, myHttpLib, workerFactory);
|
||||
|
||||
if (args.notifyHandler) {
|
||||
w.addNotificationListener(args.notifyHandler);
|
||||
}
|
||||
|
@ -19,34 +19,34 @@
|
||||
*/
|
||||
|
||||
// Errors
|
||||
export * from "./operations/errors";
|
||||
export * from "./operations/errors.js";
|
||||
|
||||
// Util functionality
|
||||
export { URL } from "./util/url";
|
||||
export * from "./util/promiseUtils";
|
||||
export * from "./util/query";
|
||||
export * from "./util/http";
|
||||
export { URL } from "./util/url.js";
|
||||
export * from "./util/promiseUtils.js";
|
||||
export * from "./util/query.js";
|
||||
export * from "./util/http.js";
|
||||
|
||||
// Utils for using the wallet under node
|
||||
export { NodeHttpLib } from "./headless/NodeHttpLib";
|
||||
export { NodeHttpLib } from "./headless/NodeHttpLib.js";
|
||||
export {
|
||||
getDefaultNodeWallet,
|
||||
DefaultNodeWalletArgs,
|
||||
} from "./headless/helpers";
|
||||
} from "./headless/helpers.js";
|
||||
|
||||
export * from "./operations/versions";
|
||||
export * from "./operations/versions.js";
|
||||
|
||||
export * from "./db";
|
||||
export * from "./db.js";
|
||||
|
||||
// Crypto and crypto workers
|
||||
export * from "./crypto/workers/nodeThreadWorker";
|
||||
export { CryptoImplementation } from "./crypto/workers/cryptoImplementation";
|
||||
export type { CryptoWorker } from "./crypto/workers/cryptoWorker";
|
||||
export { CryptoWorkerFactory, CryptoApi } from "./crypto/workers/cryptoApi";
|
||||
export * from "./crypto/talerCrypto";
|
||||
export * from "./crypto/workers/nodeThreadWorker.js";
|
||||
export { CryptoImplementation } from "./crypto/workers/cryptoImplementation.js";
|
||||
export type { CryptoWorker } from "./crypto/workers/cryptoWorker.js";
|
||||
export { CryptoWorkerFactory, CryptoApi } from "./crypto/workers/cryptoApi.js";
|
||||
export * from "./crypto/talerCrypto.js";
|
||||
|
||||
export * from "./pending-types";
|
||||
export * from "./pending-types.js";
|
||||
|
||||
export * from "./util/debugFlags";
|
||||
export * from "./util/debugFlags.js";
|
||||
|
||||
export { Wallet } from "./wallet";
|
||||
export * from "./wallet.js";
|
||||
|
@ -38,7 +38,10 @@ import {
|
||||
WalletBackupConfState,
|
||||
WALLET_BACKUP_STATE_KEY,
|
||||
} from "../../db.js";
|
||||
import { checkDbInvariant, checkLogicInvariant } from "../../util/invariants.js";
|
||||
import {
|
||||
checkDbInvariant,
|
||||
checkLogicInvariant,
|
||||
} from "../../util/invariants.js";
|
||||
import {
|
||||
bytesToString,
|
||||
decodeCrock,
|
||||
@ -83,8 +86,15 @@ import {
|
||||
TalerErrorDetails,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { CryptoApi } from "../../crypto/workers/cryptoApi.js";
|
||||
import { secretbox, secretbox_open } from "../../crypto/primitives/nacl-fast.js";
|
||||
import { checkPaymentByProposalId, confirmPay, preparePayForUri } from "../pay.js";
|
||||
import {
|
||||
secretbox,
|
||||
secretbox_open,
|
||||
} from "../../crypto/primitives/nacl-fast.js";
|
||||
import {
|
||||
checkPaymentByProposalId,
|
||||
confirmPay,
|
||||
preparePayForUri,
|
||||
} from "../pay.js";
|
||||
import { exportBackup } from "./export.js";
|
||||
import { BackupCryptoPrecomputedData, importBackup } from "./import.js";
|
||||
import { provideBackupState, getWalletBackupState } from "./state.js";
|
||||
|
@ -60,7 +60,12 @@ import {
|
||||
WALLET_CACHE_BREAKER_CLIENT_VERSION,
|
||||
WALLET_EXCHANGE_PROTOCOL_VERSION,
|
||||
} from "./versions.js";
|
||||
import { getExpiryTimestamp, HttpRequestLibrary, readSuccessResponseJsonOrThrow, readSuccessResponseTextOrThrow } from "../util/http.js";
|
||||
import {
|
||||
getExpiryTimestamp,
|
||||
HttpRequestLibrary,
|
||||
readSuccessResponseJsonOrThrow,
|
||||
readSuccessResponseTextOrThrow,
|
||||
} from "../util/http.js";
|
||||
import { CryptoApi } from "../crypto/workers/cryptoApi.js";
|
||||
import { DbAccess, GetReadOnlyAccess } from "../util/query.js";
|
||||
import { decodeCrock, encodeCrock, hash } from "../crypto/talerCrypto.js";
|
||||
|
@ -55,7 +55,10 @@ import { URL } from "../util/url.js";
|
||||
import { guardOperationException } from "./errors.js";
|
||||
import { updateExchangeFromUrl } from "./exchanges.js";
|
||||
import { EXCHANGE_COINS_LOCK, InternalWalletState } from "./state.js";
|
||||
import { isWithdrawableDenom, selectWithdrawalDenominations } from "./withdraw.js";
|
||||
import {
|
||||
isWithdrawableDenom,
|
||||
selectWithdrawalDenominations,
|
||||
} from "./withdraw.js";
|
||||
import { RefreshNewDenomInfo } from "../crypto/cryptoTypes.js";
|
||||
import { GetReadWriteAccess } from "../util/query.js";
|
||||
|
||||
|
@ -27,8 +27,13 @@ import { WalletStoresV1 } from "../db.js";
|
||||
import { PendingOperationsResponse } from "../pending-types.js";
|
||||
import { AsyncOpMemoMap, AsyncOpMemoSingle } from "../util/asyncMemo.js";
|
||||
import { HttpRequestLibrary } from "../util/http";
|
||||
import { OpenedPromise, openPromise } from "../util/promiseUtils.js";
|
||||
import {
|
||||
AsyncCondition,
|
||||
OpenedPromise,
|
||||
openPromise,
|
||||
} from "../util/promiseUtils.js";
|
||||
import { DbAccess } from "../util/query.js";
|
||||
import { TimerGroup } from "../util/timer.js";
|
||||
|
||||
type NotificationListener = (n: WalletNotification) => void;
|
||||
|
||||
@ -37,6 +42,9 @@ const logger = new Logger("state.ts");
|
||||
export const EXCHANGE_COINS_LOCK = "exchange-coins-lock";
|
||||
export const EXCHANGE_RESERVES_LOCK = "exchange-reserves-lock";
|
||||
|
||||
/**
|
||||
* Internal state of the wallet.
|
||||
*/
|
||||
export class InternalWalletState {
|
||||
memoProcessReserve: AsyncOpMemoMap<void> = new AsyncOpMemoMap();
|
||||
memoMakePlanchet: AsyncOpMemoMap<void> = new AsyncOpMemoMap();
|
||||
@ -47,8 +55,15 @@ export class InternalWalletState {
|
||||
memoProcessDeposit: AsyncOpMemoMap<void> = new AsyncOpMemoMap();
|
||||
cryptoApi: CryptoApi;
|
||||
|
||||
timerGroup: TimerGroup = new TimerGroup();
|
||||
latch = new AsyncCondition();
|
||||
stopped = false;
|
||||
memoRunRetryLoop = new AsyncOpMemoSingle<void>();
|
||||
|
||||
listeners: NotificationListener[] = [];
|
||||
|
||||
initCalled: boolean = false;
|
||||
|
||||
/**
|
||||
* Promises that are waiting for a particular resource.
|
||||
*/
|
||||
@ -85,6 +100,15 @@ export class InternalWalletState {
|
||||
this.listeners.push(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop ongoing processing.
|
||||
*/
|
||||
stop(): void {
|
||||
this.stopped = true;
|
||||
this.timerGroup.stopCurrentAndFutureTimers();
|
||||
this.cryptoApi.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run an async function after acquiring a list of locks, identified
|
||||
* by string tokens.
|
||||
|
@ -33,10 +33,13 @@ import {
|
||||
TestPayArgs,
|
||||
PreparePayResultType,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { Wallet } from "../wallet.js";
|
||||
import { createTalerWithdrawReserve } from "./reserves.js";
|
||||
import { InternalWalletState } from "./state.js";
|
||||
import { URL } from "../util/url.js";
|
||||
import { confirmPay, preparePayForUri } from "./pay.js";
|
||||
import { getBalances } from "./balance.js";
|
||||
import { runUntilDone } from "../wallet.js";
|
||||
import { applyRefund } from "./refund.js";
|
||||
|
||||
const logger = new Logger("operations/testing.ts");
|
||||
|
||||
@ -261,14 +264,13 @@ interface BankWithdrawalResponse {
|
||||
}
|
||||
|
||||
async function makePayment(
|
||||
http: HttpRequestLibrary,
|
||||
wallet: Wallet,
|
||||
ws: InternalWalletState,
|
||||
merchant: MerchantBackendInfo,
|
||||
amount: string,
|
||||
summary: string,
|
||||
): Promise<{ orderId: string }> {
|
||||
const orderResp = await createOrder(
|
||||
http,
|
||||
ws.http,
|
||||
merchant,
|
||||
amount,
|
||||
summary,
|
||||
@ -277,7 +279,7 @@ async function makePayment(
|
||||
|
||||
logger.trace("created order with orderId", orderResp.orderId);
|
||||
|
||||
let paymentStatus = await checkPayment(http, merchant, orderResp.orderId);
|
||||
let paymentStatus = await checkPayment(ws.http, merchant, orderResp.orderId);
|
||||
|
||||
logger.trace("payment status", paymentStatus);
|
||||
|
||||
@ -286,7 +288,7 @@ async function makePayment(
|
||||
throw Error("no taler://pay/ URI in payment response");
|
||||
}
|
||||
|
||||
const preparePayResult = await wallet.preparePayForUri(talerPayUri);
|
||||
const preparePayResult = await preparePayForUri(ws, talerPayUri);
|
||||
|
||||
logger.trace("prepare pay result", preparePayResult);
|
||||
|
||||
@ -294,14 +296,15 @@ async function makePayment(
|
||||
throw Error("payment not possible");
|
||||
}
|
||||
|
||||
const confirmPayResult = await wallet.confirmPay(
|
||||
const confirmPayResult = await confirmPay(
|
||||
ws,
|
||||
preparePayResult.proposalId,
|
||||
undefined,
|
||||
);
|
||||
|
||||
logger.trace("confirmPayResult", confirmPayResult);
|
||||
|
||||
paymentStatus = await checkPayment(http, merchant, orderResp.orderId);
|
||||
paymentStatus = await checkPayment(ws.http, merchant, orderResp.orderId);
|
||||
|
||||
logger.trace("payment status after wallet payment:", paymentStatus);
|
||||
|
||||
@ -315,8 +318,7 @@ async function makePayment(
|
||||
}
|
||||
|
||||
export async function runIntegrationTest(
|
||||
http: HttpRequestLibrary,
|
||||
wallet: Wallet,
|
||||
ws: InternalWalletState,
|
||||
args: IntegrationTestArgs,
|
||||
): Promise<void> {
|
||||
logger.info("running test with arguments", args);
|
||||
@ -325,15 +327,16 @@ export async function runIntegrationTest(
|
||||
const currency = parsedSpendAmount.currency;
|
||||
|
||||
logger.info("withdrawing test balance");
|
||||
await wallet.withdrawTestBalance({
|
||||
amount: args.amountToWithdraw,
|
||||
bankBaseUrl: args.bankBaseUrl,
|
||||
exchangeBaseUrl: args.exchangeBaseUrl,
|
||||
});
|
||||
await wallet.runUntilDone();
|
||||
await withdrawTestBalance(
|
||||
ws,
|
||||
args.amountToWithdraw,
|
||||
args.bankBaseUrl,
|
||||
args.exchangeBaseUrl,
|
||||
);
|
||||
await runUntilDone(ws);
|
||||
logger.info("done withdrawing test balance");
|
||||
|
||||
const balance = await wallet.getBalances();
|
||||
const balance = await getBalances(ws);
|
||||
|
||||
logger.trace(JSON.stringify(balance, null, 2));
|
||||
|
||||
@ -342,16 +345,10 @@ export async function runIntegrationTest(
|
||||
authToken: args.merchantAuthToken,
|
||||
};
|
||||
|
||||
await makePayment(
|
||||
http,
|
||||
wallet,
|
||||
myMerchant,
|
||||
args.amountToSpend,
|
||||
"hello world",
|
||||
);
|
||||
await makePayment(ws, myMerchant, args.amountToSpend, "hello world");
|
||||
|
||||
// Wait until the refresh is done
|
||||
await wallet.runUntilDone();
|
||||
await runUntilDone(ws);
|
||||
|
||||
logger.trace("withdrawing test balance for refund");
|
||||
const withdrawAmountTwo = Amounts.parseOrThrow(`${currency}:18`);
|
||||
@ -359,25 +356,25 @@ export async function runIntegrationTest(
|
||||
const refundAmount = Amounts.parseOrThrow(`${currency}:6`);
|
||||
const spendAmountThree = Amounts.parseOrThrow(`${currency}:3`);
|
||||
|
||||
await wallet.withdrawTestBalance({
|
||||
amount: Amounts.stringify(withdrawAmountTwo),
|
||||
bankBaseUrl: args.bankBaseUrl,
|
||||
exchangeBaseUrl: args.exchangeBaseUrl,
|
||||
});
|
||||
await withdrawTestBalance(
|
||||
ws,
|
||||
Amounts.stringify(withdrawAmountTwo),
|
||||
args.bankBaseUrl,
|
||||
args.exchangeBaseUrl,
|
||||
);
|
||||
|
||||
// Wait until the withdraw is done
|
||||
await wallet.runUntilDone();
|
||||
await runUntilDone(ws);
|
||||
|
||||
const { orderId: refundOrderId } = await makePayment(
|
||||
http,
|
||||
wallet,
|
||||
ws,
|
||||
myMerchant,
|
||||
Amounts.stringify(spendAmountTwo),
|
||||
"order that will be refunded",
|
||||
);
|
||||
|
||||
const refundUri = await refund(
|
||||
http,
|
||||
ws.http,
|
||||
myMerchant,
|
||||
refundOrderId,
|
||||
"test refund",
|
||||
@ -386,18 +383,17 @@ export async function runIntegrationTest(
|
||||
|
||||
logger.trace("refund URI", refundUri);
|
||||
|
||||
await wallet.applyRefund(refundUri);
|
||||
await applyRefund(ws, refundUri);
|
||||
|
||||
logger.trace("integration test: applied refund");
|
||||
|
||||
// Wait until the refund is done
|
||||
await wallet.runUntilDone();
|
||||
await runUntilDone(ws);
|
||||
|
||||
logger.trace("integration test: making payment after refund");
|
||||
|
||||
await makePayment(
|
||||
http,
|
||||
wallet,
|
||||
ws,
|
||||
myMerchant,
|
||||
Amounts.stringify(spendAmountThree),
|
||||
"payment after refund",
|
||||
@ -405,30 +401,26 @@ export async function runIntegrationTest(
|
||||
|
||||
logger.trace("integration test: make payment done");
|
||||
|
||||
await wallet.runUntilDone();
|
||||
await runUntilDone(ws);
|
||||
|
||||
logger.trace("integration test: all done!");
|
||||
}
|
||||
|
||||
export async function testPay(
|
||||
http: HttpRequestLibrary,
|
||||
wallet: Wallet,
|
||||
args: TestPayArgs,
|
||||
) {
|
||||
export async function testPay(ws: InternalWalletState, args: TestPayArgs) {
|
||||
logger.trace("creating order");
|
||||
const merchant = {
|
||||
authToken: args.merchantAuthToken,
|
||||
baseUrl: args.merchantBaseUrl,
|
||||
};
|
||||
const orderResp = await createOrder(
|
||||
http,
|
||||
ws.http,
|
||||
merchant,
|
||||
args.amount,
|
||||
args.summary,
|
||||
"taler://fulfillment-success/thank+you",
|
||||
);
|
||||
logger.trace("created new order with order ID", orderResp.orderId);
|
||||
const checkPayResp = await checkPayment(http, merchant, orderResp.orderId);
|
||||
const checkPayResp = await checkPayment(ws.http, merchant, orderResp.orderId);
|
||||
const talerPayUri = checkPayResp.taler_pay_uri;
|
||||
if (!talerPayUri) {
|
||||
console.error("fatal: no taler pay URI received from backend");
|
||||
@ -436,9 +428,9 @@ export async function testPay(
|
||||
return;
|
||||
}
|
||||
logger.trace("taler pay URI:", talerPayUri);
|
||||
const result = await wallet.preparePayForUri(talerPayUri);
|
||||
const result = await preparePayForUri(ws, talerPayUri);
|
||||
if (result.status !== PreparePayResultType.PaymentPossible) {
|
||||
throw Error(`unexpected prepare pay status: ${result.status}`);
|
||||
}
|
||||
await wallet.confirmPay(result.proposalId, undefined);
|
||||
await confirmPay(ws, result.proposalId, undefined);
|
||||
}
|
||||
|
@ -424,7 +424,7 @@ export async function retryTransaction(
|
||||
break;
|
||||
}
|
||||
case TransactionType.Payment: {
|
||||
const proposalId = rest[0]
|
||||
const proposalId = rest[0];
|
||||
await processPurchasePay(ws, proposalId, true);
|
||||
break;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
/**
|
||||
* Imports.
|
||||
*/
|
||||
import test from "ava";
|
||||
import test from "ava";
|
||||
import { AmountJson, Amounts } from "@gnu-taler/taler-util";
|
||||
import { AvailableCoinInfo, selectPayCoins } from "./coinSelection.js";
|
||||
|
||||
|
@ -24,7 +24,10 @@
|
||||
/**
|
||||
* Imports
|
||||
*/
|
||||
import { OperationFailedError, makeErrorDetails } from "../operations/errors.js";
|
||||
import {
|
||||
OperationFailedError,
|
||||
makeErrorDetails,
|
||||
} from "../operations/errors.js";
|
||||
import {
|
||||
Logger,
|
||||
Duration,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -26,7 +26,6 @@
|
||||
import { isFirefox, getPermissionsApi } from "./compat";
|
||||
import { extendedPermissions } from "./permissions";
|
||||
import {
|
||||
Wallet,
|
||||
OpenedPromise,
|
||||
openPromise,
|
||||
openTalerDatabase,
|
||||
@ -34,6 +33,9 @@ import {
|
||||
deleteTalerDatabase,
|
||||
DbAccess,
|
||||
WalletStoresV1,
|
||||
handleCoreApiRequest,
|
||||
runRetryLoop,
|
||||
handleNotifyReserve,
|
||||
} from "@gnu-taler/taler-wallet-core";
|
||||
import {
|
||||
classifyTalerUri,
|
||||
@ -45,12 +47,13 @@ import {
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { BrowserHttpLib } from "./browserHttpLib";
|
||||
import { BrowserCryptoWorkerFactory } from "./browserCryptoWorkerFactory";
|
||||
import { InternalWalletState } from "@gnu-taler/taler-wallet-core/src/operations/state";
|
||||
|
||||
/**
|
||||
* Currently active wallet instance. Might be unloaded and
|
||||
* re-instantiated when the database is reset.
|
||||
*/
|
||||
let currentWallet: Wallet | undefined;
|
||||
let currentWallet: InternalWalletState | undefined;
|
||||
|
||||
let currentDatabase: DbAccess<typeof WalletStoresV1> | undefined;
|
||||
|
||||
@ -167,7 +170,7 @@ async function dispatch(
|
||||
};
|
||||
break;
|
||||
}
|
||||
r = await w.handleCoreApiRequest(req.operation, req.id, req.payload);
|
||||
r = await handleCoreApiRequest(w, req.operation, req.id, req.payload);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -253,7 +256,7 @@ async function reinitWallet(): Promise<void> {
|
||||
}
|
||||
const http = new BrowserHttpLib();
|
||||
console.log("setting wallet");
|
||||
const wallet = new Wallet(
|
||||
const wallet = new InternalWalletState(
|
||||
currentDatabase,
|
||||
http,
|
||||
new BrowserCryptoWorkerFactory(),
|
||||
@ -267,7 +270,7 @@ async function reinitWallet(): Promise<void> {
|
||||
}
|
||||
}
|
||||
});
|
||||
wallet.runRetryLoop().catch((e) => {
|
||||
runRetryLoop(wallet).catch((e) => {
|
||||
console.log("error during wallet retry loop", e);
|
||||
});
|
||||
// Useful for debugging in the background page.
|
||||
@ -357,7 +360,7 @@ function headerListener(
|
||||
if (!w) {
|
||||
return;
|
||||
}
|
||||
w.handleNotifyReserve();
|
||||
handleNotifyReserve(w);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
@ -448,3 +451,4 @@ export async function wxMain(): Promise<void> {
|
||||
setupHeaderListener();
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user