summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/taler-wallet-core/src/host-impl.qtart.ts11
-rw-r--r--packages/taler-wallet-core/src/internal-wallet-state.ts8
-rw-r--r--packages/taler-wallet-core/src/operations/exchanges.ts224
-rw-r--r--packages/taler-wallet-core/src/operations/pay-merchant.ts2
-rw-r--r--packages/taler-wallet-core/src/operations/refresh.ts17
-rw-r--r--packages/taler-wallet-core/src/operations/testing.ts2
-rw-r--r--packages/taler-wallet-core/src/operations/withdraw.ts80
-rw-r--r--packages/taler-wallet-core/src/wallet.ts6
8 files changed, 169 insertions, 181 deletions
diff --git a/packages/taler-wallet-core/src/host-impl.qtart.ts b/packages/taler-wallet-core/src/host-impl.qtart.ts
index 686374beb..0fc346b44 100644
--- a/packages/taler-wallet-core/src/host-impl.qtart.ts
+++ b/packages/taler-wallet-core/src/host-impl.qtart.ts
@@ -30,20 +30,19 @@ import type {
} from "@gnu-taler/idb-bridge";
// eslint-disable-next-line no-duplicate-imports
import {
+ AccessStats,
BridgeIDBFactory,
MemoryBackend,
createSqliteBackend,
shimIndexedDB,
} from "@gnu-taler/idb-bridge";
-import { AccessStats } from "@gnu-taler/idb-bridge";
-import { SynchronousCryptoWorkerFactoryPlain } from "./crypto/workers/synchronousWorkerFactoryPlain.js";
-import { openTalerDatabase } from "./index.js";
-import { Logger, enableNativeLogging } from "@gnu-taler/taler-util";
+import { Logger } from "@gnu-taler/taler-util";
import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
-import { SetTimeoutTimerAPI } from "./util/timer.js";
-import { Wallet } from "./wallet.js";
import { qjsOs, qjsStd } from "@gnu-taler/taler-util/qtart";
+import { SynchronousCryptoWorkerFactoryPlain } from "./crypto/workers/synchronousWorkerFactoryPlain.js";
import { DefaultNodeWalletArgs, makeTempfileId } from "./host-common.js";
+import { SetTimeoutTimerAPI } from "./util/timer.js";
+import { Wallet } from "./wallet.js";
const logger = new Logger("host-impl.qtart.ts");
diff --git a/packages/taler-wallet-core/src/internal-wallet-state.ts b/packages/taler-wallet-core/src/internal-wallet-state.ts
index 20f8a7511..b1389a359 100644
--- a/packages/taler-wallet-core/src/internal-wallet-state.ts
+++ b/packages/taler-wallet-core/src/internal-wallet-state.ts
@@ -55,6 +55,7 @@ import {
import { TimerGroup } from "./util/timer.js";
import { WalletConfig } from "./wallet-api-types.js";
import { IDBFactory } from "@gnu-taler/idb-bridge";
+import { ReadyExchangeSummary } from "./index.js";
export const EXCHANGE_COINS_LOCK = "exchange-coins-lock";
export const EXCHANGE_RESERVES_LOCK = "exchange-reserves-lock";
@@ -107,17 +108,14 @@ export interface ExchangeOperations {
}>,
exchangeBaseUrl: string,
): Promise<ExchangeDetailsRecord | undefined>;
- updateExchangeFromUrl(
+ fetchFreshExchange(
ws: InternalWalletState,
baseUrl: string,
options?: {
forceNow?: boolean;
cancellationToken?: CancellationToken;
},
- ): Promise<{
- exchange: ExchangeEntryRecord;
- exchangeDetails: ExchangeDetailsRecord;
- }>;
+ ): Promise<ReadyExchangeSummary>;
}
export interface RecoupOperations {
diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts
index bf7d4424a..fe6060499 100644
--- a/packages/taler-wallet-core/src/operations/exchanges.ts
+++ b/packages/taler-wallet-core/src/operations/exchanges.ts
@@ -37,6 +37,7 @@ import {
ExchangeGlobalFees,
ExchangeListItem,
ExchangeSignKeyJson,
+ ExchangeTosStatus,
ExchangeWireAccount,
ExchangesListResponse,
FeeDescription,
@@ -84,12 +85,15 @@ import {
ExchangeEntryDbRecordStatus,
ExchangeEntryDbUpdateStatus,
OpenedPromise,
+ PendingTaskType,
WalletDbReadWriteTransaction,
createTimeline,
isWithdrawableDenom,
openPromise,
selectBestForOverlappingDenominations,
selectMinimumFee,
+ timestampOptionalAbsoluteFromDb,
+ timestampOptionalPreciseFromDb,
timestampPreciseFromDb,
timestampPreciseToDb,
timestampProtocolToDb,
@@ -102,9 +106,11 @@ import {
TaskIdentifiers,
TaskRunResult,
TaskRunResultType,
+ constructTaskIdentifier,
getExchangeState,
getExchangeTosStatusFromRecord,
makeExchangeListItem,
+ runTaskWithErrorReporting,
} from "./common.js";
const logger = new Logger("exchanges.ts");
@@ -629,7 +635,7 @@ async function downloadTosFromAcceptedFormat(
* If the update is forced, the exchange is put into an updating state
* even if the old information should still be up to date.
*
- * For backwards compatibility, if the exchange entry doesn't exist,
+ * If the exchange entry doesn't exist,
* a new ephemeral entry is created.
*/
export async function startUpdateExchangeEntry(
@@ -740,76 +746,18 @@ export function createNotificationWaiter(
}
/**
- * Wait until an exchange entry got successfully updated.
- *
- * Reject with an exception if the update encountered an error.
+ * Basic information about an exchange in a ready state.
*/
-export async function waitExchangeEntryUpdated(
- ws: InternalWalletState,
- exchangeBaseUrl: string,
- cancellationToken?: CancellationToken,
-): Promise<{
- exchange: ExchangeEntryRecord;
- exchangeDetails: ExchangeDetailsRecord;
-}> {
- exchangeBaseUrl = canonicalizeBaseUrl(exchangeBaseUrl);
-
- const waiter = createNotificationWaiter(
- ws,
- (notif) =>
- notif.type == NotificationType.ExchangeStateTransition &&
- notif.exchangeBaseUrl === exchangeBaseUrl,
- );
-
- const taskId = TaskIdentifiers.forExchangeUpdateFromUrl(exchangeBaseUrl);
-
- while (1) {
- const { exchange, retryRecord } = await ws.db
- .mktx((x) => [x.exchanges, x.exchangeDetails, x.operationRetries])
- .runReadOnly(async (tx) => {
- const exchange = await tx.exchanges.get(exchangeBaseUrl);
- const retryRecord = await tx.operationRetries.get(taskId);
- return { exchange, retryRecord };
- });
-
- if (!exchange) {
- throw Error("exchange does not exist anymore");
- }
-
- switch (exchange.updateStatus) {
- case ExchangeEntryDbUpdateStatus.Ready:
- const details = await ws.db
- .mktx((x) => [x.exchanges, x.exchangeDetails])
- .runReadOnly(async (tx) => {
- return getExchangeDetails(tx, exchangeBaseUrl);
- });
- if (!details) {
- throw Error("exchange entry inconsistent");
- }
- waiter.cancel();
- return { exchange, exchangeDetails: details };
- case ExchangeEntryDbUpdateStatus.ReadyUpdate:
- case ExchangeEntryDbUpdateStatus.InitialUpdate: {
- waiter.cancel();
- if (retryRecord?.lastError) {
- throw TalerError.fromUncheckedDetail(retryRecord.lastError);
- }
- break;
- }
- case ExchangeEntryDbUpdateStatus.UnavailableUpdate:
- waiter.cancel();
- if (retryRecord?.lastError) {
- throw TalerError.fromUncheckedDetail(retryRecord.lastError);
- } else {
- throw Error(
- "updating exchange failed, error info unavailable (bug!)",
- );
- }
- }
-
- await waiter.waitNext();
- }
- throw Error("not reached");
+export interface ReadyExchangeSummary {
+ exchangeBaseUrl: string;
+ currency: string;
+ masterPub: string;
+ tosStatus: ExchangeTosStatus;
+ tosAcceptedEtag: string | undefined;
+ tosCurrentEtag: string | undefined;
+ wireInfo: WireInfo;
+ protocolVersionRange: string;
+ tosAcceptedTimestamp: TalerPreciseTimestamp | undefined;
}
/**
@@ -834,21 +782,81 @@ export async function fetchFreshExchange(
forceUpdate?: boolean;
expectedMasterPub?: string;
} = {},
-): Promise<{
- exchange: ExchangeEntryRecord;
- exchangeDetails: ExchangeDetailsRecord;
-}> {
+): Promise<ReadyExchangeSummary> {
const canonUrl = canonicalizeBaseUrl(baseUrl);
- await startUpdateExchangeEntry(ws, canonUrl, {
- forceUpdate: options.forceUpdate,
+ const operationId = constructTaskIdentifier({
+ tag: PendingTaskType.ExchangeUpdate,
+ exchangeBaseUrl: canonUrl,
});
- const res = await waitExchangeEntryUpdated(
- ws,
- canonUrl,
- options.cancellationToken,
- );
+
+ const oldExchange = await ws.db
+ .mktx((x) => [x.exchanges])
+ .runReadOnly(async (tx) => {
+ return tx.exchanges.get(canonUrl);
+ });
+
+ let needsUpdate = false;
+
+ if (!oldExchange || options.forceUpdate) {
+ needsUpdate = true;
+ await startUpdateExchangeEntry(ws, canonUrl, {
+ forceUpdate: options.forceUpdate,
+ });
+ } else {
+ const nextUpdate = timestampOptionalAbsoluteFromDb(
+ oldExchange.nextUpdateStamp,
+ );
+ if (nextUpdate == null || AbsoluteTime.isExpired(nextUpdate)) {
+ needsUpdate = true;
+ }
+ }
+
+ if (needsUpdate) {
+ await runTaskWithErrorReporting(ws, operationId, () =>
+ updateExchangeFromUrlHandler(ws, canonUrl),
+ );
+ }
+
+ const { exchange, exchangeDetails } = await ws.db
+ .mktx((x) => [x.exchanges, x.exchangeDetails])
+ .runReadOnly(async (tx) => {
+ const exchange = await tx.exchanges.get(canonUrl);
+ const exchangeDetails = await getExchangeDetails(tx, canonUrl);
+ return { exchange, exchangeDetails };
+ });
+
+ if (!exchange) {
+ throw Error("exchange entry does not exist anymore");
+ }
+
+ switch (exchange.updateStatus) {
+ case ExchangeEntryDbUpdateStatus.Ready:
+ case ExchangeEntryDbUpdateStatus.ReadyUpdate:
+ break;
+ default:
+ throw Error("unable to update exchange");
+ }
+
+ if (!exchangeDetails) {
+ throw Error("invariant failed");
+ }
+
+ const res: ReadyExchangeSummary = {
+ currency: exchangeDetails.currency,
+ exchangeBaseUrl: canonUrl,
+ masterPub: exchangeDetails.masterPublicKey,
+ tosStatus: getExchangeTosStatusFromRecord(exchange),
+ tosAcceptedEtag: exchange.tosAcceptedEtag,
+ wireInfo: exchangeDetails.wireInfo,
+ protocolVersionRange: exchangeDetails.protocolVersionRange,
+ tosCurrentEtag: exchange.tosCurrentEtag,
+ tosAcceptedTimestamp: timestampOptionalPreciseFromDb(
+ exchange.tosAcceptedTimestamp,
+ ),
+ };
+
if (options.expectedMasterPub) {
- if (res.exchangeDetails.masterPublicKey !== options.expectedMasterPub) {
+ if (res.masterPub !== options.expectedMasterPub) {
throw Error(
"public key of the exchange does not match expected public key",
);
@@ -1187,10 +1195,7 @@ export async function getExchangeTos(
acceptLanguage?: string,
): Promise<GetExchangeTosResult> {
// FIXME: download ToS in acceptable format if passed!
- const { exchange, exchangeDetails } = await fetchFreshExchange(
- ws,
- exchangeBaseUrl,
- );
+ const exch = await fetchFreshExchange(ws, exchangeBaseUrl);
const tosDownload = await downloadTosFromAcceptedFormat(
ws,
@@ -1211,12 +1216,12 @@ export async function getExchangeTos(
});
return {
- acceptedEtag: exchange.tosAcceptedEtag,
+ acceptedEtag: exch.tosAcceptedEtag,
currentEtag: tosDownload.tosEtag,
content: tosDownload.tosText,
contentType: tosDownload.tosContentType,
contentLanguage: tosDownload.tosContentLanguage,
- tosStatus: getExchangeTosStatusFromRecord(exchange),
+ tosStatus: exch.tosStatus,
tosAvailableLanguages: tosDownload.tosAvailableLanguages,
};
}
@@ -1364,26 +1369,29 @@ export async function getExchangeDetailedInfo(
const transferFees = Object.entries(
exchange.info.wireInfo.feesForType,
- ).reduce((prev, [wireType, infoForType]) => {
- const feesByGroup = [
- ...infoForType.map((w) => ({
- ...w,
- fee: Amounts.stringify(w.closingFee),
- group: "closing",
- })),
- ...infoForType.map((w) => ({ ...w, fee: w.wireFee, group: "wire" })),
- ];
- prev[wireType] = createTimeline(
- feesByGroup,
- "sig",
- "startStamp",
- "endStamp",
- "fee",
- "group",
- selectMinimumFee,
- );
- return prev;
- }, {} as Record<string, FeeDescription[]>);
+ ).reduce(
+ (prev, [wireType, infoForType]) => {
+ const feesByGroup = [
+ ...infoForType.map((w) => ({
+ ...w,
+ fee: Amounts.stringify(w.closingFee),
+ group: "closing",
+ })),
+ ...infoForType.map((w) => ({ ...w, fee: w.wireFee, group: "wire" })),
+ ];
+ prev[wireType] = createTimeline(
+ feesByGroup,
+ "sig",
+ "startStamp",
+ "endStamp",
+ "fee",
+ "group",
+ selectMinimumFee,
+ );
+ return prev;
+ },
+ {} as Record<string, FeeDescription[]>,
+ );
const globalFeesByGroup = [
...exchange.info.globalFees.map((w) => ({
diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts b/packages/taler-wallet-core/src/operations/pay-merchant.ts
index 17a879d90..078f0faf9 100644
--- a/packages/taler-wallet-core/src/operations/pay-merchant.ts
+++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts
@@ -1278,7 +1278,7 @@ export async function generateDepositPermissions(
* Run the operation handler for a payment
* and return the result as a {@link ConfirmPayResult}.
*/
-export async function runPayForConfirmPay(
+async function runPayForConfirmPay(
ws: InternalWalletState,
proposalId: string,
): Promise<ConfirmPayResult> {
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts b/packages/taler-wallet-core/src/operations/refresh.ts
index 3bbbc2a4b..5ea8fae23 100644
--- a/packages/taler-wallet-core/src/operations/refresh.ts
+++ b/packages/taler-wallet-core/src/operations/refresh.ts
@@ -99,11 +99,7 @@ import {
TaskRunResult,
TaskRunResultType,
} from "./common.js";
-import {
- fetchFreshExchange,
- startUpdateExchangeEntry,
- waitExchangeEntryUpdated,
-} from "./exchanges.js";
+import { fetchFreshExchange } from "./exchanges.js";
import {
constructTransactionIdentifier,
notifyTransition,
@@ -226,10 +222,7 @@ async function provideRefreshSession(
const { refreshGroup, coin } = d;
- const { exchange } = await fetchFreshExchange(ws, coin.exchangeBaseUrl);
- if (!exchange) {
- throw Error("db inconsistent: exchange of coin not found");
- }
+ const exch = await fetchFreshExchange(ws, coin.exchangeBaseUrl);
// FIXME: use helper functions from withdraw.ts
// to update and filter withdrawable denoms.
@@ -240,7 +233,7 @@ async function provideRefreshSession(
const oldDenom = await ws.getDenomInfo(
ws,
tx,
- exchange.baseUrl,
+ exch.exchangeBaseUrl,
coin.denomPubHash,
);
@@ -251,7 +244,7 @@ async function provideRefreshSession(
// FIXME: use an index here, based on the withdrawal expiration time.
const availableDenoms: DenominationRecord[] =
await tx.denominations.indexes.byExchangeBaseUrl
- .iter(exchange.baseUrl)
+ .iter(exch.exchangeBaseUrl)
.toArray();
const availableAmount = Amounts.sub(
@@ -872,7 +865,7 @@ export async function processRefreshGroup(
return TaskRunResult.finished();
}
// Process refresh sessions of the group in parallel.
- logger.trace("processing refresh sessions for old coins");
+ logger.trace("processing refresh sessions for $ old coins");
let errors: TalerErrorDetail[] = [];
let inShutdown = false;
const ps = refreshGroup.oldCoinPubs.map((x, i) =>
diff --git a/packages/taler-wallet-core/src/operations/testing.ts b/packages/taler-wallet-core/src/operations/testing.ts
index a03d54d3a..d75fb54a7 100644
--- a/packages/taler-wallet-core/src/operations/testing.ts
+++ b/packages/taler-wallet-core/src/operations/testing.ts
@@ -581,7 +581,7 @@ export async function runIntegrationTest2(
const exchangeInfo = await fetchFreshExchange(ws, args.exchangeBaseUrl);
- const currency = exchangeInfo.exchangeDetails.currency;
+ const currency = exchangeInfo.currency;
const amountToWithdraw = Amounts.parseOrThrow(`${currency}:10`);
const amountToSpend = Amounts.parseOrThrow(`${currency}:2`);
diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts
index 8a718dd49..3dffab7d6 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.ts
@@ -136,6 +136,7 @@ import {
getExchangeDetails,
getExchangePaytoUri,
fetchFreshExchange,
+ ReadyExchangeSummary,
} from "./exchanges.js";
import {
TransitionInfo,
@@ -616,9 +617,10 @@ export async function getCandidateWithdrawalDenoms(
return await ws.db
.mktx((x) => [x.denominations])
.runReadOnly(async (tx) => {
- const allDenoms = await tx.denominations.indexes.byExchangeBaseUrl.getAll(
- exchangeBaseUrl,
- );
+ const allDenoms =
+ await tx.denominations.indexes.byExchangeBaseUrl.getAll(
+ exchangeBaseUrl,
+ );
return allDenoms.filter((d) =>
isWithdrawableDenom(d, ws.config.testing.denomselAllowLate),
);
@@ -870,10 +872,10 @@ async function handleKycRequired(
amlStatus === AmlStatus.normal || amlStatus === undefined
? WithdrawalGroupStatus.PendingKyc
: amlStatus === AmlStatus.pending
- ? WithdrawalGroupStatus.PendingAml
- : amlStatus === AmlStatus.fronzen
- ? WithdrawalGroupStatus.SuspendedAml
- : assertUnreachable(amlStatus);
+ ? WithdrawalGroupStatus.PendingAml
+ : amlStatus === AmlStatus.fronzen
+ ? WithdrawalGroupStatus.SuspendedAml
+ : assertUnreachable(amlStatus);
notificationKycUrl = kycUrl;
@@ -1508,10 +1510,7 @@ async function processWithdrawalGroupPendingReady(
withdrawalGroupId,
});
- await ws.exchangeOps.updateExchangeFromUrl(
- ws,
- withdrawalGroup.exchangeBaseUrl,
- );
+ await ws.exchangeOps.fetchFreshExchange(ws, withdrawalGroup.exchangeBaseUrl);
if (withdrawalGroup.denomsSel.selectedDenoms.length === 0) {
logger.warn("Finishing empty withdrawal group (no denoms)");
@@ -1549,9 +1548,8 @@ async function processWithdrawalGroupPendingReady(
await ws.db
.mktx((x) => [x.planchets])
.runReadOnly(async (tx) => {
- const planchets = await tx.planchets.indexes.byGroup.getAll(
- withdrawalGroupId,
- );
+ const planchets =
+ await tx.planchets.indexes.byGroup.getAll(withdrawalGroupId);
for (const p of planchets) {
if (p.planchetStatus === PlanchetStatus.WithdrawalDone) {
wgContext.planchetsFinished.add(p.coinPub);
@@ -1759,19 +1757,18 @@ export async function getExchangeWithdrawalInfo(
ageRestricted: number | undefined,
): Promise<ExchangeWithdrawalDetails> {
logger.trace("updating exchange");
- const { exchange, exchangeDetails } =
- await ws.exchangeOps.updateExchangeFromUrl(ws, exchangeBaseUrl);
+ const exchange = await ws.exchangeOps.fetchFreshExchange(ws, exchangeBaseUrl);
- if (exchangeDetails.currency != instructedAmount.currency) {
+ if (exchange.currency != instructedAmount.currency) {
// Specifiying the amount in the conversion input currency is not yet supported.
// We might add support for it later.
throw new Error(
- `withdrawal only supported when specifying target currency ${exchangeDetails.currency}`,
+ `withdrawal only supported when specifying target currency ${exchange.currency}`,
);
}
const withdrawalAccountsList = await fetchWithdrawalAccountInfo(ws, {
- exchangeDetails,
+ exchange,
instructedAmount,
});
@@ -1799,7 +1796,7 @@ export async function getExchangeWithdrawalInfo(
const exchangeWireAccounts: string[] = [];
- for (const account of exchangeDetails.wireInfo.accounts) {
+ for (const account of exchange.wireInfo.accounts) {
exchangeWireAccounts.push(account.payto_uri);
}
@@ -1839,17 +1836,18 @@ export async function getExchangeWithdrawalInfo(
const possibleDenoms = await ws.db
.mktx((x) => [x.denominations])
.runReadOnly(async (tx) => {
- const ds = await tx.denominations.indexes.byExchangeBaseUrl.getAll(
- exchangeBaseUrl,
- );
+ const ds =
+ await tx.denominations.indexes.byExchangeBaseUrl.getAll(
+ exchangeBaseUrl,
+ );
return ds.filter((x) => x.isOffered);
});
let versionMatch;
- if (exchangeDetails.protocolVersionRange) {
+ if (exchange.protocolVersionRange) {
versionMatch = LibtoolVersion.compare(
WALLET_EXCHANGE_PROTOCOL_VERSION,
- exchangeDetails.protocolVersionRange,
+ exchange.protocolVersionRange,
);
if (
@@ -1859,7 +1857,7 @@ export async function getExchangeWithdrawalInfo(
) {
logger.warn(
`wallet's support for exchange protocol version ${WALLET_EXCHANGE_PROTOCOL_VERSION} might be outdated ` +
- `(exchange has ${exchangeDetails.protocolVersionRange}), checking for updates`,
+ `(exchange has ${exchange.protocolVersionRange}), checking for updates`,
);
}
}
@@ -1871,7 +1869,7 @@ export async function getExchangeWithdrawalInfo(
}
}
- const paytoUris = exchangeDetails.wireInfo.accounts.map((x) => x.payto_uri);
+ const paytoUris = exchange.wireInfo.accounts.map((x) => x.payto_uri);
if (!paytoUris) {
throw Error("exchange is in invalid state");
}
@@ -1881,7 +1879,7 @@ export async function getExchangeWithdrawalInfo(
exchangePaytoUris: paytoUris,
exchangeWireAccounts,
exchangeCreditAccountDetails: withdrawalAccountsList,
- exchangeVersion: exchangeDetails.protocolVersionRange || "unknown",
+ exchangeVersion: exchange.protocolVersionRange || "unknown",
numOfferedDenoms: possibleDenoms.length,
selectedDenoms,
// FIXME: delete this field / replace by something we can display to the user
@@ -1923,7 +1921,7 @@ export async function getWithdrawalDetailsForUri(
// FIXME: right now the exchange gets permanently added,
// we might want to only temporarily add it.
try {
- await ws.exchangeOps.updateExchangeFromUrl(ws, info.suggestedExchange);
+ await ws.exchangeOps.fetchFreshExchange(ws, info.suggestedExchange);
} catch (e) {
// We still continued if it failed, as other exchanges might be available.
// We don't want to fail if the bank-suggested exchange is broken/offline.
@@ -2289,7 +2287,6 @@ export interface PrepareCreateWithdrawalGroupResult {
creationInfo?: {
amount: AmountJson;
canonExchange: string;
- exchangeDetails: ExchangeDetailsRecord;
};
}
@@ -2376,7 +2373,6 @@ export async function internalPrepareCreateWithdrawalGroup(
};
const exchangeInfo = await fetchFreshExchange(ws, canonExchange);
- const exchangeDetails = exchangeInfo.exchangeDetails;
const transactionId = constructTransactionIdentifier({
tag: TransactionType.Withdrawal,
withdrawalGroupId: withdrawalGroup.withdrawalGroupId,
@@ -2388,7 +2384,6 @@ export async function internalPrepareCreateWithdrawalGroup(
creationInfo: {
canonExchange,
amount,
- exchangeDetails,
},
};
}
@@ -2411,8 +2406,6 @@ export async function internalPerformCreateWithdrawalGroup(
if (!prep.creationInfo) {
return { withdrawalGroup, transitionInfo: undefined };
}
- const { amount, canonExchange, exchangeDetails } = prep.creationInfo;
-
await tx.withdrawalGroups.add(withdrawalGroup);
await tx.reserves.put({
reservePub: withdrawalGroup.reservePub,
@@ -2529,13 +2522,13 @@ export async function acceptWithdrawalFromUri(
withdrawInfo.wireTypes,
);
- const { exchangeDetails } = await ws.exchangeOps.updateExchangeFromUrl(
+ const exchange = await ws.exchangeOps.fetchFreshExchange(
ws,
selectedExchange,
);
const withdrawalAccountList = await fetchWithdrawalAccountInfo(ws, {
- exchangeDetails,
+ exchange,
instructedAmount: withdrawInfo.amount,
});
@@ -2666,14 +2659,14 @@ async function fetchAccount(
async function fetchWithdrawalAccountInfo(
ws: InternalWalletState,
req: {
- exchangeDetails: ExchangeDetailsRecord;
+ exchange: ReadyExchangeSummary;
instructedAmount: AmountJson;
reservePub?: string;
},
): Promise<WithdrawalExchangeAccountDetails[]> {
- const { exchangeDetails, instructedAmount } = req;
+ const { exchange, instructedAmount } = req;
const withdrawalAccounts: WithdrawalExchangeAccountDetails[] = [];
- for (let acct of exchangeDetails.wireInfo.accounts) {
+ for (let acct of exchange.wireInfo.accounts) {
const acctInfo = await fetchAccount(
ws,
req.instructedAmount,
@@ -2704,12 +2697,9 @@ export async function createManualWithdrawal(
): Promise<AcceptManualWithdrawalResult> {
const { exchangeBaseUrl } = req;
const amount = Amounts.parseOrThrow(req.amount);
- const { exchangeDetails } = await ws.exchangeOps.updateExchangeFromUrl(
- ws,
- exchangeBaseUrl,
- );
+ const exchange = await ws.exchangeOps.fetchFreshExchange(ws, exchangeBaseUrl);
- if (exchangeDetails.currency != amount.currency) {
+ if (exchange.currency != amount.currency) {
throw Error(
"manual withdrawal with conversion from foreign currency is not yet supported",
);
@@ -2719,7 +2709,7 @@ export async function createManualWithdrawal(
);
const withdrawalAccountsList = await fetchWithdrawalAccountInfo(ws, {
- exchangeDetails,
+ exchange,
instructedAmount: amount,
reservePub: reserveKeyPair.pub,
});
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index da6ffa41f..2d422e59c 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -844,12 +844,12 @@ async function handlePrepareWithdrawExchange(
}
const exchangeBaseUrl = parsedUri.exchangeBaseUrl;
const exchange = await fetchFreshExchange(ws, exchangeBaseUrl);
- if (exchange.exchangeDetails.masterPublicKey != parsedUri.exchangePub) {
+ if (exchange.masterPub != parsedUri.exchangePub) {
throw Error("mismatch of exchange master public key (URI vs actual)");
}
if (parsedUri.amount) {
const amt = Amounts.parseOrThrow(parsedUri.amount);
- if (amt.currency !== exchange.exchangeDetails.currency) {
+ if (amt.currency !== exchange.currency) {
throw Error("mismatch of currency (URI vs exchange)");
}
}
@@ -1689,7 +1689,7 @@ class InternalWalletStateImpl implements InternalWalletState {
exchangeOps: ExchangeOperations = {
getExchangeDetails,
- updateExchangeFromUrl: fetchFreshExchange,
+ fetchFreshExchange,
};
recoupOps: RecoupOperations = {