commit 5c90675104b7df6875cb5b3402d7e51a41dced6b
parent 3dc66c6c9731a07c843adb95802910a546799f38
Author: Florian Dold <dold@taler.net>
Date: Sat, 18 Jul 2026 20:25:53 +0200
db: move coin types to db-common.ts, add coin accessors
Diffstat:
9 files changed, 379 insertions(+), 261 deletions(-)
diff --git a/packages/taler-wallet-core/src/common.ts b/packages/taler-wallet-core/src/common.ts
@@ -66,10 +66,10 @@ import {
ExchangeEntryDbUpdateStatus,
timestampPreciseToDb,
WalletRetryInfo,
+ WalletCoinHistory,
+ WalletCoin,
} from "./db-common.js";
import {
- CoinHistoryRecord,
- CoinRecord,
DepositGroupRecord,
ExchangeEntryRecord,
PeerPullCreditRecord,
@@ -81,6 +81,7 @@ import {
RefreshGroupRecord,
WithdrawalGroupRecord,
} from "./db-indexeddb.js";
+import { WalletDbTransaction } from "./dbtx.js";
import { ReadyExchangeSummary } from "./exchanges.js";
import { createRefreshGroup } from "./refresh.js";
import { BalanceEffect, applyNotifyTransition } from "./transactions.js";
@@ -109,56 +110,55 @@ export interface TokensSpendInfo {
export async function makeCoinsVisible(
wex: WalletExecutionContext,
- tx: LegacyWalletTxHandle,
+ tx: WalletDbTransaction,
transactionId: string,
): Promise<void> {
- const coins =
- await tx.coins.indexes.bySourceTransactionId.getAll(transactionId);
+ const coins = await tx.getCoinsBySourceTransaction(transactionId);
for (const coinRecord of coins) {
if (!coinRecord.visible) {
coinRecord.visible = 1;
- await tx.coins.put(coinRecord);
+ await tx.upsertCoin(coinRecord);
const ageRestriction = coinRecord.maxAge;
- const car = await tx.coinAvailability.get([
+ const car = await tx.getCoinAvailability(
coinRecord.exchangeBaseUrl,
coinRecord.denomPubHash,
ageRestriction,
- ]);
+ );
if (!car) {
logger.error("missing coin availability record");
continue;
}
const visCount = car.visibleCoinCount ?? 0;
car.visibleCoinCount = visCount + 1;
- await tx.coinAvailability.put(car);
+ await tx.upsertCoinAvailability(car);
}
}
}
export async function makeCoinAvailable(
wex: WalletExecutionContext,
- tx: LegacyWalletTxHandle,
- coinRecord: CoinRecord,
+ tx: WalletDbTransaction,
+ coinRecord: WalletCoin,
): Promise<void> {
checkLogicInvariant(coinRecord.status === CoinStatus.Fresh);
- const existingCoin = await tx.coins.get(coinRecord.coinPub);
+ const existingCoin = await tx.getCoin(coinRecord.coinPub);
if (existingCoin) {
return;
}
- const denom = await tx.denominations.get([
+ const denom = await tx.getDenomination(
coinRecord.exchangeBaseUrl,
coinRecord.denomPubHash,
- ]);
+ );
checkDbInvariant(
!!denom,
`denomination of a coin is missing hash: ${coinRecord.denomPubHash}`,
);
const ageRestriction = coinRecord.maxAge;
- let car = await tx.coinAvailability.get([
+ let car = await tx.getCoinAvailability(
coinRecord.exchangeBaseUrl,
coinRecord.denomPubHash,
ageRestriction,
- ]);
+ );
if (!car) {
car = {
maxAge: ageRestriction,
@@ -172,8 +172,8 @@ export async function makeCoinAvailable(
};
}
car.freshCoinCount++;
- await tx.coins.put(coinRecord);
- await tx.coinAvailability.put(car);
+ await tx.upsertCoin(coinRecord);
+ await tx.upsertCoinAvailability(car);
}
/**
@@ -239,7 +239,7 @@ export async function spendCoins(
coinAvailability.visibleCoinCount--;
}
}
- let histEntry: CoinHistoryRecord | undefined = await tx.coinHistory.get(
+ let histEntry: WalletCoinHistory | undefined = await tx.coinHistory.get(
coin.coinPub,
);
if (!histEntry) {
@@ -269,7 +269,7 @@ export async function spendCoins(
}
export async function spendTokens(
- tx: LegacyWalletTxHandle,
+ tx: WalletDbTransaction,
tsi: TokensSpendInfo,
): Promise<void> {
if (tsi.tokenPubs.length === 0) {
@@ -277,7 +277,7 @@ export async function spendTokens(
}
for (const pub of tsi.tokenPubs) {
- const token = await tx.tokens.get(pub);
+ const token = await tx.getToken(pub);
if (!token) {
throw Error(`token allocated for payment doesn't exist anymore`);
}
@@ -291,8 +291,7 @@ export async function spendTokens(
}
logger.trace(`spending token ${token.tokenUsePub} in ${tsi.transactionId}`);
- token.transactionId = tsi.transactionId;
- await tx.tokens.put(token);
+ await tx.setTokenTransactionId(token.tokenUsePub, tsi.transactionId);
}
}
diff --git a/packages/taler-wallet-core/src/db-common.ts b/packages/taler-wallet-core/src/db-common.ts
@@ -29,6 +29,9 @@ import {
DenominationPubKey,
Amounts,
DenominationInfo,
+ CoinStatus,
+ AgeCommitmentProof,
+ TransactionIdStr,
} from "@gnu-taler/taler-util";
declare const symDbProtocolTimestamp: unique symbol;
@@ -187,6 +190,207 @@ export interface WalletContractTerms {
contractTermsRaw: any;
}
+export interface WalletWithdrawCoinSource {
+ type: CoinSourceType.Withdraw;
+
+ /**
+ * Can be the empty string for orphaned coins.
+ */
+ withdrawalGroupId: string;
+
+ /**
+ * Index of the coin in the withdrawal session.
+ */
+ coinIndex: number;
+
+ /**
+ * Reserve public key for the reserve we got this coin from.
+ */
+ reservePub: string;
+}
+
+export interface WalletRefreshCoinSource {
+ type: CoinSourceType.Refresh;
+ refreshGroupId: string;
+ oldCoinPub: string;
+}
+
+export interface WalletRewardCoinSource {
+ type: CoinSourceType.Reward;
+ walletRewardId: string;
+ coinIndex: number;
+}
+
+/**
+ * WalletCoin as stored in the "coins" data store
+ * of the wallet database.
+ */
+export interface WalletCoin {
+ /**
+ * Where did the coin come from? Used for recouping coins.
+ */
+ coinSource: WalletCoinSource;
+
+ /**
+ * Source transaction ID of the coin.
+ *
+ * Used to make the coin visible after the transaction
+ * has entered a final state.
+ */
+ sourceTransactionId?: string;
+
+ /**
+ * Public key of the coin.
+ */
+ coinPub: string;
+
+ /**
+ * Private key to authorize operations on the coin.
+ */
+ coinPriv: string;
+
+ /**
+ * Hash of the public key that signs the coin.
+ */
+ denomPubHash: string;
+
+ /**
+ * Unblinded signature by the exchange.
+ */
+ denomSig: UnblindedDenominationSignature;
+
+ /**
+ * Base URL that identifies the exchange from which we got the
+ * coin.
+ */
+ exchangeBaseUrl: string;
+
+ /**
+ * Blinding key used when withdrawing the coin.
+ * Potentionally used again during payback.
+ */
+ blindingKey: string;
+
+ /**
+ * Hash of the coin envelope.
+ *
+ * Stored here for indexing purposes, so that when looking at a
+ * reserve history, we can quickly find the coin for a withdrawal transaction.
+ */
+ coinEvHash: string;
+
+ /**
+ * Status of the coin.
+ */
+ status: CoinStatus;
+
+ /**
+ * Non-zero for visible.
+ *
+ * A coin is visible when it is fresh and the
+ * source transaction is in a final state.
+ */
+ visible?: number;
+
+ /**
+ * Maximum age of purchases that can be made with this coin.
+ *
+ * (Used for indexing, redundant with {@link ageCommitmentProof}).
+ */
+ maxAge: number;
+
+ ageCommitmentProof: AgeCommitmentProof | undefined;
+}
+
+/**
+ * Availability of coins of a given denomination (and age restriction!).
+ *
+ * We can't store this information with the denomination record, as one denomination
+ * can be withdrawn with multiple age restrictions.
+ */
+export interface WalletCoinAvailability {
+ currency: string;
+ value: AmountString;
+ denomPubHash: string;
+ exchangeBaseUrl: string;
+ exchangeMasterPub?: string;
+
+ /**
+ * Age restriction on the coin, or 0 for no age restriction (or
+ * denomination without age restriction support).
+ */
+ maxAge: number;
+
+ /**
+ * Number of fresh coins of this denomination that are available.
+ */
+ freshCoinCount: number;
+
+ /**
+ * Number of fresh coins that are available
+ * and visible, i.e. the source transaction is in
+ * a final state.
+ */
+ visibleCoinCount: number;
+
+ /**
+ * Number of coins that we expect to obtain via a pending refresh.
+ */
+ pendingRefreshOutputCount?: number;
+}
+
+/**
+ * History event for a coin from the wallet's perspective.
+ *
+ * The history might reference transactions that were already deleted from the wallet.
+ */
+export interface WalletCoinHistory {
+ coinPub: string;
+ /**
+ * History items for the coin.
+ *
+ * We store this as an array in the object store, as the coin history
+ * is pretty much always very small.
+ */
+ history: WalletCoinHistoryItem[];
+}
+
+export type WalletCoinSource =
+ | WalletWithdrawCoinSource
+ | WalletRefreshCoinSource
+ | WalletRewardCoinSource;
+
+/**
+ * History item for a coin.
+ *
+ * DB-specific format,
+ */
+export type WalletCoinHistoryItem =
+ | {
+ type: "withdraw";
+ transactionId: TransactionIdStr;
+ }
+ | {
+ type: "spend";
+ transactionId: TransactionIdStr;
+ amount: AmountString;
+ }
+ | {
+ type: "refresh";
+ transactionId: TransactionIdStr;
+ amount: AmountString;
+ }
+ | {
+ type: "recoup";
+ transactionId: TransactionIdStr;
+ amount: AmountString;
+ }
+ | {
+ type: "refund";
+ transactionId: TransactionIdStr;
+ amount: AmountString;
+ };
+
/**
* How a coin came into the wallet.
*/
diff --git a/packages/taler-wallet-core/src/db-indexeddb.ts b/packages/taler-wallet-core/src/db-indexeddb.ts
@@ -116,6 +116,14 @@ import {
WalletTransactionMeta,
WalletOperationRetry,
WalletContractTerms,
+ WalletCoin,
+ WalletCoinAvailability,
+ WalletCoinHistory,
+ WalletCoinSource,
+ WalletCoinHistoryItem,
+ WalletWithdrawCoinSource,
+ WalletRefreshCoinSource,
+ WalletRewardCoinSource,
RefundReason,
ExchangeMigrationReason,
} from "./db-common.js";
@@ -529,123 +537,6 @@ export interface PlanchetRecord {
ageCommitmentProof?: AgeCommitmentProof;
}
-export interface WithdrawCoinSource {
- type: CoinSourceType.Withdraw;
-
- /**
- * Can be the empty string for orphaned coins.
- */
- withdrawalGroupId: string;
-
- /**
- * Index of the coin in the withdrawal session.
- */
- coinIndex: number;
-
- /**
- * Reserve public key for the reserve we got this coin from.
- */
- reservePub: string;
-}
-
-export interface RefreshCoinSource {
- type: CoinSourceType.Refresh;
- refreshGroupId: string;
- oldCoinPub: string;
-}
-
-export interface RewardCoinSource {
- type: CoinSourceType.Reward;
- walletRewardId: string;
- coinIndex: number;
-}
-
-export type CoinSource =
- | WithdrawCoinSource
- | RefreshCoinSource
- | RewardCoinSource;
-
-/**
- * CoinRecord as stored in the "coins" data store
- * of the wallet database.
- */
-export interface CoinRecord {
- /**
- * Where did the coin come from? Used for recouping coins.
- */
- coinSource: CoinSource;
-
- /**
- * Source transaction ID of the coin.
- *
- * Used to make the coin visible after the transaction
- * has entered a final state.
- */
- sourceTransactionId?: string;
-
- /**
- * Public key of the coin.
- */
- coinPub: string;
-
- /**
- * Private key to authorize operations on the coin.
- */
- coinPriv: string;
-
- /**
- * Hash of the public key that signs the coin.
- */
- denomPubHash: string;
-
- /**
- * Unblinded signature by the exchange.
- */
- denomSig: UnblindedDenominationSignature;
-
- /**
- * Base URL that identifies the exchange from which we got the
- * coin.
- */
- exchangeBaseUrl: string;
-
- /**
- * Blinding key used when withdrawing the coin.
- * Potentionally used again during payback.
- */
- blindingKey: string;
-
- /**
- * Hash of the coin envelope.
- *
- * Stored here for indexing purposes, so that when looking at a
- * reserve history, we can quickly find the coin for a withdrawal transaction.
- */
- coinEvHash: string;
-
- /**
- * Status of the coin.
- */
- status: CoinStatus;
-
- /**
- * Non-zero for visible.
- *
- * A coin is visible when it is fresh and the
- * source transaction is in a final state.
- */
- visible?: number;
-
- /**
- * Maximum age of purchases that can be made with this coin.
- *
- * (Used for indexing, redundant with {@link ageCommitmentProof}).
- */
- maxAge: number;
-
- ageCommitmentProof: AgeCommitmentProof | undefined;
-}
-
/**
* Object to be hashed for use as a grouping key for token listings, such that
* any change in token family details results in a separate list item.
@@ -805,53 +696,6 @@ export namespace TokenRecord {
}
}
-/**
- * History item for a coin.
- *
- * DB-specific format,
- */
-export type DbWalletCoinHistoryItem =
- | {
- type: "withdraw";
- transactionId: TransactionIdStr;
- }
- | {
- type: "spend";
- transactionId: TransactionIdStr;
- amount: AmountString;
- }
- | {
- type: "refresh";
- transactionId: TransactionIdStr;
- amount: AmountString;
- }
- | {
- type: "recoup";
- transactionId: TransactionIdStr;
- amount: AmountString;
- }
- | {
- type: "refund";
- transactionId: TransactionIdStr;
- amount: AmountString;
- };
-
-/**
- * History event for a coin from the wallet's perspective.
- *
- * The history might reference transactions that were already deleted from the wallet.
- */
-export interface CoinHistoryRecord {
- coinPub: string;
- /**
- * History items for the coin.
- *
- * We store this as an array in the object store, as the coin history
- * is pretty much always very small.
- */
- history: DbWalletCoinHistoryItem[];
-}
-
export interface RefreshGroupPerExchangeInfo {
/**
* (Expected) output once the refresh group succeeded.
@@ -1830,43 +1674,6 @@ export interface ReserveRecord {
amlReview?: boolean;
}
-/**
- * Availability of coins of a given denomination (and age restriction!).
- *
- * We can't store this information with the denomination record, as one denomination
- * can be withdrawn with multiple age restrictions.
- */
-export interface CoinAvailabilityRecord {
- currency: string;
- value: AmountString;
- denomPubHash: string;
- exchangeBaseUrl: string;
- exchangeMasterPub?: string;
-
- /**
- * Age restriction on the coin, or 0 for no age restriction (or
- * denomination without age restriction support).
- */
- maxAge: number;
-
- /**
- * Number of fresh coins of this denomination that are available.
- */
- freshCoinCount: number;
-
- /**
- * Number of fresh coins that are available
- * and visible, i.e. the source transaction is in
- * a final state.
- */
- visibleCoinCount: number;
-
- /**
- * Number of coins that we expect to obtain via a pending refresh.
- */
- pendingRefreshOutputCount?: number;
-}
-
export interface DbExchangeHandle {
url: string;
exchangeMasterPub: string;
@@ -2175,7 +1982,7 @@ export const WalletIndexedDbStoresV1 = {
}),
coinAvailability: describeStore(
"coinAvailability",
- describeContents<CoinAvailabilityRecord>({
+ describeContents<WalletCoinAvailability>({
keyPath: ["exchangeBaseUrl", "denomPubHash", "maxAge"],
}),
{
@@ -2191,13 +1998,13 @@ export const WalletIndexedDbStoresV1 = {
),
coinHistory: describeStoreV2({
storeName: "coinHistory",
- recordCodec: passthroughCodec<CoinHistoryRecord>(),
+ recordCodec: passthroughCodec<WalletCoinHistory>(),
keyPath: "coinPub",
versionAdded: 11,
}),
coins: describeStore(
"coins",
- describeContents<CoinRecord>({
+ describeContents<WalletCoin>({
keyPath: "coinPub",
}),
{
diff --git a/packages/taler-wallet-core/src/dbtx-indexeddb.ts b/packages/taler-wallet-core/src/dbtx-indexeddb.ts
@@ -29,6 +29,7 @@ import {
MailboxConfiguration,
MailboxMessageRecord,
ScopeInfo,
+ TransactionIdStr,
stringifyScopeInfo,
assertUnreachable,
ScopeType,
@@ -49,13 +50,14 @@ import {
DenominationVerificationStatus,
OPERATION_STATUS_NONFINAL_FIRST,
OPERATION_STATUS_NONFINAL_LAST,
+ WalletCoinAvailability,
+ WalletCoinHistory,
+ WalletCoin,
} from "./db-common.js";
import type {
ExchangeEntryRecord,
- CoinAvailabilityRecord,
RefreshGroupRecord,
WithdrawalGroupRecord,
- CoinRecord,
DepositGroupRecord,
ExchangeDetailsRecord,
DonationSummaryRecord,
@@ -258,6 +260,53 @@ export class IdbWalletTransaction implements WalletDbTransaction {
});
}
+ async getCoin(coinPub: string): Promise<WalletCoin | undefined> {
+ const tx = this.tx;
+ return await tx.coins.get(coinPub);
+ }
+
+ async upsertCoin(coin: WalletCoin): Promise<void> {
+ const tx = this.tx;
+ await tx.coins.put(coin);
+ }
+
+ async getCoinsBySourceTransaction(
+ transactionId: string,
+ ): Promise<WalletCoin[]> {
+ const tx = this.tx;
+ return await tx.coins.indexes.bySourceTransactionId.getAll(transactionId);
+ }
+
+ async getCoinAvailability(
+ exchangeBaseUrl: string,
+ denomPubHash: string,
+ maxAge: number,
+ ): Promise<WalletCoinAvailability | undefined> {
+ const tx = this.tx;
+ return await tx.coinAvailability.get([
+ exchangeBaseUrl,
+ denomPubHash,
+ maxAge,
+ ]);
+ }
+
+ async upsertCoinAvailability(rec: WalletCoinAvailability): Promise<void> {
+ const tx = this.tx;
+ await tx.coinAvailability.put(rec);
+ }
+
+ async getCoinHistory(
+ coinPub: string,
+ ): Promise<WalletCoinHistory | undefined> {
+ const tx = this.tx;
+ return await tx.coinHistory.get(coinPub);
+ }
+
+ async upsertCoinHistory(rec: WalletCoinHistory): Promise<void> {
+ const tx = this.tx;
+ await tx.coinHistory.put(rec);
+ }
+
async listTokens(): Promise<WalletToken[]> {
const tx = this.tx;
const records = await tx.tokens.getAll();
@@ -286,6 +335,24 @@ export class IdbWalletTransaction implements WalletDbTransaction {
}));
}
+ async getToken(tokenUsePub: string): Promise<WalletToken | undefined> {
+ const tx = this.tx;
+ return await tx.tokens.get(tokenUsePub);
+ }
+
+ async setTokenTransactionId(
+ tokenUsePub: string,
+ transactionId: TransactionIdStr,
+ ): Promise<void> {
+ const tx = this.tx;
+ const rec = await tx.tokens.get(tokenUsePub);
+ if (!rec) {
+ throw Error("token not found");
+ }
+ rec.transactionId = transactionId;
+ await tx.tokens.put(rec);
+ }
+
async deleteToken(tokenUsePub: string): Promise<void> {
const tx = this.tx;
await tx.tokens.delete(tokenUsePub);
@@ -626,7 +693,7 @@ export class IdbWalletTransaction implements WalletDbTransaction {
return await this.tx.exchanges.iter().toArray();
}
- async getCoinAvailabilities(): Promise<CoinAvailabilityRecord[]> {
+ async getCoinAvailabilities(): Promise<WalletCoinAvailability[]> {
return await this.tx.coinAvailability.iter().toArray();
}
@@ -670,8 +737,8 @@ export class IdbWalletTransaction implements WalletDbTransaction {
return await this.tx.purchases.indexes.byStatus.getAll(getActiveKeyRange());
}
- async getCoinsByPubs(coinPubs: string[]): Promise<CoinRecord[]> {
- const coins: CoinRecord[] = [];
+ async getCoinsByPubs(coinPubs: string[]): Promise<WalletCoin[]> {
+ const coins: WalletCoin[] = [];
for (const pub of coinPubs) {
const coin = await this.tx.coins.get(pub);
if (coin) {
diff --git a/packages/taler-wallet-core/src/dbtx.ts b/packages/taler-wallet-core/src/dbtx.ts
@@ -40,6 +40,7 @@ import {
MailboxConfiguration,
MailboxMessageRecord,
ScopeInfo,
+ TransactionIdStr,
WalletNotification,
} from "@gnu-taler/taler-util";
import {
@@ -54,13 +55,14 @@ import {
WalletOperationRetry,
WalletContractTerms,
DenominationVerificationStatus,
+ WalletCoinAvailability,
+ WalletCoinHistory,
+ WalletCoin,
} from "./db-common.js";
import type {
ExchangeEntryRecord,
- CoinAvailabilityRecord,
RefreshGroupRecord,
WithdrawalGroupRecord,
- CoinRecord,
DepositGroupRecord,
ExchangeDetailsRecord,
DonationSummaryRecord,
@@ -172,12 +174,51 @@ export interface WalletDbTransaction {
*/
upsertContractTerms(rec: WalletContractTerms): Promise<void>;
+ getCoin(coinPub: string): Promise<WalletCoin | undefined>;
+
+ upsertCoin(coin: WalletCoin): Promise<void>;
+
+ /**
+ * Get all coins whose source transaction is the given transaction.
+ */
+ getCoinsBySourceTransaction(transactionId: string): Promise<WalletCoin[]>;
+
+ getCoinAvailability(
+ exchangeBaseUrl: string,
+ denomPubHash: string,
+ maxAge: number,
+ ): Promise<WalletCoinAvailability | undefined>;
+
+ upsertCoinAvailability(rec: WalletCoinAvailability): Promise<void>;
+
+ getCoinHistory(coinPub: string): Promise<WalletCoinHistory | undefined>;
+
+ upsertCoinHistory(rec: WalletCoinHistory): Promise<void>;
+
/**
* List all stored wallet tokens.
*/
listTokens(): Promise<WalletToken[]>;
/**
+ * Get a wallet token by its token use public key.
+ */
+ getToken(tokenUsePub: string): Promise<WalletToken | undefined>;
+
+ /**
+ * Mark a token as spent in a transaction.
+ *
+ * This is a targeted update rather than an upsert of a whole WalletToken,
+ * because WalletToken is a narrower projection of the stored record: it does
+ * not carry blindingKey, tokenEv or tokenEvHash, so a read-modify-write
+ * through it would silently drop them.
+ */
+ setTokenTransactionId(
+ tokenUsePub: string,
+ transactionId: TransactionIdStr,
+ ): Promise<void>;
+
+ /**
* Delete a wallet token by its token use public key.
*/
deleteToken(tokenUsePub: string): Promise<void>;
@@ -284,7 +325,7 @@ export interface WalletDbTransaction {
getExchanges(): Promise<ExchangeEntryRecord[]>;
- getCoinAvailabilities(): Promise<CoinAvailabilityRecord[]>;
+ getCoinAvailabilities(): Promise<WalletCoinAvailability[]>;
getActiveRefreshGroups(): Promise<RefreshGroupRecord[]>;
@@ -300,7 +341,7 @@ export interface WalletDbTransaction {
getActivePurchases(): Promise<PurchaseRecord[]>;
- getCoinsByPubs(coinPubs: string[]): Promise<CoinRecord[]>;
+ getCoinsByPubs(coinPubs: string[]): Promise<WalletCoin[]>;
getActiveDepositGroups(): Promise<DepositGroupRecord[]>;
diff --git a/packages/taler-wallet-core/src/pay-merchant.ts b/packages/taler-wallet-core/src/pay-merchant.ts
@@ -151,9 +151,9 @@ import {
timestampProtocolFromDb,
timestampProtocolToDb,
WalletDenomination,
+ WalletCoin,
} from "./db-common.js";
import {
- CoinRecord,
DbCoinSelection,
DonationPlanchetRecord,
PurchaseRecord,
@@ -1732,7 +1732,7 @@ async function reselectCoinsTx(
}
if (p.payInfo.payTokenSelection) {
- await spendTokens(tx, {
+ await spendTokens(tx.wtx, {
transactionId: ctx.transactionId,
tokenPubs: p.payInfo.payTokenSelection.tokenPubs,
});
@@ -2307,7 +2307,7 @@ export async function generateDepositPermissions(
): Promise<CoinDepositPermission[]> {
const depositPermissions: CoinDepositPermission[] = [];
const coinWithDenom: Array<{
- coin: CoinRecord;
+ coin: WalletCoin;
denom: WalletDenomination;
}> = [];
await wex.runLegacyWalletDbTx(async (tx) => {
@@ -2953,7 +2953,7 @@ export async function confirmPay(
p.purchaseStatus = PurchaseStatus.PendingPaying;
await h.update(p);
if (p.payInfo.payTokenSelection) {
- await spendTokens(tx, {
+ await spendTokens(tx.wtx, {
tokenPubs: p.payInfo.payTokenSelection.tokenPubs,
transactionId: ctx.transactionId,
});
diff --git a/packages/taler-wallet-core/src/recoup.ts b/packages/taler-wallet-core/src/recoup.ts
@@ -55,13 +55,13 @@ import {
RecoupOperationStatus,
WithdrawalGroupStatus,
timestampPreciseToDb,
+ WalletCoin,
+ WalletRefreshCoinSource,
+ WalletWithdrawCoinSource,
} from "./db-common.js";
import {
- CoinRecord,
CoinSourceType,
RecoupGroupRecord,
- RefreshCoinSource,
- WithdrawCoinSource,
WithdrawalRecordType,
} from "./db-indexeddb.js";
import { createRefreshGroup } from "./refresh.js";
@@ -101,7 +101,7 @@ async function recoupRewardCoin(
wex: WalletExecutionContext,
recoupGroupId: string,
coinIdx: number,
- coin: CoinRecord,
+ coin: WalletCoin,
): Promise<void> {
// We can't really recoup a coin we got via tipping.
// Thus we just put the coin to sleep.
@@ -122,8 +122,8 @@ async function recoupRefreshCoin(
wex: WalletExecutionContext,
recoupGroupId: string,
coinIdx: number,
- coin: CoinRecord,
- cs: RefreshCoinSource,
+ coin: WalletCoin,
+ cs: WalletRefreshCoinSource,
): Promise<void> {
const d = await wex.runLegacyWalletDbTx(async (tx) => {
const denomInfo = await getDenomInfo(
@@ -223,8 +223,8 @@ export async function recoupWithdrawCoin(
wex: WalletExecutionContext,
recoupGroupId: string,
coinIdx: number,
- coin: CoinRecord,
- cs: WithdrawCoinSource,
+ coin: WalletCoin,
+ cs: WalletWithdrawCoinSource,
): Promise<void> {
const reservePub = cs.reservePub;
const denomInfo = await wex.runLegacyWalletDbTx(async (tx) => {
diff --git a/packages/taler-wallet-core/src/refresh.ts b/packages/taler-wallet-core/src/refresh.ts
@@ -96,11 +96,11 @@ import {
timestampPreciseFromDb,
timestampPreciseToDb,
WalletDenomination,
+ WalletCoinAvailability,
+ WalletCoinHistory,
+ WalletCoin,
} from "./db-common.js";
import {
- CoinAvailabilityRecord,
- CoinHistoryRecord,
- CoinRecord,
CoinSourceType,
RefreshGroupPerExchangeInfo,
RefreshGroupRecord,
@@ -421,7 +421,7 @@ async function getCoinAvailabilityForDenom(
tx: LegacyWalletTxHandle,
denom: DenominationInfo,
ageRestriction: number,
-): Promise<CoinAvailabilityRecord> {
+): Promise<WalletCoinAvailability> {
let car = await tx.coinAvailability.get([
denom.exchangeBaseUrl,
denom.denomPubHash,
@@ -853,7 +853,7 @@ async function handleRefreshMeltConflict(
coinIndex: number,
errDetails: TalerErrorDetail,
meltValueWithFee: AmountLike,
- oldCoin: CoinRecord,
+ oldCoin: WalletCoin,
): Promise<void> {
// Just log for better diagnostics here, error status
// will be handled later.
@@ -1136,7 +1136,7 @@ async function refreshReveal(
resEvSigs = reveal.ev_sigs;
planchets = derived.planchets;
- const coins: CoinRecord[] = [];
+ const coins: WalletCoin[] = [];
for (let i = 0; i < refreshSession.newDenoms.length; i++) {
const ncd = newCoinDenoms[i];
@@ -1154,7 +1154,7 @@ async function refreshReveal(
},
evSig,
});
- const coin: CoinRecord = {
+ const coin: WalletCoin = {
blindingKey: pc.blindingKey,
coinPriv: pc.coinPriv,
coinPub: pc.coinPub,
@@ -1383,7 +1383,7 @@ export async function processRefreshGroup(
);
rg.operationStatus = RefreshOperationStatus.Finished;
}
- await makeCoinsVisible(wex, tx, ctx.transactionId);
+ await makeCoinsVisible(wex, tx.wtx, ctx.transactionId);
await h.update(rg);
return true;
}
@@ -1568,7 +1568,7 @@ async function applyRefreshToOldCoins(
default:
assertUnreachable(coin.status);
}
- let histEntry: CoinHistoryRecord | undefined = await tx.coinHistory.get(
+ let histEntry: WalletCoinHistory | undefined = await tx.coinHistory.get(
coin.coinPub,
);
if (!histEntry) {
diff --git a/packages/taler-wallet-core/src/withdraw.ts b/packages/taler-wallet-core/src/withdraw.ts
@@ -146,9 +146,9 @@ import {
timestampProtocolToDb,
WalletDenomination,
WalletOperationRetry,
+ WalletCoin,
} from "./db-common.js";
import {
- CoinRecord,
CoinSourceType,
PlanchetRecord,
WgInfo,
@@ -1942,7 +1942,7 @@ async function processPlanchetVerifyAndStoreCoin(
throw Error("unsupported cipher");
}
- const coin: CoinRecord = {
+ const coin: WalletCoin = {
blindingKey: planchet.blindingKey,
coinPriv: planchet.coinPriv,
coinPub: planchet.coinPub,
@@ -1974,7 +1974,7 @@ async function processPlanchetVerifyAndStoreCoin(
p.planchetStatus = PlanchetStatus.WithdrawalDone;
p.lastError = undefined;
await tx.planchets.put(p);
- await makeCoinAvailable(wex, tx, coin);
+ await makeCoinAvailable(wex, tx.wtx, coin);
});
}
@@ -2746,7 +2746,7 @@ async function processWithdrawalGroupPendingReady(
) {
wg.timestampFinish = timestampPreciseToDb(TalerPreciseTimestamp.now());
wg.status = WithdrawalGroupStatus.Done;
- await makeCoinsVisible(wex, tx, ctx.transactionId);
+ await makeCoinsVisible(wex, tx.wtx, ctx.transactionId);
}
await h.update(wg);
return wg;