taler-typescript-core

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

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:
Mpackages/taler-wallet-core/src/common.ts | 45++++++++++++++++++++++-----------------------
Mpackages/taler-wallet-core/src/db-common.ts | 204+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpackages/taler-wallet-core/src/db-indexeddb.ts | 215++++---------------------------------------------------------------------------
Mpackages/taler-wallet-core/src/dbtx-indexeddb.ts | 77++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mpackages/taler-wallet-core/src/dbtx.ts | 49+++++++++++++++++++++++++++++++++++++++++++++----
Mpackages/taler-wallet-core/src/pay-merchant.ts | 8++++----
Mpackages/taler-wallet-core/src/recoup.ts | 16++++++++--------
Mpackages/taler-wallet-core/src/refresh.ts | 18+++++++++---------
Mpackages/taler-wallet-core/src/withdraw.ts | 8++++----
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;