commit 09aa6b1d3a0b7d52c626fa5bdfb31c107b060769
parent 1f83b0afa73d26ffb2f61ec466032f14f6d07ab3
Author: Florian Dold <florian@dold.me>
Date: Sun, 24 Aug 2025 19:32:51 +0200
wallet-core: implement dev experiments for global currency exchanges
Diffstat:
3 files changed, 67 insertions(+), 5 deletions(-)
diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts
@@ -1058,6 +1058,21 @@ exchangesCli
});
exchangesCli
+ .subcommand("exchangesListCmd", "trusted", {
+ help: "List trusted global currency exchanges.",
+ })
+ .action(async (args) => {
+ console.log("Listing exchanges ...");
+ await withWallet(args, { lazyTaskLoop: true }, async (wallet) => {
+ const exchanges = await wallet.client.call(
+ WalletApiOperation.ListGlobalCurrencyExchanges,
+ {},
+ );
+ console.log(JSON.stringify(exchanges, undefined, 2));
+ });
+ });
+
+exchangesCli
.subcommand("exchangesUpdateCmd", "update", {
help: "Update or add an exchange by base URL.",
})
diff --git a/packages/taler-wallet-core/src/dev-experiments.ts b/packages/taler-wallet-core/src/dev-experiments.ts
@@ -67,7 +67,12 @@ import { PeerPushCreditTransactionContext } from "./pay-peer-push-credit.js";
import { PeerPushDebitTransactionContext } from "./pay-peer-push-debit.js";
import { RefreshTransactionContext } from "./refresh.js";
import { rematerializeTransactions } from "./transactions.js";
-import { DevExperimentState, WalletExecutionContext } from "./wallet.js";
+import {
+ DevExperimentState,
+ WalletExecutionContext,
+ handleAddGlobalCurrencyExchange,
+ handleRemoveGlobalCurrencyExchange,
+} from "./wallet.js";
import { WithdrawTransactionContext } from "./withdraw.js";
const logger = new Logger("dev-experiments.ts");
@@ -222,6 +227,46 @@ export async function applyDevExperiment(
await addFakeTx(wex, parsedUri);
return;
}
+ case "add-global-exchange": {
+ const currency = parsedUri.query?.get("c");
+ if (!currency || currency.length === 0) {
+ throw Error("missing currency (c)");
+ }
+ const exchangeBaseUrl = parsedUri.query?.get("e");
+ if (!exchangeBaseUrl || exchangeBaseUrl.length === 0) {
+ throw Error("missing exchange base URL (e)");
+ }
+ const exchangeMasterPub = parsedUri.query?.get("p");
+ if (!exchangeMasterPub || exchangeMasterPub.length === 0) {
+ throw Error("missing exchange master pub (p)");
+ }
+ await handleAddGlobalCurrencyExchange(wex, {
+ currency,
+ exchangeBaseUrl,
+ exchangeMasterPub,
+ });
+ return;
+ }
+ case "remove-global-exchange": {
+ const currency = parsedUri.query?.get("c");
+ if (!currency || currency.length === 0) {
+ throw Error("missing currency (c)");
+ }
+ const exchangeBaseUrl = parsedUri.query?.get("e");
+ if (!exchangeBaseUrl || exchangeBaseUrl.length === 0) {
+ throw Error("missing exchange base URL (e)");
+ }
+ const exchangeMasterPub = parsedUri.query?.get("p");
+ if (!exchangeMasterPub || exchangeMasterPub.length === 0) {
+ throw Error("missing exchange master pub (p)");
+ }
+ await handleRemoveGlobalCurrencyExchange(wex, {
+ currency,
+ exchangeBaseUrl,
+ exchangeMasterPub,
+ });
+ return;
+ }
case "flag-confirm-pay-no-wait": {
const setVal = parsedUri.query?.get("val");
if (setVal === "0") {
@@ -233,9 +278,11 @@ export async function applyDevExperiment(
}
return;
}
+ default:
+ throw Error(
+ `dev-experiment id not understood ${parsedUri.devExperimentId}`,
+ );
}
-
- throw Error(`dev-experiment id not understood ${parsedUri.devExperimentId}`);
}
async function addFakeTx(
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
@@ -1500,7 +1500,7 @@ async function handleListGlobalCurrencyAuditors(
return resp;
}
-async function handleAddGlobalCurrencyExchange(
+export async function handleAddGlobalCurrencyExchange(
wex: WalletExecutionContext,
req: AddGlobalCurrencyExchangeRequest,
): Promise<EmptyObject> {
@@ -1561,7 +1561,7 @@ async function handleRemoveGlobalCurrencyAuditor(
return {};
}
-async function handleRemoveGlobalCurrencyExchange(
+export async function handleRemoveGlobalCurrencyExchange(
wex: WalletExecutionContext,
req: RemoveGlobalCurrencyExchangeRequest,
): Promise<EmptyObject> {