diff options
author | Florian Dold <florian@dold.me> | 2024-01-22 13:49:11 +0100 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2024-01-22 13:49:11 +0100 |
commit | 88851f45403c1995c973bcae7ad2976db3c430c7 (patch) | |
tree | 8a7bbd228b7b647a4ddc22bff732b71e0c6be276 /packages/taler-wallet-core | |
parent | d32731fc7526df18361aae6aa5541e10cf6b41aa (diff) | |
download | wallet-core-88851f45403c1995c973bcae7ad2976db3c430c7.tar.xz |
wallet-core: implement DD45 global currency management requests
Diffstat (limited to 'packages/taler-wallet-core')
-rw-r--r-- | packages/taler-wallet-core/src/db.ts | 69 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/util/query.ts | 3 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/wallet-api-types.ts | 67 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/wallet.ts | 118 |
4 files changed, 213 insertions, 44 deletions
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); |