summaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2024-01-22 13:49:11 +0100
committerFlorian Dold <florian@dold.me>2024-01-22 13:49:11 +0100
commit88851f45403c1995c973bcae7ad2976db3c430c7 (patch)
tree8a7bbd228b7b647a4ddc22bff732b71e0c6be276 /packages
parentd32731fc7526df18361aae6aa5541e10cf6b41aa (diff)
downloadwallet-core-88851f45403c1995c973bcae7ad2976db3c430c7.tar.gz
wallet-core-88851f45403c1995c973bcae7ad2976db3c430c7.tar.bz2
wallet-core-88851f45403c1995c973bcae7ad2976db3c430c7.zip
wallet-core: implement DD45 global currency management requests
Diffstat (limited to 'packages')
-rw-r--r--packages/taler-util/src/wallet-types.ts72
-rw-r--r--packages/taler-wallet-cli/src/index.ts104
-rw-r--r--packages/taler-wallet-core/src/db.ts69
-rw-r--r--packages/taler-wallet-core/src/util/query.ts3
-rw-r--r--packages/taler-wallet-core/src/wallet-api-types.ts67
-rw-r--r--packages/taler-wallet-core/src/wallet.ts118
6 files changed, 387 insertions, 46 deletions
diff --git a/packages/taler-util/src/wallet-types.ts b/packages/taler-util/src/wallet-types.ts
index 52156cf9e..c20290287 100644
--- a/packages/taler-util/src/wallet-types.ts
+++ b/packages/taler-util/src/wallet-types.ts
@@ -2972,3 +2972,75 @@ export interface ExchangeEntryState {
exchangeEntryStatus: ExchangeEntryStatus;
exchangeUpdateStatus: ExchangeUpdateStatus;
}
+
+export interface ListGlobalCurrencyAuditorsResponse {
+ auditors: {
+ currency: string;
+ auditorBaseUrl: string;
+ auditorPub: string;
+ }[];
+}
+
+export interface ListGlobalCurrencyExchangesResponse {
+ exchanges: {
+ currency: string;
+ exchangeBaseUrl: string;
+ exchangeMasterPub: string;
+ }[];
+}
+
+export interface AddGlobalCurrencyExchangeRequest {
+ currency: string;
+ exchangeBaseUrl: string;
+ exchangeMasterPub: string;
+}
+
+export const codecForAddGlobalCurrencyExchangeRequest =
+ (): Codec<AddGlobalCurrencyExchangeRequest> =>
+ buildCodecForObject<AddGlobalCurrencyExchangeRequest>()
+ .property("currency", codecForString())
+ .property("exchangeBaseUrl", codecForString())
+ .property("exchangeMasterPub", codecForString())
+ .build("AddGlobalCurrencyExchangeRequest");
+
+export interface RemoveGlobalCurrencyExchangeRequest {
+ currency: string;
+ exchangeBaseUrl: string;
+ exchangeMasterPub: string;
+}
+
+export const codecForRemoveGlobalCurrencyExchangeRequest =
+ (): Codec<RemoveGlobalCurrencyExchangeRequest> =>
+ buildCodecForObject<RemoveGlobalCurrencyExchangeRequest>()
+ .property("currency", codecForString())
+ .property("exchangeBaseUrl", codecForString())
+ .property("exchangeMasterPub", codecForString())
+ .build("RemoveGlobalCurrencyExchangeRequest");
+
+export interface AddGlobalCurrencyAuditorRequest {
+ currency: string;
+ auditorBaseUrl: string;
+ auditorPub: string;
+}
+
+export const codecForAddGlobalCurrencyAuditorRequest =
+ (): Codec<AddGlobalCurrencyAuditorRequest> =>
+ buildCodecForObject<AddGlobalCurrencyAuditorRequest>()
+ .property("currency", codecForString())
+ .property("auditorBaseUrl", codecForString())
+ .property("auditorPub", codecForString())
+ .build("AddGlobalCurrencyAuditorRequest");
+
+export interface RemoveGlobalCurrencyAuditorRequest {
+ currency: string;
+ auditorBaseUrl: string;
+ auditorPub: string;
+}
+
+export const codecForRemoveGlobalCurrencyAuditorRequest =
+ (): Codec<RemoveGlobalCurrencyAuditorRequest> =>
+ buildCodecForObject<RemoveGlobalCurrencyAuditorRequest>()
+ .property("currency", codecForString())
+ .property("auditorBaseUrl", codecForString())
+ .property("auditorPub", codecForString())
+ .build("RemoveGlobalCurrencyAuditorRequest");
diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts
index 8a8f9737a..d1c8cc4d1 100644
--- a/packages/taler-wallet-cli/src/index.ts
+++ b/packages/taler-wallet-cli/src/index.ts
@@ -1308,17 +1308,117 @@ const currenciesCli = walletCli.subcommand("currencies", "currencies", {
});
currenciesCli
- .subcommand("show", "show", { help: "Show currencies." })
+ .subcommand("listGlobalAuditors", "list-global-auditors", {
+ help: "List global-currency auditors.",
+ })
.action(async (args) => {
await withWallet(args, async (wallet) => {
const currencies = await wallet.client.call(
- WalletApiOperation.ListCurrencies,
+ WalletApiOperation.ListGlobalCurrencyAuditors,
{},
);
console.log(JSON.stringify(currencies, undefined, 2));
});
});
+currenciesCli
+ .subcommand("listGlobalExchanges", "list-global-exchanges", {
+ help: "List global-currency exchanges.",
+ })
+ .action(async (args) => {
+ await withWallet(args, async (wallet) => {
+ const currencies = await wallet.client.call(
+ WalletApiOperation.ListGlobalCurrencyExchanges,
+ {},
+ );
+ console.log(JSON.stringify(currencies, undefined, 2));
+ });
+ });
+
+currenciesCli
+ .subcommand("addGlobalExchange", "add-global-exchange", {
+ help: "Add a global-currency exchange.",
+ })
+ .requiredOption("currency", ["--currency"], clk.STRING)
+ .requiredOption("exchangeBaseUrl", ["--url"], clk.STRING)
+ .requiredOption("exchangePub", ["--pub"], clk.STRING)
+ .action(async (args) => {
+ await withWallet(args, async (wallet) => {
+ const currencies = await wallet.client.call(
+ WalletApiOperation.AddGlobalCurrencyExchange,
+ {
+ currency: args.addGlobalExchange.currency,
+ exchangeBaseUrl: args.addGlobalExchange.exchangeBaseUrl,
+ exchangeMasterPub: args.addGlobalExchange.exchangePub,
+ },
+ );
+ console.log(JSON.stringify(currencies, undefined, 2));
+ });
+ });
+
+currenciesCli
+ .subcommand("removeGlobalExchange", "remove-global-exchange", {
+ help: "Remove a global-currency exchange.",
+ })
+ .requiredOption("currency", ["--currency"], clk.STRING)
+ .requiredOption("exchangeBaseUrl", ["--url"], clk.STRING)
+ .requiredOption("exchangePub", ["--pub"], clk.STRING)
+ .action(async (args) => {
+ await withWallet(args, async (wallet) => {
+ const currencies = await wallet.client.call(
+ WalletApiOperation.RemoveGlobalCurrencyExchange,
+ {
+ currency: args.removeGlobalExchange.currency,
+ exchangeBaseUrl: args.removeGlobalExchange.exchangeBaseUrl,
+ exchangeMasterPub: args.removeGlobalExchange.exchangePub,
+ },
+ );
+ console.log(JSON.stringify(currencies, undefined, 2));
+ });
+ });
+
+currenciesCli
+ .subcommand("addGlobalAuditor", "add-global-auditor", {
+ help: "Add a global-currency auditor.",
+ })
+ .requiredOption("currency", ["--currency"], clk.STRING)
+ .requiredOption("auditorBaseUrl", ["--url"], clk.STRING)
+ .requiredOption("auditorPub", ["--pub"], clk.STRING)
+ .action(async (args) => {
+ await withWallet(args, async (wallet) => {
+ const currencies = await wallet.client.call(
+ WalletApiOperation.AddGlobalCurrencyAuditor,
+ {
+ currency: args.addGlobalAuditor.currency,
+ auditorBaseUrl: args.addGlobalAuditor.auditorBaseUrl,
+ auditorPub: args.addGlobalAuditor.auditorPub,
+ },
+ );
+ console.log(JSON.stringify(currencies, undefined, 2));
+ });
+ });
+
+currenciesCli
+ .subcommand("removeGlobalAuditor", "remove-global-auditor", {
+ help: "Remove a global-currency auditor.",
+ })
+ .requiredOption("currency", ["--currency"], clk.STRING)
+ .requiredOption("auditorBaseUrl", ["--url"], clk.STRING)
+ .requiredOption("auditorPub", ["--pub"], clk.STRING)
+ .action(async (args) => {
+ await withWallet(args, async (wallet) => {
+ const currencies = await wallet.client.call(
+ WalletApiOperation.RemoveGlobalCurrencyAuditor,
+ {
+ currency: args.removeGlobalAuditor.currency,
+ auditorBaseUrl: args.removeGlobalAuditor.auditorBaseUrl,
+ auditorPub: args.removeGlobalAuditor.auditorPub,
+ },
+ );
+ console.log(JSON.stringify(currencies, undefined, 2));
+ });
+ });
+
advancedCli
.subcommand("clearDatabase", "clear-database", {
help: "Clear the database, irrevocable deleting all data in the wallet.",
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index f16600f5d..ceca24c82 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -74,6 +74,7 @@ import {
describeContents,
describeIndex,
describeStore,
+ describeStoreV2,
openDatabase,
} from "./util/query.js";
@@ -149,7 +150,7 @@ export const CURRENT_DB_CONFIG_KEY = "currentMainDbName";
* backwards-compatible way or object stores and indices
* are added.
*/
-export const WALLET_DB_MINOR_VERSION = 2;
+export const WALLET_DB_MINOR_VERSION = 3;
declare const symDbProtocolTimestamp: unique symbol;
@@ -2197,21 +2198,6 @@ export interface DbAuditorHandle {
auditorPub: string;
}
-// Work in progress for regional currencies
-export interface CurrencySettingsRecord {
- currency: string;
-
- globalScopeExchanges: DbExchangeHandle[];
-
- globalScopeAuditors: DbAuditorHandle[];
-
- // Used to decide which auditor to show the currency under
- // when multiple auditors apply.
- auditorPriority: string[];
-
- // Later, we might add stuff related to how the currency is rendered.
-}
-
export enum RefundGroupStatus {
Pending = 0x0100_0000,
Done = 0x0500_0000,
@@ -2299,18 +2285,55 @@ export function passthroughCodec<T>(): Codec<T> {
return codecForAny();
}
+export interface GlobalCurrencyAuditorRecord {
+ id?: number;
+ currency: string;
+ auditorBaseUrl: string;
+ auditorPub: string;
+}
+
+export interface GlobalCurrencyExchangeRecord {
+ id?: number;
+ currency: string;
+ exchangeBaseUrl: string;
+ exchangeMasterPub: string;
+}
+
/**
* Schema definition for the IndexedDB
* wallet database.
*/
export const WalletStoresV1 = {
- currencySettings: describeStore(
- "currencySettings",
- describeContents<CurrencySettingsRecord>({
- keyPath: ["currency"],
- }),
- {},
- ),
+ globalCurrencyAuditors: describeStoreV2({
+ recordCodec: passthroughCodec<GlobalCurrencyAuditorRecord>(),
+ storeName: "globalCurrencyAuditors",
+ keyPath: "id",
+ autoIncrement: true,
+ versionAdded: 3,
+ indexes: {
+ byCurrencyAndUrlAndPub: describeIndex("byCurrencyAndUrlAndPub", [
+ "currency",
+ "auditorBaseUrl",
+ "auditorPub",
+ ]),
+ },
+ }),
+ globalCurrencyExchanges: describeStoreV2({
+ recordCodec: passthroughCodec<GlobalCurrencyExchangeRecord>(),
+ storeName: "globalCurrencyExchanges",
+ keyPath: "id",
+ autoIncrement: true,
+ versionAdded: 3,
+ indexes: {
+ byCurrencyAndUrlAndPub: describeIndex(
+ "byCurrencyAndUrlAndPub",
+ ["currency", "exchangeBaseUrl", "exchangeMasterPub"],
+ {
+ unique: true,
+ },
+ ),
+ },
+ }),
coinAvailability: describeStore(
"coinAvailability",
describeContents<CoinAvailabilityRecord>({
diff --git a/packages/taler-wallet-core/src/util/query.ts b/packages/taler-wallet-core/src/util/query.ts
index 59c6ea2f5..efb1a3f42 100644
--- a/packages/taler-wallet-core/src/util/query.ts
+++ b/packages/taler-wallet-core/src/util/query.ts
@@ -822,7 +822,8 @@ export class DbAccess<StoreMap> {
const sn = this.db.objectStoreNames[i];
const swi = (this.stores as any)[sn] as StoreWithIndexes<any, any, any>;
if (!swi) {
- throw Error(`store metadata not available (${sn})`);
+ logger.warn(`store metadata not available (${sn})`);
+ continue;
}
storeNames.push(sn);
accessibleStores[sn] = swi;
diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts
index 2cbf693f5..c02862757 100644
--- a/packages/taler-wallet-core/src/wallet-api-types.ts
+++ b/packages/taler-wallet-core/src/wallet-api-types.ts
@@ -133,6 +133,12 @@ import {
GetExchangeResourcesRequest,
DeleteExchangeRequest,
GetExchangeResourcesResponse,
+ ListGlobalCurrencyExchangesResponse,
+ ListGlobalCurrencyAuditorsResponse,
+ AddGlobalCurrencyExchangeRequest,
+ AddGlobalCurrencyAuditorRequest,
+ RemoveGlobalCurrencyExchangeRequest,
+ RemoveGlobalCurrencyAuditorRequest,
} from "@gnu-taler/taler-util";
import {
AddBackupProviderRequest,
@@ -209,7 +215,6 @@ export enum WalletApiOperation {
GetBackupInfo = "getBackupInfo",
PrepareDeposit = "prepareDeposit",
GetVersion = "getVersion",
- ListCurrencies = "listCurrencies",
GenerateDepositGroupTxId = "generateDepositGroupTxId",
CreateDepositGroup = "createDepositGroup",
SetWalletDeviceId = "setWalletDeviceId",
@@ -243,6 +248,12 @@ export enum WalletApiOperation {
TestingInfiniteTransactionLoop = "testingInfiniteTransactionLoop",
GetExchangeResources = "getExchangeResources",
DeleteExchange = "deleteExchange",
+ ListGlobalCurrencyExchanges = "listExchangeCurrencyScope",
+ ListGlobalCurrencyAuditors = "listGlobalCurrencyAuditors",
+ AddGlobalCurrencyExchange = "addGlobalCurrencyExchange",
+ RemoveGlobalCurrencyExchange = "removeGlobalCurrencyExchange",
+ AddGlobalCurrencyAuditor = "addGlobalCurrencyAuditor",
+ RemoveGlobalCurrencyAuditor = "removeGlobalCurrencyAuditor",
}
// group: Initialization
@@ -550,6 +561,44 @@ export type StartRefundQueryOp = {
response: EmptyObject;
};
+// group: Global Currency management
+
+export type ListGlobalCurrencyAuditorsOp = {
+ op: WalletApiOperation.ListGlobalCurrencyAuditors;
+ request: EmptyObject;
+ response: ListGlobalCurrencyAuditorsResponse;
+};
+
+export type ListGlobalCurrencyExchangesOp = {
+ op: WalletApiOperation.ListGlobalCurrencyExchanges;
+ request: EmptyObject;
+ response: ListGlobalCurrencyExchangesResponse;
+};
+
+export type AddGlobalCurrencyExchangeOp = {
+ op: WalletApiOperation.AddGlobalCurrencyExchange;
+ request: AddGlobalCurrencyExchangeRequest;
+ response: EmptyObject;
+};
+
+export type AddGlobalCurrencyAuditorOp = {
+ op: WalletApiOperation.AddGlobalCurrencyAuditor;
+ request: AddGlobalCurrencyAuditorRequest;
+ response: EmptyObject;
+};
+
+export type RemoveGlobalCurrencyExchangeOp = {
+ op: WalletApiOperation.RemoveGlobalCurrencyExchange;
+ request: RemoveGlobalCurrencyExchangeRequest;
+ response: EmptyObject;
+};
+
+export type RemoveGlobalCurrencyAuditorOp = {
+ op: WalletApiOperation.RemoveGlobalCurrencyAuditor;
+ request: RemoveGlobalCurrencyAuditorRequest;
+ response: EmptyObject;
+};
+
// group: Rewards
/**
@@ -690,15 +739,6 @@ export type DeleteExchangeOp = {
response: EmptyObject;
};
-/**
- * List currencies known to the wallet.
- */
-export type ListCurrenciesOp = {
- op: WalletApiOperation.ListCurrencies;
- request: EmptyObject;
- response: WalletCurrencyInfo;
-};
-
export type GetCurrencySpecificationOp = {
op: WalletApiOperation.GetCurrencySpecification;
request: GetCurrencySpecificationRequest;
@@ -1171,7 +1211,6 @@ export type WalletOperations = {
[WalletApiOperation.AcceptReward]: AcceptTipOp;
[WalletApiOperation.StartRefundQueryForUri]: StartRefundQueryForUriOp;
[WalletApiOperation.StartRefundQuery]: StartRefundQueryOp;
- [WalletApiOperation.ListCurrencies]: ListCurrenciesOp;
[WalletApiOperation.GetWithdrawalDetailsForAmount]: GetWithdrawalDetailsForAmountOp;
[WalletApiOperation.GetWithdrawalDetailsForUri]: GetWithdrawalDetailsForUriOp;
[WalletApiOperation.AcceptBankIntegratedWithdrawal]: AcceptBankIntegratedWithdrawalOp;
@@ -1231,6 +1270,12 @@ export type WalletOperations = {
[WalletApiOperation.TestingInfiniteTransactionLoop]: any;
[WalletApiOperation.DeleteExchange]: DeleteExchangeOp;
[WalletApiOperation.GetExchangeResources]: GetExchangeResourcesOp;
+ [WalletApiOperation.ListGlobalCurrencyAuditors]: ListGlobalCurrencyAuditorsOp;
+ [WalletApiOperation.ListGlobalCurrencyExchanges]: ListGlobalCurrencyExchangesOp;
+ [WalletApiOperation.AddGlobalCurrencyAuditor]: AddGlobalCurrencyAuditorOp;
+ [WalletApiOperation.RemoveGlobalCurrencyAuditor]: RemoveGlobalCurrencyAuditorOp;
+ [WalletApiOperation.AddGlobalCurrencyExchange]: AddGlobalCurrencyExchangeOp;
+ [WalletApiOperation.RemoveGlobalCurrencyExchange]: RemoveGlobalCurrencyExchangeOp;
};
export type WalletCoreRequestType<
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index 3294e2a09..87c5aa995 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -39,6 +39,8 @@ import {
InitResponse,
KnownBankAccounts,
KnownBankAccountsInfo,
+ ListGlobalCurrencyAuditorsResponse,
+ ListGlobalCurrencyExchangesResponse,
Logger,
NotificationType,
PrepareWithdrawExchangeRequest,
@@ -64,6 +66,8 @@ import {
codecForAcceptPeerPullPaymentRequest,
codecForAcceptTipRequest,
codecForAddExchangeRequest,
+ codecForAddGlobalCurrencyAuditorRequest,
+ codecForAddGlobalCurrencyExchangeRequest,
codecForAddKnownBankAccounts,
codecForAny,
codecForApplyDevExperiment,
@@ -104,6 +108,8 @@ import {
codecForPrepareRewardRequest,
codecForPrepareWithdrawExchangeRequest,
codecForRecoverStoredBackupRequest,
+ codecForRemoveGlobalCurrencyAuditorRequest,
+ codecForRemoveGlobalCurrencyExchangeRequest,
codecForResumeTransaction,
codecForRetryTransactionRequest,
codecForSetCoinSuspendedRequest,
@@ -200,7 +206,6 @@ import {
lookupExchangeByUri,
updateExchangeFromUrlHandler,
} from "./operations/exchanges.js";
-import { getMerchantInfo } from "./operations/merchants.js";
import {
computePayMerchantTransactionState,
computeRefundTransactionState,
@@ -302,7 +307,7 @@ import {
GetReadOnlyAccess,
GetReadWriteAccess,
} from "./util/query.js";
-import { TimerAPI, TimerGroup, timer } from "./util/timer.js";
+import { TimerAPI, TimerGroup } from "./util/timer.js";
import {
WALLET_BANK_CONVERSION_API_PROTOCOL_VERSION,
WALLET_BANK_INTEGRATION_PROTOCOL_VERSION,
@@ -1328,13 +1333,6 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
await setWalletDeviceId(ws, req.walletDeviceId);
return {};
}
- case WalletApiOperation.ListCurrencies: {
- // FIXME: Remove / change to scoped currency approach.
- return {
- trustedAuditors: [],
- trustedExchanges: [],
- };
- }
case WalletApiOperation.TestCrypto: {
return await ws.cryptoApi.hashString({ str: "hello world" });
}
@@ -1349,6 +1347,108 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
const dbDump = await exportDb(ws.idb);
return dbDump;
}
+ case WalletApiOperation.ListGlobalCurrencyExchanges: {
+ const resp: ListGlobalCurrencyExchangesResponse = {
+ exchanges: [],
+ };
+ await ws.db.runReadOnlyTx(["globalCurrencyExchanges"], async (tx) => {
+ const gceList = await tx.globalCurrencyExchanges.iter().toArray();
+ for (const gce of gceList) {
+ resp.exchanges.push({
+ currency: gce.currency,
+ exchangeBaseUrl: gce.exchangeBaseUrl,
+ exchangeMasterPub: gce.exchangeMasterPub,
+ });
+ }
+ });
+ return resp;
+ }
+ case WalletApiOperation.ListGlobalCurrencyAuditors: {
+ const resp: ListGlobalCurrencyAuditorsResponse = {
+ auditors: [],
+ };
+ await ws.db.runReadOnlyTx(["globalCurrencyAuditors"], async (tx) => {
+ const gcaList = await tx.globalCurrencyAuditors.iter().toArray();
+ for (const gca of gcaList) {
+ resp.auditors.push({
+ currency: gca.currency,
+ auditorBaseUrl: gca.auditorBaseUrl,
+ auditorPub: gca.auditorPub,
+ });
+ }
+ });
+ return resp;
+ }
+ case WalletApiOperation.AddGlobalCurrencyExchange: {
+ const req = codecForAddGlobalCurrencyExchangeRequest().decode(payload);
+ await ws.db.runReadWriteTx(["globalCurrencyExchanges"], async (tx) => {
+ const key = [req.currency, req.exchangeBaseUrl, req.exchangeMasterPub];
+ const existingRec =
+ await tx.globalCurrencyExchanges.indexes.byCurrencyAndUrlAndPub.get(
+ key,
+ );
+ if (existingRec) {
+ return;
+ }
+ await tx.globalCurrencyExchanges.add({
+ currency: req.currency,
+ exchangeBaseUrl: req.exchangeBaseUrl,
+ exchangeMasterPub: req.exchangeMasterPub,
+ });
+ });
+ return {};
+ }
+ case WalletApiOperation.RemoveGlobalCurrencyExchange: {
+ const req = codecForRemoveGlobalCurrencyExchangeRequest().decode(payload);
+ await ws.db.runReadWriteTx(["globalCurrencyExchanges"], async (tx) => {
+ const key = [req.currency, req.exchangeBaseUrl, req.exchangeMasterPub];
+ const existingRec =
+ await tx.globalCurrencyExchanges.indexes.byCurrencyAndUrlAndPub.get(
+ key,
+ );
+ if (!existingRec) {
+ return;
+ }
+ checkDbInvariant(!!existingRec.id);
+ await tx.globalCurrencyExchanges.delete(existingRec.id);
+ });
+ return {};
+ }
+ case WalletApiOperation.AddGlobalCurrencyAuditor: {
+ const req = codecForAddGlobalCurrencyAuditorRequest().decode(payload);
+ await ws.db.runReadWriteTx(["globalCurrencyAuditors"], async (tx) => {
+ const key = [req.currency, req.auditorBaseUrl, req.auditorPub];
+ const existingRec =
+ await tx.globalCurrencyAuditors.indexes.byCurrencyAndUrlAndPub.get(
+ key,
+ );
+ if (existingRec) {
+ return;
+ }
+ await tx.globalCurrencyAuditors.add({
+ currency: req.currency,
+ auditorBaseUrl: req.auditorBaseUrl,
+ auditorPub: req.auditorPub,
+ });
+ });
+ return {};
+ }
+ case WalletApiOperation.RemoveGlobalCurrencyAuditor: {
+ const req = codecForRemoveGlobalCurrencyAuditorRequest().decode(payload);
+ await ws.db.runReadWriteTx(["globalCurrencyAuditors"], async (tx) => {
+ const key = [req.currency, req.auditorBaseUrl, req.auditorPub];
+ const existingRec =
+ await tx.globalCurrencyAuditors.indexes.byCurrencyAndUrlAndPub.get(
+ key,
+ );
+ if (!existingRec) {
+ return;
+ }
+ checkDbInvariant(!!existingRec.id);
+ await tx.globalCurrencyAuditors.delete(existingRec.id);
+ });
+ return {};
+ }
case WalletApiOperation.ImportDb: {
const req = codecForImportDbRequest().decode(payload);
await importDb(ws.db.idbHandle(), req.dump);