diff options
Diffstat (limited to 'packages/taler-wallet-core/src/exchanges.ts')
-rw-r--r-- | packages/taler-wallet-core/src/exchanges.ts | 142 |
1 files changed, 69 insertions, 73 deletions
diff --git a/packages/taler-wallet-core/src/exchanges.ts b/packages/taler-wallet-core/src/exchanges.ts index 932df721d..a26b3f5ca 100644 --- a/packages/taler-wallet-core/src/exchanges.ts +++ b/packages/taler-wallet-core/src/exchanges.ts @@ -128,7 +128,7 @@ import { DbReadOnlyTransaction } from "./query.js"; import { createRecoupGroup } from "./recoup.js"; import { createRefreshGroup } from "./refresh.js"; import { WALLET_EXCHANGE_PROTOCOL_VERSION } from "./versions.js"; -import { InternalWalletState } from "./wallet.js"; +import { InternalWalletState, WalletExecutionContext } from "./wallet.js"; const logger = new Logger("exchanges.ts"); @@ -147,10 +147,10 @@ interface ExchangeTosDownloadResult { } async function downloadExchangeWithTermsOfService( + wex: WalletExecutionContext, exchangeBaseUrl: string, http: HttpRequestLibrary, timeout: Duration, - cancellationToken: CancellationToken, acceptFormat: string, acceptLanguage: string | undefined, ): Promise<ExchangeTosDownloadResult> { @@ -170,7 +170,7 @@ async function downloadExchangeWithTermsOfService( const resp = await http.fetch(reqUrl.href, { headers, timeout, - cancellationToken, + cancellationToken: wex.cancellationToken, }); const tosText = await readSuccessResponseTextOrThrow(resp); const tosEtag = resp.headers.get("etag") || "unknown"; @@ -344,10 +344,10 @@ export async function getExchangeWireDetailsInTx( } export async function lookupExchangeByUri( - ws: InternalWalletState, + wex: WalletExecutionContext, req: GetExchangeEntryByUrlRequest, ): Promise<ExchangeListItem> { - return await ws.db.runReadOnlyTx( + return await wex.db.runReadOnlyTx( [ "exchanges", "exchangeDetails", @@ -381,10 +381,10 @@ export async function lookupExchangeByUri( * Mark the current ToS version as accepted by the user. */ export async function acceptExchangeTermsOfService( - ws: InternalWalletState, + wex: WalletExecutionContext, exchangeBaseUrl: string, ): Promise<void> { - const notif = await ws.db.runReadWriteTx( + const notif = await wex.db.runReadWriteTx( ["exchangeDetails", "exchanges"], async (tx) => { const exch = await tx.exchanges.get(exchangeBaseUrl); @@ -407,7 +407,7 @@ export async function acceptExchangeTermsOfService( }, ); if (notif) { - ws.notify(notif); + wex.ws.notify(notif); } } @@ -449,7 +449,7 @@ export async function forgetExchangeTermsOfService( * Throw an exception if they are invalid. */ async function validateWireInfo( - ws: InternalWalletState, + wex: WalletExecutionContext, versionCurrent: number, wireInfo: ExchangeKeysDownloadResult, masterPublicKey: string, @@ -457,10 +457,10 @@ async function validateWireInfo( for (const a of wireInfo.accounts) { logger.trace("validating exchange acct"); let isValid = false; - if (ws.config.testing.insecureTrustExchange) { + if (wex.ws.config.testing.insecureTrustExchange) { isValid = true; } else { - const { valid: v } = await ws.cryptoApi.isValidWireAccount({ + const { valid: v } = await wex.ws.cryptoApi.isValidWireAccount({ masterPub: masterPublicKey, paytoUri: a.payto_uri, sig: a.master_sig, @@ -490,10 +490,10 @@ async function validateWireInfo( wireFee: Amounts.stringify(x.wire_fee), }; let isValid = false; - if (ws.config.testing.insecureTrustExchange) { + if (wex.ws.config.testing.insecureTrustExchange) { isValid = true; } else { - const { valid: v } = await ws.cryptoApi.isValidWireFee({ + const { valid: v } = await wex.ws.cryptoApi.isValidWireFee({ masterPub: masterPublicKey, type: wireMethod, wf: fee, @@ -520,7 +520,7 @@ async function validateWireInfo( * Throw an exception if they are invalid. */ async function validateGlobalFees( - ws: InternalWalletState, + wex: WalletExecutionContext, fees: GlobalFees[], masterPub: string, ): Promise<ExchangeGlobalFees[]> { @@ -528,10 +528,10 @@ async function validateGlobalFees( for (const gf of fees) { logger.trace("validating exchange global fees"); let isValid = false; - if (ws.config.testing.insecureTrustExchange) { + if (wex.ws.config.testing.insecureTrustExchange) { isValid = true; } else { - const { valid: v } = await ws.cryptoApi.isValidGlobalFees({ + const { valid: v } = await wex.cryptoApi.isValidGlobalFees({ masterPub, gf, }); @@ -832,10 +832,9 @@ async function downloadExchangeKeysInfo( } async function downloadTosFromAcceptedFormat( - ws: InternalWalletState, + wex: WalletExecutionContext, baseUrl: string, timeout: Duration, - cancellationToken: CancellationToken, acceptedFormat?: string[], acceptLanguage?: string, ): Promise<ExchangeTosDownloadResult> { @@ -844,10 +843,10 @@ async function downloadTosFromAcceptedFormat( if (acceptedFormat) for (const format of acceptedFormat) { const resp = await downloadExchangeWithTermsOfService( + wex, baseUrl, - ws.http, + wex.http, timeout, - cancellationToken, format, acceptLanguage, ); @@ -861,10 +860,10 @@ async function downloadTosFromAcceptedFormat( } // If none of the specified format was found try text/plain return await downloadExchangeWithTermsOfService( + wex, baseUrl, - ws.http, + wex.http, timeout, - cancellationToken, "text/plain", acceptLanguage, ); @@ -880,7 +879,7 @@ async function downloadTosFromAcceptedFormat( * a new ephemeral entry is created. */ async function startUpdateExchangeEntry( - ws: InternalWalletState, + wex: WalletExecutionContext, exchangeBaseUrl: string, options: { forceUpdate?: boolean } = {}, ): Promise<void> { @@ -892,19 +891,19 @@ async function startUpdateExchangeEntry( }`, ); - const { notification } = await ws.db.runReadWriteTx( + const { notification } = await wex.db.runReadWriteTx( ["exchanges", "exchangeDetails"], async (tx) => { - return provideExchangeRecordInTx(ws, tx, exchangeBaseUrl); + return provideExchangeRecordInTx(wex.ws, tx, exchangeBaseUrl); }, ); if (notification) { - ws.notify(notification); + wex.ws.notify(notification); } const { oldExchangeState, newExchangeState, taskId } = - await ws.db.runReadWriteTx( + await wex.db.runReadWriteTx( ["exchanges", "operationRetries"], async (tx) => { const r = await tx.exchanges.get(canonBaseUrl); @@ -952,13 +951,13 @@ async function startUpdateExchangeEntry( return { oldExchangeState, newExchangeState, taskId }; }, ); - ws.notify({ + wex.ws.notify({ type: NotificationType.ExchangeStateTransition, exchangeBaseUrl: canonBaseUrl, newExchangeState: newExchangeState, oldExchangeState: oldExchangeState, }); - await ws.taskScheduler.resetTaskRetries(taskId); + await wex.ws.taskScheduler.resetTaskRetries(taskId); } /** @@ -978,7 +977,7 @@ export interface ReadyExchangeSummary { } async function internalWaitReadyExchange( - ws: InternalWalletState, + wex: WalletExecutionContext, canonUrl: string, exchangeNotifFlag: AsyncFlag, options: { @@ -994,7 +993,7 @@ async function internalWaitReadyExchange( while (true) { logger.info(`waiting for ready exchange ${canonUrl}`); const { exchange, exchangeDetails, retryInfo, scopeInfo } = - await ws.db.runReadOnlyTx( + await wex.db.runReadOnlyTx( [ "exchanges", "exchangeDetails", @@ -1105,7 +1104,7 @@ async function internalWaitReadyExchange( * will still have been added as an ephemeral exchange entry. */ export async function fetchFreshExchange( - ws: InternalWalletState, + wex: WalletExecutionContext, baseUrl: string, options: { cancellationToken?: CancellationToken; @@ -1115,17 +1114,17 @@ export async function fetchFreshExchange( ): Promise<ReadyExchangeSummary> { const canonUrl = canonicalizeBaseUrl(baseUrl); - ws.taskScheduler.ensureRunning(); + wex.ws.taskScheduler.ensureRunning(); - await startUpdateExchangeEntry(ws, canonUrl, { + await startUpdateExchangeEntry(wex, canonUrl, { forceUpdate: options.forceUpdate, }); - return waitReadyExchange(ws, canonUrl, options); + return waitReadyExchange(wex, canonUrl, options); } async function waitReadyExchange( - ws: InternalWalletState, + wex: WalletExecutionContext, canonUrl: string, options: { cancellationToken?: CancellationToken; @@ -1138,7 +1137,7 @@ async function waitReadyExchange( const exchangeNotifFlag = new AsyncFlag(); // Raise exchangeNotifFlag whenever we get a notification // about our exchange. - const cancelNotif = ws.addNotificationListener((notif) => { + const cancelNotif = wex.ws.addNotificationListener((notif) => { if ( notif.type === NotificationType.ExchangeStateTransition && notif.exchangeBaseUrl === canonUrl @@ -1150,7 +1149,7 @@ async function waitReadyExchange( try { const res = await internalWaitReadyExchange( - ws, + wex, canonUrl, exchangeNotifFlag, options, @@ -1169,14 +1168,13 @@ async function waitReadyExchange( * exchange entry in then DB. */ export async function updateExchangeFromUrlHandler( - ws: InternalWalletState, + wex: WalletExecutionContext, exchangeBaseUrl: string, - cancellationToken: CancellationToken, ): Promise<TaskRunResult> { logger.trace(`updating exchange info for ${exchangeBaseUrl}`); exchangeBaseUrl = canonicalizeBaseUrl(exchangeBaseUrl); - const oldExchangeRec = await ws.db.runReadOnlyTx( + const oldExchangeRec = await wex.db.runReadOnlyTx( ["exchanges"], async (tx) => { return tx.exchanges.get(exchangeBaseUrl); @@ -1264,9 +1262,9 @@ export async function updateExchangeFromUrlHandler( const keysInfo = await downloadExchangeKeysInfo( exchangeBaseUrl, - ws.http, + wex.http, timeout, - cancellationToken, + wex.cancellationToken, oldExchangeRec.cachebreakNextUpdate ?? false, ); @@ -1279,14 +1277,14 @@ export async function updateExchangeFromUrlHandler( } const wireInfo = await validateWireInfo( - ws, + wex, version.current, keysInfo, keysInfo.masterPublicKey, ); const globalFees = await validateGlobalFees( - ws, + wex, keysInfo.globalFees, keysInfo.masterPublicKey, ); @@ -1311,10 +1309,9 @@ export async function updateExchangeFromUrlHandler( // because that one needs to exist, and we // will get the current etag from the response. const tosDownload = await downloadTosFromAcceptedFormat( - ws, + wex, exchangeBaseUrl, timeout, - cancellationToken, ["text/plain"], ); @@ -1327,7 +1324,7 @@ export async function updateExchangeFromUrlHandler( let ageMask = 0; for (const x of keysInfo.currentDenominations) { if ( - isWithdrawableDenom(x, ws.config.testing.denomselAllowLate) && + isWithdrawableDenom(x, wex.ws.config.testing.denomselAllowLate) && x.denomPub.age_mask != 0 ) { ageMask = x.denomPub.age_mask; @@ -1335,7 +1332,7 @@ export async function updateExchangeFromUrlHandler( } } - const updated = await ws.db.runReadWriteTx( + const updated = await wex.db.runReadWriteTx( [ "exchanges", "exchangeDetails", @@ -1492,7 +1489,7 @@ export async function updateExchangeFromUrlHandler( if (newlyRevokedCoinPubs.length != 0) { logger.info("recouping coins", newlyRevokedCoinPubs); recoupGroupId = await createRecoupGroup( - ws, + wex, tx, exchangeBaseUrl, newlyRevokedCoinPubs, @@ -1517,7 +1514,7 @@ export async function updateExchangeFromUrlHandler( }); // Asynchronously start recoup. This doesn't need to finish // for the exchange update to be considered finished. - ws.taskScheduler.startShepherdTask(recoupTaskId); + wex.ws.taskScheduler.startShepherdTask(recoupTaskId); } if (!updated) { @@ -1535,7 +1532,7 @@ export async function updateExchangeFromUrlHandler( if (refreshCheckNecessary) { // Do auto-refresh. - await ws.db.runReadWriteTx( + await wex.db.runReadWriteTx( [ "coins", "denominations", @@ -1581,7 +1578,7 @@ export async function updateExchangeFromUrlHandler( } if (refreshCoins.length > 0) { const res = await createRefreshGroup( - ws, + wex, tx, exchange.detailsPointer?.currency, refreshCoins, @@ -1605,7 +1602,7 @@ export async function updateExchangeFromUrlHandler( ); } - ws.notify({ + wex.ws.notify({ type: NotificationType.ExchangeStateTransition, exchangeBaseUrl, newExchangeState: updated.newExchangeState, @@ -1648,13 +1645,13 @@ function getAutoRefreshCheckThreshold(d: DenominationRecord): AbsoluteTime { * Throws if no matching account was found. */ export async function getExchangePaytoUri( - ws: InternalWalletState, + wex: WalletExecutionContext, exchangeBaseUrl: string, supportedTargetTypes: string[], ): Promise<string> { // We do the update here, since the exchange might not even exist // yet in our database. - const details = await ws.db.runReadOnlyTx( + const details = await wex.db.runReadOnlyTx( ["exchanges", "exchangeDetails"], async (tx) => { return getExchangeRecordsInternal(tx, exchangeBaseUrl); @@ -1682,23 +1679,22 @@ export async function getExchangePaytoUri( * Try to download in the accepted format not cached. */ export async function getExchangeTos( - ws: InternalWalletState, + wex: WalletExecutionContext, exchangeBaseUrl: string, acceptedFormat?: string[], acceptLanguage?: string, ): Promise<GetExchangeTosResult> { - const exch = await fetchFreshExchange(ws, exchangeBaseUrl); + const exch = await fetchFreshExchange(wex, exchangeBaseUrl); const tosDownload = await downloadTosFromAcceptedFormat( - ws, + wex, exchangeBaseUrl, getExchangeRequestTimeout(), - CancellationToken.CONTINUE, acceptedFormat, acceptLanguage, ); - await ws.db.runReadWriteTx(["exchanges"], async (tx) => { + await wex.db.runReadWriteTx(["exchanges"], async (tx) => { const updateExchangeEntry = await tx.exchanges.get(exchangeBaseUrl); if (updateExchangeEntry) { updateExchangeEntry.tosCurrentEtag = tosDownload.tosEtag; @@ -1750,10 +1746,10 @@ export async function downloadExchangeInfo( * List all exchange entries known to the wallet. */ export async function listExchanges( - ws: InternalWalletState, + wex: WalletExecutionContext, ): Promise<ExchangesListResponse> { const exchanges: ExchangeListItem[] = []; - await ws.db.runReadOnlyTx( + await wex.db.runReadOnlyTx( [ "exchanges", "operationRetries", @@ -1793,7 +1789,7 @@ export async function listExchanges( * succeeded. */ export async function markExchangeUsed( - ws: InternalWalletState, + wex: WalletExecutionContext, tx: WalletDbReadWriteTransaction<["exchanges"]>, exchangeBaseUrl: string, ): Promise<{ notif: WalletNotification | undefined }> { @@ -1833,10 +1829,10 @@ export async function markExchangeUsed( * for the fees charged by the exchange. */ export async function getExchangeDetailedInfo( - ws: InternalWalletState, + wex: WalletExecutionContext, exchangeBaseurl: string, ): Promise<ExchangeDetailedResponse> { - const exchange = await ws.db.runReadOnlyTx( + const exchange = await wex.db.runReadOnlyTx( ["exchanges", "exchangeDetails", "denominations"], async (tx) => { const ex = await tx.exchanges.get(exchangeBaseurl); @@ -1986,7 +1982,7 @@ export async function getExchangeDetailedInfo( } async function internalGetExchangeResources( - ws: InternalWalletState, + wex: WalletExecutionContext, tx: DbReadOnlyTransaction< typeof WalletStoresV1, ["exchanges", "coins", "withdrawalGroups"] @@ -2005,12 +2001,12 @@ async function internalGetExchangeResources( } export async function deleteExchange( - ws: InternalWalletState, + wex: WalletExecutionContext, req: DeleteExchangeRequest, ): Promise<void> { let inUse: boolean = false; const exchangeBaseUrl = canonicalizeBaseUrl(req.exchangeBaseUrl); - await ws.db.runReadWriteTx( + await wex.db.runReadWriteTx( ["exchanges", "coins", "withdrawalGroups", "exchangeDetails"], async (tx) => { const exchangeRec = await tx.exchanges.get(exchangeBaseUrl); @@ -2019,7 +2015,7 @@ export async function deleteExchange( logger.info("no exchange found to delete"); return; } - const res = await internalGetExchangeResources(ws, tx, exchangeBaseUrl); + const res = await internalGetExchangeResources(wex, tx, exchangeBaseUrl); if (res.hasResources) { if (req.purge) { const detRecs = @@ -2050,18 +2046,18 @@ export async function deleteExchange( } export async function getExchangeResources( - ws: InternalWalletState, + wex: WalletExecutionContext, exchangeBaseUrl: string, ): Promise<GetExchangeResourcesResponse> { // Withdrawals include internal withdrawals from peer transactions - const res = await ws.db.runReadOnlyTx( + const res = await wex.db.runReadOnlyTx( ["exchanges", "withdrawalGroups", "coins"], async (tx) => { const exchangeRecord = await tx.exchanges.get(exchangeBaseUrl); if (!exchangeRecord) { return undefined; } - return internalGetExchangeResources(ws, tx, exchangeBaseUrl); + return internalGetExchangeResources(wex, tx, exchangeBaseUrl); }, ); if (!res) { |