summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core/src/operations/exchanges.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-core/src/operations/exchanges.ts')
-rw-r--r--packages/taler-wallet-core/src/operations/exchanges.ts211
1 files changed, 102 insertions, 109 deletions
diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts
index 460b47e73..678e48fb9 100644
--- a/packages/taler-wallet-core/src/operations/exchanges.ts
+++ b/packages/taler-wallet-core/src/operations/exchanges.ts
@@ -99,8 +99,8 @@ import {
ExchangeEntryDbRecordStatus,
ExchangeEntryDbUpdateStatus,
PendingTaskType,
- WalletDbReadOnlyTransactionArr,
- WalletDbReadWriteTransactionArr,
+ WalletDbReadOnlyTransaction,
+ WalletDbReadWriteTransaction,
createRefreshGroup,
createTimeline,
isWithdrawableDenom,
@@ -115,11 +115,7 @@ import {
} from "../index.js";
import { InternalWalletState } from "../internal-wallet-state.js";
import { checkDbInvariant } from "../util/invariants.js";
-import {
- DbReadOnlyTransactionArr,
- GetReadOnlyAccess,
- GetReadWriteAccess,
-} from "../util/query.js";
+import { DbReadOnlyTransaction } from "../util/query.js";
import { WALLET_EXCHANGE_PROTOCOL_VERSION } from "../versions.js";
import {
TaskIdentifiers,
@@ -197,10 +193,7 @@ async function downloadExchangeWithTermsOfService(
* Get exchange details from the database.
*/
async function getExchangeRecordsInternal(
- tx: GetReadOnlyAccess<{
- exchanges: typeof WalletStoresV1.exchanges;
- exchangeDetails: typeof WalletStoresV1.exchangeDetails;
- }>,
+ tx: WalletDbReadOnlyTransaction<["exchanges", "exchangeDetails"]>,
exchangeBaseUrl: string,
): Promise<ExchangeDetailsRecord | undefined> {
const r = await tx.exchanges.get(exchangeBaseUrl);
@@ -220,7 +213,7 @@ async function getExchangeRecordsInternal(
}
export async function getExchangeScopeInfo(
- tx: WalletDbReadOnlyTransactionArr<
+ tx: WalletDbReadOnlyTransaction<
[
"exchanges",
"exchangeDetails",
@@ -243,7 +236,7 @@ export async function getExchangeScopeInfo(
}
async function internalGetExchangeScopeInfo(
- tx: WalletDbReadOnlyTransactionArr<
+ tx: WalletDbReadOnlyTransaction<
["globalCurrencyExchanges", "globalCurrencyAuditors"]
>,
exchangeDetails: ExchangeDetailsRecord,
@@ -284,7 +277,7 @@ async function internalGetExchangeScopeInfo(
}
async function makeExchangeListItem(
- tx: WalletDbReadOnlyTransactionArr<
+ tx: WalletDbReadOnlyTransaction<
["globalCurrencyExchanges", "globalCurrencyAuditors"]
>,
r: ExchangeEntryRecord,
@@ -328,10 +321,7 @@ export interface ExchangeWireDetails {
}
export async function getExchangeWireDetailsInTx(
- tx: GetReadOnlyAccess<{
- exchanges: typeof WalletStoresV1.exchanges;
- exchangeDetails: typeof WalletStoresV1.exchangeDetails;
- }>,
+ tx: WalletDbReadOnlyTransaction<["exchanges", "exchangeDetails"]>,
exchangeBaseUrl: string,
): Promise<ExchangeWireDetails | undefined> {
const det = await getExchangeRecordsInternal(tx, exchangeBaseUrl);
@@ -389,9 +379,9 @@ export async function acceptExchangeTermsOfService(
ws: InternalWalletState,
exchangeBaseUrl: string,
): Promise<void> {
- const notif = await ws.db
- .mktx((x) => [x.exchanges, x.exchangeDetails])
- .runReadWrite(async (tx) => {
+ const notif = await ws.db.runReadWriteTx(
+ ["exchangeDetails", "exchanges"],
+ async (tx) => {
const exch = await tx.exchanges.get(exchangeBaseUrl);
if (exch && exch.tosCurrentEtag) {
const oldExchangeState = getExchangeState(exch);
@@ -409,7 +399,8 @@ export async function acceptExchangeTermsOfService(
} satisfies WalletNotification;
}
return undefined;
- });
+ },
+ );
if (notif) {
ws.notify(notif);
}
@@ -537,7 +528,7 @@ async function validateGlobalFees(
* if the DB transaction succeeds.
*/
export async function addPresetExchangeEntry(
- tx: WalletDbReadWriteTransactionArr<["exchanges"]>,
+ tx: WalletDbReadWriteTransaction<["exchanges"]>,
exchangeBaseUrl: string,
currencyHint?: string,
): Promise<{ notification?: WalletNotification }> {
@@ -577,10 +568,7 @@ export async function addPresetExchangeEntry(
async function provideExchangeRecordInTx(
ws: InternalWalletState,
- tx: GetReadWriteAccess<{
- exchanges: typeof WalletStoresV1.exchanges;
- exchangeDetails: typeof WalletStoresV1.exchangeDetails;
- }>,
+ tx: WalletDbReadWriteTransaction<["exchanges", "exchangeDetails"]>,
baseUrl: string,
): Promise<{
exchange: ExchangeEntryRecord;
@@ -854,55 +842,58 @@ async function startUpdateExchangeEntry(
}`,
);
- const { notification } = await ws.db
- .mktx((x) => [x.exchanges, x.exchangeDetails])
- .runReadWrite(async (tx) => {
+ const { notification } = await ws.db.runReadWriteTx(
+ ["exchanges", "exchangeDetails"],
+ async (tx) => {
return provideExchangeRecordInTx(ws, tx, exchangeBaseUrl);
- });
+ },
+ );
if (notification) {
ws.notify(notification);
}
- const { oldExchangeState, newExchangeState, taskId } = await ws.db
- .mktx((x) => [x.exchanges, x.operationRetries])
- .runReadWrite(async (tx) => {
- const r = await tx.exchanges.get(canonBaseUrl);
- if (!r) {
- throw Error("exchange not found");
- }
- const oldExchangeState = getExchangeState(r);
- switch (r.updateStatus) {
- case ExchangeEntryDbUpdateStatus.UnavailableUpdate:
- break;
- case ExchangeEntryDbUpdateStatus.Suspended:
- break;
- case ExchangeEntryDbUpdateStatus.ReadyUpdate:
- break;
- case ExchangeEntryDbUpdateStatus.Ready: {
- const nextUpdateTimestamp = AbsoluteTime.fromPreciseTimestamp(
- timestampPreciseFromDb(r.nextUpdateStamp),
- );
- // Only update if entry is outdated or update is forced.
- if (
- options.forceUpdate ||
- AbsoluteTime.isExpired(nextUpdateTimestamp)
- ) {
- r.updateStatus = ExchangeEntryDbUpdateStatus.ReadyUpdate;
+ const { oldExchangeState, newExchangeState, taskId } =
+ await ws.db.runReadWriteTx(
+ ["exchanges", "operationRetries"],
+ async (tx) => {
+ const r = await tx.exchanges.get(canonBaseUrl);
+ if (!r) {
+ throw Error("exchange not found");
+ }
+ const oldExchangeState = getExchangeState(r);
+ switch (r.updateStatus) {
+ case ExchangeEntryDbUpdateStatus.UnavailableUpdate:
+ break;
+ case ExchangeEntryDbUpdateStatus.Suspended:
+ break;
+ case ExchangeEntryDbUpdateStatus.ReadyUpdate:
+ break;
+ case ExchangeEntryDbUpdateStatus.Ready: {
+ const nextUpdateTimestamp = AbsoluteTime.fromPreciseTimestamp(
+ timestampPreciseFromDb(r.nextUpdateStamp),
+ );
+ // Only update if entry is outdated or update is forced.
+ if (
+ options.forceUpdate ||
+ AbsoluteTime.isExpired(nextUpdateTimestamp)
+ ) {
+ r.updateStatus = ExchangeEntryDbUpdateStatus.ReadyUpdate;
+ }
+ break;
}
- break;
+ case ExchangeEntryDbUpdateStatus.Initial:
+ r.updateStatus = ExchangeEntryDbUpdateStatus.InitialUpdate;
+ break;
}
- case ExchangeEntryDbUpdateStatus.Initial:
- r.updateStatus = ExchangeEntryDbUpdateStatus.InitialUpdate;
- break;
- }
- await tx.exchanges.put(r);
- const newExchangeState = getExchangeState(r);
- // Reset retries for updating the exchange entry.
- const taskId = TaskIdentifiers.forExchangeUpdate(r);
- await tx.operationRetries.delete(taskId);
- return { oldExchangeState, newExchangeState, taskId };
- });
+ await tx.exchanges.put(r);
+ const newExchangeState = getExchangeState(r);
+ // Reset retries for updating the exchange entry.
+ const taskId = TaskIdentifiers.forExchangeUpdate(r);
+ await tx.operationRetries.delete(taskId);
+ return { oldExchangeState, newExchangeState, taskId };
+ },
+ );
ws.notify({
type: NotificationType.ExchangeStateTransition,
exchangeBaseUrl: canonBaseUrl,
@@ -1284,17 +1275,17 @@ export async function updateExchangeFromUrlHandler(
}
}
- const updated = await ws.db
- .mktx((x) => [
- x.exchanges,
- x.exchangeDetails,
- x.exchangeSignKeys,
- x.denominations,
- x.coins,
- x.refreshGroups,
- x.recoupGroups,
- ])
- .runReadWrite(async (tx) => {
+ const updated = await ws.db.runReadWriteTx(
+ [
+ "exchanges",
+ "exchangeDetails",
+ "exchangeSignKeys",
+ "denominations",
+ "coins",
+ "refreshGroups",
+ "recoupGroups",
+ ],
+ async (tx) => {
const r = await tx.exchanges.get(exchangeBaseUrl);
if (!r) {
logger.warn(`exchange ${exchangeBaseUrl} no longer present`);
@@ -1454,7 +1445,8 @@ export async function updateExchangeFromUrlHandler(
oldExchangeState,
newExchangeState,
};
- });
+ },
+ );
if (recoupGroupId) {
const recoupTaskId = constructTaskIdentifier({
@@ -1481,15 +1473,15 @@ export async function updateExchangeFromUrlHandler(
if (refreshCheckNecessary) {
// Do auto-refresh.
- await ws.db
- .mktx((x) => [
- x.coins,
- x.denominations,
- x.coinAvailability,
- x.refreshGroups,
- x.exchanges,
- ])
- .runReadWrite(async (tx) => {
+ await ws.db.runReadWriteTx(
+ [
+ "coins",
+ "denominations",
+ "coinAvailability",
+ "refreshGroups",
+ "exchanges",
+ ],
+ async (tx) => {
const exchange = await tx.exchanges.get(exchangeBaseUrl);
if (!exchange || !exchange.detailsPointer) {
return;
@@ -1547,7 +1539,8 @@ export async function updateExchangeFromUrlHandler(
AbsoluteTime.toPreciseTimestamp(minCheckThreshold),
);
await tx.exchanges.put(exchange);
- });
+ },
+ );
}
ws.notify({
@@ -1599,11 +1592,12 @@ export async function getExchangePaytoUri(
): Promise<string> {
// We do the update here, since the exchange might not even exist
// yet in our database.
- const details = await ws.db
- .mktx((x) => [x.exchangeDetails, x.exchanges])
- .runReadOnly(async (tx) => {
+ const details = await ws.db.runReadOnlyTx(
+ ["exchanges", "exchangeDetails"],
+ async (tx) => {
return getExchangeRecordsInternal(tx, exchangeBaseUrl);
- });
+ },
+ );
const accounts = details?.wireInfo.accounts ?? [];
for (const account of accounts) {
const res = parsePaytoUri(account.payto_uri);
@@ -1641,15 +1635,13 @@ export async function getExchangeTos(
acceptLanguage,
);
- await ws.db
- .mktx((x) => [x.exchanges, x.exchangeDetails])
- .runReadWrite(async (tx) => {
- const updateExchangeEntry = await tx.exchanges.get(exchangeBaseUrl);
- if (updateExchangeEntry) {
- updateExchangeEntry.tosCurrentEtag = tosDownload.tosEtag;
- await tx.exchanges.put(updateExchangeEntry);
- }
- });
+ await ws.db.runReadWriteTx(["exchanges"], async (tx) => {
+ const updateExchangeEntry = await tx.exchanges.get(exchangeBaseUrl);
+ if (updateExchangeEntry) {
+ updateExchangeEntry.tosCurrentEtag = tosDownload.tosEtag;
+ await tx.exchanges.put(updateExchangeEntry);
+ }
+ });
return {
acceptedEtag: exch.tosAcceptedEtag,
@@ -1738,7 +1730,7 @@ export async function listExchanges(
*/
export async function markExchangeUsed(
ws: InternalWalletState,
- tx: GetReadWriteAccess<{ exchanges: typeof WalletStoresV1.exchanges }>,
+ tx: WalletDbReadWriteTransaction<["exchanges"]>,
exchangeBaseUrl: string,
): Promise<{ notif: WalletNotification | undefined }> {
exchangeBaseUrl = canonicalizeBaseUrl(exchangeBaseUrl);
@@ -1780,9 +1772,9 @@ export async function getExchangeDetailedInfo(
ws: InternalWalletState,
exchangeBaseurl: string,
): Promise<ExchangeDetailedResponse> {
- const exchange = await ws.db
- .mktx((x) => [x.exchanges, x.exchangeDetails, x.denominations])
- .runReadOnly(async (tx) => {
+ const exchange = await ws.db.runReadOnlyTx(
+ ["exchanges", "exchangeDetails", "denominations"],
+ async (tx) => {
const ex = await tx.exchanges.get(exchangeBaseurl);
const dp = ex?.detailsPointer;
if (!dp) {
@@ -1815,7 +1807,8 @@ export async function getExchangeDetailedInfo(
},
denominations,
};
- });
+ },
+ );
if (!exchange) {
throw Error(`exchange with base url "${exchangeBaseurl}" not found`);
@@ -1930,7 +1923,7 @@ export async function getExchangeDetailedInfo(
async function internalGetExchangeResources(
ws: InternalWalletState,
- tx: DbReadOnlyTransactionArr<
+ tx: DbReadOnlyTransaction<
typeof WalletStoresV1,
["exchanges", "coins", "withdrawalGroups"]
>,