taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit e2d5772e4605c8b8e94376c39060c8aa97df6a4f
parent 2560bde8fab087289af3aaafa45a9db83ac983c5
Author: Florian Dold <florian@dold.me>
Date:   Thu, 27 Nov 2025 23:35:12 +0100

wallet-core: implement shopping url and p2p disabled, remove deprecated flags

Diffstat:
Mpackages/taler-harness/src/harness/harness.ts | 62++++++++++++++++++++++++++++++++++----------------------------
Mpackages/taler-harness/src/integrationtests/testrunner.ts | 2++
Mpackages/taler-util/src/types-taler-exchange.ts | 3+++
Mpackages/taler-util/src/types-taler-wallet.ts | 20+++++++-------------
Mpackages/taler-wallet-core/src/balance.ts | 60+++++++++++++++++++++++++++++++++++++++++++++++++-----------
Mpackages/taler-wallet-core/src/coinSelection.ts | 20++++++++++----------
Mpackages/taler-wallet-core/src/db.ts | 10+++++-----
Mpackages/taler-wallet-core/src/deposits.ts | 10+++++-----
Mpackages/taler-wallet-core/src/dev-experiments.ts | 9+++++++++
Mpackages/taler-wallet-core/src/exchanges.ts | 12+++++++++---
Mpackages/taler-wallet-core/src/instructedAmountConversion.ts | 4++--
Mpackages/taler-wallet-core/src/wallet.ts | 10+++++++---
Mpackages/taler-wallet-core/src/withdraw.ts | 12++++++------
13 files changed, 148 insertions(+), 86 deletions(-)

diff --git a/packages/taler-harness/src/harness/harness.ts b/packages/taler-harness/src/harness/harness.ts @@ -1633,7 +1633,7 @@ export class ExchangeService implements ExchangeServiceInterface { * Update keys signing the keys generated by the security module * with the offline signing key. */ - async keyup(): Promise<void> { + async keyup(opts: { skipGlobalFees?: boolean } = {}): Promise<void> { await runCommand( this.globalState, "exchange-offline", @@ -1705,31 +1705,33 @@ export class ExchangeService implements ExchangeServiceInterface { } } - await runCommand( - this.globalState, - "exchange-offline", - "taler-exchange-offline", - [ - "-c", - this.configFilename, - "global-fee", - // year - "now", - // history fee - `${this.exchangeConfig.currency}:0.01`, - // account fee - `${this.exchangeConfig.currency}:0.01`, - // purse fee - `${this.exchangeConfig.currency}:0.00`, - // purse timeout - "1h", - // history expiration - "1year", - // free purses per account - "5", - "upload", - ], - ); + if (!opts.skipGlobalFees) { + await runCommand( + this.globalState, + "exchange-offline", + "taler-exchange-offline", + [ + "-c", + this.configFilename, + "global-fee", + // year + "now", + // history fee + `${this.exchangeConfig.currency}:0.01`, + // account fee + `${this.exchangeConfig.currency}:0.01`, + // purse fee + `${this.exchangeConfig.currency}:0.00`, + // purse timeout + "1h", + // history expiration + "1year", + // free purses per account + "5", + "upload", + ], + ); + } } async revokeDenomination(denomPubHash: string) { @@ -1857,7 +1859,11 @@ export class ExchangeService implements ExchangeServiceInterface { } async start( - opts: { skipDbinit?: boolean; skipKeyup?: boolean } = {}, + opts: { + skipDbinit?: boolean; + skipKeyup?: boolean; + skipGlobalFees?: boolean; + } = {}, ): Promise<void> { if (this.isRunning()) { throw Error("exchange is already running"); @@ -1910,7 +1916,7 @@ export class ExchangeService implements ExchangeServiceInterface { const skipKeyup = opts.skipKeyup ?? false; if (!skipKeyup) { - await this.keyup(); + await this.keyup({ skipGlobalFees: opts.skipGlobalFees }); } else { logger.info("skipping keyup"); } diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts b/packages/taler-harness/src/integrationtests/testrunner.ts @@ -178,6 +178,7 @@ import { runWalletDd48Test } from "./test-wallet-dd48.js"; import { runWalletDenomExpireTest } from "./test-wallet-denom-expire.js"; import { runWalletDevExperimentsTest } from "./test-wallet-dev-experiments.js"; import { runWalletDevexpFakeprotoverTest } from "./test-wallet-devexp-fakeprotover.js"; +import { runWalletExchangeFeaturesTest } from "./test-wallet-exchange-features.js"; import { runWalletExchangeMigrationExistingTest } from "./test-wallet-exchange-migration-existing.js"; import { runWalletExchangeMigrationTest } from "./test-wallet-exchange-migration.js"; import { runWalletExchangeUpdateTest } from "./test-wallet-exchange-update.js"; @@ -403,6 +404,7 @@ const allTests: TestMainFunction[] = [ runDonauKeychangeTest, runTopsAmlPdfTest, runMerchantWireTest, + runWalletExchangeFeaturesTest, ]; export interface TestRunSpec { diff --git a/packages/taler-util/src/types-taler-exchange.ts b/packages/taler-util/src/types-taler-exchange.ts @@ -479,6 +479,9 @@ export interface ExchangeKeysResponse { reserve_closing_delay: TalerProtocolDuration; + /** + * Global fees, applicable only to p2p payments. + */ global_fees: GlobalFees[]; accounts: ExchangeWireAccount[]; diff --git a/packages/taler-util/src/types-taler-wallet.ts b/packages/taler-util/src/types-taler-wallet.ts @@ -359,22 +359,18 @@ export interface WalletBalance { pendingIncoming: AmountString; pendingOutgoing: AmountString; + flags: BalanceFlag[]; + /** - * Does the balance for this currency have a pending - * transaction? - * - * @deprecated use flags and pendingIncoming/pendingOutgoing instead + * Available URLs for pages that list + * where money in this scope can be spent. */ - hasPendingTransactions: boolean; + shoppingUrls?: string[]; /** - * Is there a transaction that requires user input? - * - * @deprecated use flags instead + * Are p2p payments disabled for this scope? */ - requiresUserInput: boolean; - - flags: BalanceFlag[]; + disablePeerPayments?: boolean; } export const codecForScopeInfoGlobal = (): Codec<ScopeInfoGlobal> => @@ -585,10 +581,8 @@ export const codecForBalance = (): Codec<WalletBalance> => buildCodecForObject<WalletBalance>() .property("scopeInfo", codecForAny()) // FIXME .property("available", codecForAmountString()) - .property("hasPendingTransactions", codecForBoolean()) .property("pendingIncoming", codecForAmountString()) .property("pendingOutgoing", codecForAmountString()) - .property("requiresUserInput", codecForBoolean()) .property("flags", codecForAny()) // FIXME .build("Balance"); diff --git a/packages/taler-wallet-core/src/balance.ts b/packages/taler-wallet-core/src/balance.ts @@ -87,8 +87,8 @@ import { } from "./db.js"; import { checkExchangeInScopeTx, + getExchangeDetailsInTx, getExchangeScopeInfo, - getExchangeWireDetailsInTx, } from "./exchanges.js"; import { getDenomInfo, WalletExecutionContext } from "./wallet.js"; @@ -105,6 +105,8 @@ interface WalletBalance { flagIncomingKyc: boolean; flagIncomingConfirmation: boolean; flagOutgoingKyc: boolean; + disablePeerPayments: boolean; + shoppingUrls: Set<string>; } function computeRefreshGroupAvailableAmountForExchanges( @@ -203,6 +205,8 @@ class BalancesStore { flagIncomingConfirmation: false, flagIncomingKyc: false, flagOutgoingKyc: false, + disablePeerPayments: false, + shoppingUrls: new Set(), }; } return this.balanceStore[balanceKey]; @@ -212,6 +216,23 @@ class BalancesStore { await this.initBalance(currency, exchangeBaseUrl); } + async setPeerPaymentsDisabled( + currency: string, + exchangeBaseUrl: string, + ): Promise<void> { + const b = await this.initBalance(currency, exchangeBaseUrl); + b.disablePeerPayments = true; + } + + async addShoppingUrl( + currency: string, + exchangeBaseUrl: string, + shoppingUrl: string, + ): Promise<void> { + const b = await this.initBalance(currency, exchangeBaseUrl); + b.shoppingUrls.add(shoppingUrl); + } + async addAvailable( currency: string, exchangeBaseUrl: string, @@ -311,16 +332,26 @@ class BalancesStore { if (v.flagOutgoingKyc) { flags.push(BalanceFlag.OutgoingKyc); } + let shoppingUrls: string[]; + if (this.wex.ws.devExperimentState.fakeShoppingUrl != null) { + shoppingUrls = [this.wex.ws.devExperimentState.fakeShoppingUrl]; + } else { + shoppingUrls = [...v.shoppingUrls]; + } + let disablePeerPayments: boolean; + if (this.wex.ws.devExperimentState.flagDisablePeerPayments) { + disablePeerPayments = true; + } else { + disablePeerPayments = v.disablePeerPayments; + } balancesResponse.balances.push({ scopeInfo: v.scopeInfo, available: Amounts.stringify(v.available), pendingIncoming: Amounts.stringify(v.pendingIncoming), pendingOutgoing: Amounts.stringify(v.pendingOutgoing), - // FIXME: This field is basically not implemented, do we even need it? - hasPendingTransactions: false, - // FIXME: This field is basically not implemented, do we even need it? - requiresUserInput: false, flags, + shoppingUrls, + disablePeerPayments, }); }); return balancesResponse; @@ -368,9 +399,19 @@ export async function getBalancesInsideTransaction( ex.entryStatus === ExchangeEntryDbRecordStatus.Used || ex.tosAcceptedTimestamp != null ) { - const det = await getExchangeWireDetailsInTx(tx, ex.baseUrl); + const det = await getExchangeDetailsInTx(tx, ex.baseUrl); if (det) { await balanceStore.addZero(det.currency, ex.baseUrl); + if (ex.peerPaymentsDisabled) { + await balanceStore.setPeerPaymentsDisabled(det.currency, ex.baseUrl); + } + if (det.shoppingUrl) { + await balanceStore.addShoppingUrl( + det.currency, + ex.baseUrl, + det.shoppingUrl, + ); + } } } }); @@ -851,10 +892,7 @@ export async function getPaymentBalanceDetailsInTx( continue; } - const wireDetails = await getExchangeWireDetailsInTx( - tx, - ca.exchangeBaseUrl, - ); + const wireDetails = await getExchangeDetailsInTx(tx, ca.exchangeBaseUrl); if (!wireDetails) { continue; } @@ -974,7 +1012,7 @@ export async function getBalanceDetail( async (tx) => { const allExchanges = await tx.exchanges.iter().toArray(); for (const e of allExchanges) { - const details = await getExchangeWireDetailsInTx(tx, e.baseUrl); + const details = await getExchangeDetailsInTx(tx, e.baseUrl); if (!details || req.currency !== details.currency) { continue; } diff --git a/packages/taler-wallet-core/src/coinSelection.ts b/packages/taler-wallet-core/src/coinSelection.ts @@ -65,8 +65,8 @@ import { getAutoRefreshExecuteThreshold } from "./common.js"; import { DenominationRecord, WalletDbReadOnlyTransaction } from "./db.js"; import { checkExchangeInScopeTx, - ExchangeWireDetails, - getExchangeWireDetailsInTx, + ExchangeDetails, + getExchangeDetailsInTx, } from "./exchanges.js"; import { getDenomInfo, WalletExecutionContext } from "./wallet.js"; @@ -593,7 +593,7 @@ export async function reportInsufficientBalanceDetails( continue; } let missingGlobalFees = false; - const exchWire = await getExchangeWireDetailsInTx(tx, exch.baseUrl); + const exchWire = await getExchangeDetailsInTx(tx, exch.baseUrl); if (!exchWire) { // No wire details about the exchange known, skip! continue; @@ -840,7 +840,7 @@ export type AvailableCoinsOfDenom = DenominationInfo & { export function findMatchingWire( wireMethod: string, depositPaytoUri: string | undefined, - exchangeWireDetails: ExchangeWireDetails, + exchangeWireDetails: ExchangeDetails, ): | { ok: true; wireFee: AmountJson } | { ok: false; accountRestrictions: Record<string, AccountRestriction[]> } @@ -900,7 +900,7 @@ export function findMatchingWire( } function checkExchangeAccepted( - exchangeDetails: ExchangeWireDetails, + exchangeDetails: ExchangeDetails, exchangeRestrictions: ExchangeRestrictionSpec | undefined, ): boolean { if (!exchangeRestrictions) { @@ -972,7 +972,7 @@ async function selectPayCandidates( Record<string, AccountRestriction[]> > = {}; for (const exchange of exchanges) { - const exchangeDetails = await getExchangeWireDetailsInTx( + const exchangeDetails = await getExchangeDetailsInTx( tx, exchange.baseUrl, ); @@ -1220,7 +1220,7 @@ export function emptyTallyForPeerPayment( } function getGlobalFees( - wireDetails: ExchangeWireDetails, + wireDetails: ExchangeDetails, ): ExchangeGlobalFees | undefined { const now = AbsoluteTime.now(); for (let gf of wireDetails.globalFees) { @@ -1253,7 +1253,7 @@ async function internalSelectPeerCoins( ] >, req: PeerCoinSelectionRequest, - exch: ExchangeWireDetails, + exch: ExchangeDetails, includePendingCoins: boolean, ): Promise< | { sel: SelResult; tally: CoinSelectionTally; resCoins: SelectedCoin[] } @@ -1340,7 +1340,7 @@ export async function selectPeerCoinsInTx( if (exch.detailsPointer?.currency !== currency) { continue; } - const exchWire = await getExchangeWireDetailsInTx(tx, exch.baseUrl); + const exchWire = await getExchangeDetailsInTx(tx, exch.baseUrl); if (!exchWire) { continue; } @@ -1603,7 +1603,7 @@ export async function getMaxPeerPushDebitAmount( if (exch.detailsPointer?.currency !== currency) { continue; } - const exchWire = await getExchangeWireDetailsInTx(tx, exch.baseUrl); + const exchWire = await getExchangeDetailsInTx(tx, exch.baseUrl); if (!exchWire) { continue; } diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts @@ -56,6 +56,7 @@ import { HashCodeString, Logger, MailboxConfiguration, + MailboxMessageRecord, MerchantContractTokenDetails, MerchantContractTokenKind, RefreshReason, @@ -80,7 +81,6 @@ import { j2s, stringToBytes, stringifyScopeInfo, - MailboxMessageRecord, } from "@gnu-taler/taler-util"; import { DbRetryInfo, TaskIdentifiers } from "./common.js"; import { @@ -640,6 +640,8 @@ export interface ExchangeDetailsRecord { reserveClosingDelay: TalerProtocolDuration; + shoppingUrl?: string; + /** * Fees for exchange services */ @@ -1099,8 +1101,6 @@ export interface TokenRecord extends TokenFamilyInfo { blindingKey: string; } - - /** * Slate, a blank slice of rock cut for use as a writing surface, * also the database representation of a token before being @@ -1652,7 +1652,7 @@ export type ConfigRecord = | { key: ConfigRecordKey.TestLoopTx; value: number } | { key: ConfigRecordKey.LastInitInfo; value: DbProtocolTimestamp } | { key: ConfigRecordKey.MaterializedTransactionsVersion; value: number } - | { key: ConfigRecordKey.DonauConfig; value: DonauConfig } + | { key: ConfigRecordKey.DonauConfig; value: DonauConfig }; export interface WalletBackupConfState { deviceId: string; @@ -3206,7 +3206,7 @@ export const WalletStoresV1 = { indexes: {}, versionAdded: 24, }), - refreshGroups: describeStore( + refreshGroups: describeStore( "refreshGroups", describeContents<RefreshGroupRecord>({ keyPath: "refreshGroupId", diff --git a/packages/taler-wallet-core/src/deposits.ts b/packages/taler-wallet-core/src/deposits.ts @@ -120,7 +120,7 @@ import { ReadyExchangeSummary, checkExchangeInScopeTx, fetchFreshExchange, - getExchangeWireDetailsInTx, + getExchangeDetailsInTx, getExchangeWireFee, getScopeForAllExchanges, } from "./exchanges.js"; @@ -245,7 +245,7 @@ export class DepositTransactionContext implements TransactionContext { break; } const plainCreditPaytoUris: string[] = []; - const exchangeWire = await getExchangeWireDetailsInTx( + const exchangeWire = await getExchangeDetailsInTx( tx, dg.kycInfo.exchangeBaseUrl, ); @@ -2034,7 +2034,7 @@ async function getExchangesForDeposit( await wex.db.runAllStoresReadOnlyTx({}, async (tx) => { const allExchanges = await tx.exchanges.iter().toArray(); for (const e of allExchanges) { - const details = await getExchangeWireDetailsInTx(tx, e.baseUrl); + const details = await getExchangeDetailsInTx(tx, e.baseUrl); if (!details) { logger.trace(`skipping ${e.baseUrl}, no details`); continue; @@ -2483,7 +2483,7 @@ async function getCounterpartyEffectiveDepositAmount( } for (const exchangeUrl of exchangeSet.values()) { - const exchangeDetails = await getExchangeWireDetailsInTx( + const exchangeDetails = await getExchangeDetailsInTx( tx, exchangeUrl, ); @@ -2551,7 +2551,7 @@ async function getTotalFeesForDepositAmount( } for (const exchangeUrl of exchangeSet.values()) { - const exchangeDetails = await getExchangeWireDetailsInTx( + const exchangeDetails = await getExchangeDetailsInTx( tx, exchangeUrl, ); diff --git a/packages/taler-wallet-core/src/dev-experiments.ts b/packages/taler-wallet-core/src/dev-experiments.ts @@ -301,6 +301,15 @@ export async function applyDevExperiment( wex.ws.devExperimentState.pretendPostWopFailed = v; return; } + case "flag-disable-peer-payments": { + wex.ws.devExperimentState.flagDisablePeerPayments = getValFlag(parsedUri); + return; + } + case "fake-shopping-url": { + const url = parsedUri.query?.get("url") ?? undefined; + wex.ws.devExperimentState.fakeShoppingUrl = url; + return; + } case "flag-confirm-pay-no-wait": { wex.ws.devExperimentState.flagConfirmPayNoWait = getValFlag(parsedUri); return; diff --git a/packages/taler-wallet-core/src/exchanges.ts b/packages/taler-wallet-core/src/exchanges.ts @@ -545,7 +545,7 @@ async function makeExchangeListItem( return listItem; } -export interface ExchangeWireDetails { +export interface ExchangeDetails { currency: string; masterPublicKey: EddsaPublicKeyString; wireInfo: WireInfo; @@ -553,12 +553,13 @@ export interface ExchangeWireDetails { auditors: ExchangeAuditor[]; globalFees: ExchangeGlobalFees[]; reserveClosingDelay: TalerProtocolDuration; + shoppingUrl: string | undefined; } -export async function getExchangeWireDetailsInTx( +export async function getExchangeDetailsInTx( tx: WalletDbReadOnlyTransaction<["exchanges", "exchangeDetails"]>, exchangeBaseUrl: string, -): Promise<ExchangeWireDetails | undefined> { +): Promise<ExchangeDetails | undefined> { const det = await getExchangeRecordsInternal(tx, exchangeBaseUrl); if (!det) { return undefined; @@ -571,6 +572,7 @@ export async function getExchangeWireDetailsInTx( auditors: det.auditors, globalFees: det.globalFees, reserveClosingDelay: det.reserveClosingDelay, + shoppingUrl: det.shoppingUrl, }; } @@ -900,6 +902,7 @@ async function provideExchangeRecordInTx( return { exchange, exchangeDetails }; } +// FIXME: Get rid of this, return response directly instead. export interface ExchangeKeysDownloadSuccessResult { baseUrl: string; masterPublicKey: string; @@ -920,6 +923,7 @@ export interface ExchangeKeysDownloadSuccessResult { hardLimits: AccountLimit[] | undefined; zeroLimits: ZeroLimitedOperation[] | undefined; bankComplianceLanguage: string | undefined; + shoppingUrl: string | undefined; } export type ExchangeKeysDownloadResult = @@ -1112,6 +1116,7 @@ async function downloadExchangeKeysInfo( zeroLimits: exchangeKeysResponseUnchecked.zero_limits, bankComplianceLanguage: exchangeKeysResponseUnchecked.bank_compliance_language, + shoppingUrl: exchangeKeysResponseUnchecked.shopping_url, }; return { type: "ok", @@ -1993,6 +1998,7 @@ export async function updateExchangeFromUrlHandler( hardLimits: keysInfo.hardLimits, zeroLimits: keysInfo.zeroLimits, bankComplianceLanguage: keysInfo.bankComplianceLanguage, + shoppingUrl: keysInfo.shoppingUrl, }; r.noFees = noFees; r.peerPaymentsDisabled = peerPaymentsDisabled; diff --git a/packages/taler-wallet-core/src/instructedAmountConversion.ts b/packages/taler-wallet-core/src/instructedAmountConversion.ts @@ -29,7 +29,7 @@ import { strcmp, } from "@gnu-taler/taler-util"; import { DenominationRecord, timestampProtocolFromDb } from "./db.js"; -import { getExchangeWireDetailsInTx } from "./exchanges.js"; +import { getExchangeDetailsInTx } from "./exchanges.js"; import { WalletExecutionContext } from "./wallet.js"; export interface CoinInfo { @@ -144,7 +144,7 @@ async function getAvailableCoins( filters.exchanges ?? databaseExchanges.map((e) => e.baseUrl); for (const exchangeBaseUrl of filteredExchanges) { - const exchangeDetails = await getExchangeWireDetailsInTx( + const exchangeDetails = await getExchangeDetailsInTx( tx, exchangeBaseUrl, ); diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts @@ -333,9 +333,9 @@ import { fetchFreshExchange, forgetExchangeTermsOfService, getExchangeDetailedInfo, + getExchangeDetailsInTx, getExchangeResources, getExchangeTos, - getExchangeWireDetailsInTx, handleStartExchangeWalletKyc, handleTestingPlanMigrateExchangeBaseUrl, handleTestingWaitExchangeState, @@ -1455,7 +1455,7 @@ async function handleGetDepositWireTypes( async (tx) => { const exchanges = await tx.exchanges.getAll(); for (const exchange of exchanges) { - const det = await getExchangeWireDetailsInTx(tx, exchange.baseUrl); + const det = await getExchangeDetailsInTx(tx, exchange.baseUrl); if (!det) { continue; } @@ -1523,7 +1523,7 @@ async function handleGetDepositWireTypesForCurrency( async (tx) => { const exchanges = await tx.exchanges.getAll(); for (const exchange of exchanges) { - const det = await getExchangeWireDetailsInTx(tx, exchange.baseUrl); + const det = await getExchangeDetailsInTx(tx, exchange.baseUrl); if (!det) { continue; } @@ -2864,6 +2864,10 @@ export interface DevExperimentState { } >; + fakeShoppingUrl?: string; + + flagDisablePeerPayments?: boolean; + blockPayResponse?: boolean; /** Migration test for confirmPay */ diff --git a/packages/taler-wallet-core/src/withdraw.ts b/packages/taler-wallet-core/src/withdraw.ts @@ -164,12 +164,12 @@ import { } from "./denominations.js"; import { BalanceThresholdCheckResult, - ExchangeWireDetails, + ExchangeDetails, ReadyExchangeSummary, checkIncomingAmountLegalUnderKycBalanceThreshold, fetchFreshExchange, getExchangePaytoUri, - getExchangeWireDetailsInTx, + getExchangeDetailsInTx, getPreferredExchangeForCurrency, getScopeForAllExchanges, handleStartExchangeWalletKyc, @@ -279,7 +279,7 @@ function buildTransactionForBankIntegratedWithdraw( function buildTransactionForManualWithdraw( wg: WithdrawalGroupRecord, - exchangeDetails: ExchangeWireDetails | undefined, + exchangeDetails: ExchangeDetails | undefined, scopes: ScopeInfo[], ort: OperationRetryRecord | undefined, kycDetails: TxKycDetails | undefined, @@ -380,7 +380,7 @@ export class WithdrawTransactionContext implements TransactionContext { const exchangeDetails = exchangeBaseUrl == null ? undefined - : await getExchangeWireDetailsInTx(tx, exchangeBaseUrl); + : await getExchangeDetailsInTx(tx, exchangeBaseUrl); const scopes = await getScopeForAllExchanges( tx, !exchangeDetails ? [] : [exchangeDetails.exchangeBaseUrl], @@ -2089,7 +2089,7 @@ export async function updateWithdrawalDenomsForExchange( const res = await wex.db.runReadOnlyTx( { storeNames: ["exchanges", "exchangeDetails", "denominations"] }, async (tx) => { - const exchangeDetails = await getExchangeWireDetailsInTx( + const exchangeDetails = await getExchangeDetailsInTx( tx, exchangeBaseUrl, ); @@ -3151,7 +3151,7 @@ export async function getFundingPaytoUris( withdrawalGroup.instructedAmount !== undefined, "can't get funding uri from uninitialized wg", ); - const exchangeDetails = await getExchangeWireDetailsInTx( + const exchangeDetails = await getExchangeDetailsInTx( tx, withdrawalGroup.exchangeBaseUrl, );