commit d9f1f052617330cb5423e12ec611fd325cce34ca
parent 78eb78346a9eba3de75d5d013108653afd0cdbc2
Author: Florian Dold <florian@dold.me>
Date: Thu, 16 Apr 2026 15:47:51 +0200
wallet-core: add TOPS exchange to builtin
We also version the built-in list now, to allow it to evolve without
overriding the user's settings. The wallet-core client can no longer
configure the builtin exchanges list, the corresponding test has been
removed as well.
Diffstat:
6 files changed, 50 insertions(+), 119 deletions(-)
diff --git a/packages/taler-harness/src/integrationtests/test-wallet-config.ts b/packages/taler-harness/src/integrationtests/test-wallet-config.ts
@@ -1,67 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2020 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- * Imports.
- */
-import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
-import { GlobalTestState } from "../harness/harness.js";
-import { createWalletDaemonWithClient } from "../harness/environments.js";
-
-export async function runWalletConfigTest(t: GlobalTestState) {
- const w1 = await createWalletDaemonWithClient(t, {
- name: "w1",
- config: {
- builtin: {
- exchanges: [],
- },
- },
- });
-
- const exchangesResp1 = await w1.walletClient.call(
- WalletApiOperation.ListExchanges,
- {},
- );
-
- t.assertDeepEqual(exchangesResp1.exchanges.length, 0);
-
- const w2 = await createWalletDaemonWithClient(t, {
- name: "w2",
- config: {
- builtin: {
- exchanges: [
- {
- exchangeBaseUrl: "https://exchange.demo.taler.net/",
- currencyHint: "KUDOS",
- },
- {
- exchangeBaseUrl: "https://exchange.test.taler.net/",
- currencyHint: "TESTKUDOS",
- },
- ],
- },
- },
- });
-
- const exchangesResp2 = await w2.walletClient.call(
- WalletApiOperation.ListExchanges,
- {},
- );
-
- t.assertDeepEqual(exchangesResp2.exchanges.length, 2);
-}
-
-runWalletConfigTest.suites = ["wallet"];
diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts b/packages/taler-harness/src/integrationtests/testrunner.ts
@@ -147,6 +147,7 @@ import { runPeerPullTest } from "./test-peer-pull.js";
import { runPeerPushLargeTest } from "./test-peer-push-large.js";
import { runPeerPushTest } from "./test-peer-push.js";
import { runPeerRepairTest } from "./test-peer-repair.js";
+import { runPreparedTransferTest } from "./test-prepared-transfer.js";
import { runRefundAutoTest } from "./test-refund-auto.js";
import { runRefundGoneTest } from "./test-refund-gone.js";
import { runRefundIncrementalTest } from "./test-refund-incremental.js";
@@ -179,7 +180,6 @@ import { runWalletBlockedPayMerchantTest } from "./test-wallet-blocked-pay-merch
import { runWalletBlockedPayPeerPullTest } from "./test-wallet-blocked-pay-peer-pull.js";
import { runWalletBlockedPayPeerPushTest } from "./test-wallet-blocked-pay-peer-push.js";
import { runWalletCliTerminationTest } from "./test-wallet-cli-termination.js";
-import { runWalletConfigTest } from "./test-wallet-config.js";
import { runWalletContactsBasicTest } from "./test-wallet-contacts-basic.js";
import { runWalletCryptoWorkerTest } from "./test-wallet-cryptoworker.js";
import { runWalletDblessTest } from "./test-wallet-dbless.js";
@@ -224,7 +224,6 @@ import { runWithdrawalHugeTest } from "./test-withdrawal-huge.js";
import { runWithdrawalIdempotentTest } from "./test-withdrawal-idempotent.js";
import { runWithdrawalManualTest } from "./test-withdrawal-manual.js";
import { runWithdrawalPrepareTest } from "./test-withdrawal-prepare.js";
-import { runPreparedTransferTest } from "./test-prepared-transfer.js"
/**
* Test runner.
@@ -315,7 +314,6 @@ const allTests: TestMainFunction[] = [
runOtpTest,
runWalletBalanceNotificationsTest,
runExchangeManagementTest,
- runWalletConfigTest,
runWalletObservabilityTest,
runWalletDevExperimentsTest,
runWalletBalanceZeroTest,
@@ -433,7 +431,7 @@ const allTests: TestMainFunction[] = [
runMerchantDepositLargeTest,
runWireMetadataTest,
runMerchantPaytoReuseTest,
- runPreparedTransferTest
+ runPreparedTransferTest,
];
export interface TestRunSpec {
diff --git a/packages/taler-util/src/types-taler-wallet.ts b/packages/taler-util/src/types-taler-wallet.ts
@@ -419,7 +419,6 @@ export interface BuiltinExchange {
}
export interface PartialWalletRunConfig {
- builtin?: Partial<WalletRunConfig["builtin"]>;
testing?: Partial<WalletRunConfig["testing"]>;
features?: Partial<WalletRunConfig["features"]>;
lazyTaskLoop?: Partial<WalletRunConfig["lazyTaskLoop"]>;
@@ -428,15 +427,6 @@ export interface PartialWalletRunConfig {
export interface WalletRunConfig {
/**
- * Initialization values useful for a complete startup.
- *
- * These are values may be overridden by different wallets
- */
- builtin: {
- exchanges: BuiltinExchange[];
- };
-
- /**
* Unsafe options which it should only be used to create
* testing environment.
*/
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
@@ -1727,7 +1727,7 @@ export type ConfigRecord =
key: ConfigRecordKey.WalletBackupState;
value: WalletBackupConfState;
}
- | { key: ConfigRecordKey.CurrencyDefaultsApplied; value: boolean }
+ | { key: ConfigRecordKey.CurrencyDefaultsApplied; value: boolean | number }
| { key: ConfigRecordKey.TestLoopTx; value: number }
| { key: ConfigRecordKey.LastInitInfo; value: DbProtocolTimestamp }
| { key: ConfigRecordKey.MaterializedTransactionsVersion; value: number }
diff --git a/packages/taler-wallet-core/src/exchanges.ts b/packages/taler-wallet-core/src/exchanges.ts
@@ -761,7 +761,7 @@ export async function addPresetExchangeEntry(
tx: WalletIndexedDbTransaction,
exchangeBaseUrl: string,
currencyHint?: string,
-): Promise<{ notification?: WalletNotification }> {
+): Promise<void> {
let exchange = await tx.exchanges.get(exchangeBaseUrl);
if (!exchange) {
const r: ExchangeEntryRecord = {
@@ -783,17 +783,15 @@ export async function addPresetExchangeEntry(
tosCurrentEtag: undefined,
};
await tx.exchanges.put(r);
- return {
- notification: {
- type: NotificationType.ExchangeStateTransition,
- exchangeBaseUrl: exchangeBaseUrl,
- // Exchange did not exist yet
- oldExchangeState: undefined,
- newExchangeState: getExchangeState(r),
- },
- };
+ tx.notify({
+ type: NotificationType.ExchangeStateTransition,
+ exchangeBaseUrl: exchangeBaseUrl,
+ // Exchange did not exist yet
+ oldExchangeState: undefined,
+ newExchangeState: getExchangeState(r),
+ });
}
- return {};
+ return;
}
async function provideExchangeRecordInTx(
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
@@ -526,38 +526,58 @@ export type NotificationListener = (n: WalletNotification) => void;
type CancelFn = () => void;
+const currentDefaultsVersion = 2;
+
+/**
+ * Exchanges that ship with wallet-core.
+ */
+const builtinExchanges = [
+ {
+ exchangeBaseUrl: "https://exchange.demo.taler.net/",
+ currencyHint: "KUDOS",
+ versionAdded: 1,
+ },
+ {
+ exchangeBaseUrl: "https://exchange.taler-ops.ch/",
+ currencyHint: "CHF",
+ versionAdded: 2,
+ },
+];
+
/**
* Insert the hard-coded defaults for exchanges, coins and
* auditors into the database, unless these defaults have
* already been applied.
*/
async function fillDefaults(wex: WalletExecutionContext): Promise<void> {
- const notifications: WalletNotification[] = [];
await wex.runLegacyWalletDbTx(async (tx) => {
- const appliedRec = await tx.config.get("currencyDefaultsApplied");
- let alreadyApplied = appliedRec ? !!appliedRec.value : false;
- if (alreadyApplied) {
- logger.trace("defaults already applied");
- return;
+ let appliedRec = await tx.config.get("currencyDefaultsApplied");
+ let appliedVersion = appliedRec ? !!appliedRec.value : 0;
+ if (appliedRec != null) {
+ if (appliedRec.value === true) {
+ appliedVersion = 1;
+ } else if (appliedRec.value == false) {
+ appliedVersion = 0;
+ } else if (typeof appliedRec.value === "number") {
+ appliedVersion = appliedRec.value;
+ } else {
+ logger.error("invalid value for currencyDefaultsApplied config");
+ appliedVersion = 0;
+ }
+ } else {
+ appliedVersion = 0;
}
- for (const exch of wex.ws.config.builtin.exchanges) {
- const resp = await addPresetExchangeEntry(
- tx,
- exch.exchangeBaseUrl,
- exch.currencyHint,
- );
- if (resp.notification) {
- notifications.push(resp.notification);
+ for (const exch of builtinExchanges) {
+ if (exch.versionAdded < currentDefaultsVersion) {
+ continue;
}
+ await addPresetExchangeEntry(tx, exch.exchangeBaseUrl, exch.currencyHint);
}
await tx.config.put({
key: ConfigRecordKey.CurrencyDefaultsApplied,
- value: true,
+ value: currentDefaultsVersion,
});
});
- for (const notif of notifications) {
- wex.ws.notify(notif);
- }
}
/**
@@ -3015,14 +3035,6 @@ function applyRunConfigDefaults(wcp?: PartialWalletRunConfig): WalletRunConfig {
logger.warn(`allowHttp flag not supported anymore`);
}
return {
- builtin: {
- exchanges: wcp?.builtin?.exchanges ?? [
- {
- exchangeBaseUrl: "https://exchange.demo.taler.net/",
- currencyHint: "KUDOS",
- },
- ],
- },
features: {
allowHttp: true,
enableV1Contracts: wcp?.features?.enableV1Contracts ?? false,