gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] 01/03: wallet-core: use typed microsecond timestamps


From: gnunet
Subject: [taler-wallet-core] 01/03: wallet-core: use typed microsecond timestamps in DB
Date: Thu, 14 Sep 2023 19:18:12 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository wallet-core.

commit f4587c44fd6a6d76384cd671550890255c3fe650
Author: Florian Dold <florian@dold.me>
AuthorDate: Wed Sep 13 16:08:51 2023 +0200

    wallet-core: use typed microsecond timestamps in DB
---
 packages/taler-util/src/time.ts                    |   4 +
 packages/taler-wallet-core/src/db.ts               | 118 ++++++++++++++-------
 .../taler-wallet-core/src/operations/attention.ts  |   3 +-
 .../src/operations/backup/index.ts                 |  31 ++++--
 .../taler-wallet-core/src/operations/deposits.ts   |   9 +-
 .../taler-wallet-core/src/operations/exchanges.ts  |   7 +-
 .../src/operations/pay-merchant.ts                 |  15 +--
 .../src/operations/pay-peer-pull-credit.ts         |  27 +++--
 .../src/operations/pay-peer-pull-debit.ts          |   3 +-
 .../src/operations/pay-peer-push-credit.ts         |  46 +++-----
 .../src/operations/pay-peer-push-debit.ts          |   3 +-
 .../taler-wallet-core/src/operations/pending.ts    |   3 +-
 .../taler-wallet-core/src/operations/recoup.ts     |   5 +-
 .../taler-wallet-core/src/operations/refresh.ts    |  11 +-
 .../taler-wallet-core/src/operations/reward.ts     |  10 +-
 .../src/operations/transactions.ts                 |  35 +++---
 .../taler-wallet-core/src/operations/withdraw.ts   |  29 +++--
 17 files changed, 216 insertions(+), 143 deletions(-)

diff --git a/packages/taler-util/src/time.ts b/packages/taler-util/src/time.ts
index 46ed37637..a63f9b296 100644
--- a/packages/taler-util/src/time.ts
+++ b/packages/taler-util/src/time.ts
@@ -52,6 +52,10 @@ export interface TalerProtocolTimestamp {
   readonly _flavor?: typeof flavor_TalerProtocolTimestamp;
 }
 
+/**
+ * Precise timestamp, typically used in the wallet-core
+ * API but not in other Taler APIs so far.
+ */
 export interface TalerPreciseTimestamp {
   /**
    * Seconds (as integer) since epoch.
diff --git a/packages/taler-wallet-core/src/db.ts 
b/packages/taler-wallet-core/src/db.ts
index 9bf9a29cc..cebe3635b 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -28,7 +28,6 @@ import {
 } from "@gnu-taler/idb-bridge";
 import {
   AgeCommitmentProof,
-  AmountJson,
   AmountString,
   Amounts,
   AttentionInfo,
@@ -45,12 +44,8 @@ import {
   ExchangeAuditor,
   ExchangeGlobalFees,
   HashCodeString,
-  InternationalizedString,
   Logger,
-  MerchantContractTerms,
-  MerchantInfo,
   PayCoinSelection,
-  PeerContractTerms,
   RefreshReason,
   TalerErrorDetail,
   TalerPreciseTimestamp,
@@ -151,6 +146,53 @@ export const CURRENT_DB_CONFIG_KEY = "currentMainDbName";
  */
 export const WALLET_DB_MINOR_VERSION = 1;
 
+declare const symDbProtocolTimestamp: unique symbol;
+
+declare const symDbPreciseTimestamp: unique symbol;
+
+/**
+ * Timestamp, stored as microseconds.
+ *
+ * Always rounded to a full second.
+ */
+export type DbProtocolTimestamp = number & { [symDbProtocolTimestamp]: true };
+
+/**
+ * Timestamp, stored as microseconds.
+ */
+export type DbPreciseTimestamp = number & { [symDbPreciseTimestamp]: true };
+
+const DB_TIMESTAMP_FOREVER = Number.MAX_SAFE_INTEGER;
+
+export function timestampPreciseFromDb(
+  dbTs: DbPreciseTimestamp,
+): TalerPreciseTimestamp {
+  return TalerPreciseTimestamp.fromMilliseconds(Math.floor(dbTs / 1000));
+}
+
+export function timestampOptionalPreciseFromDb(
+  dbTs: DbPreciseTimestamp | undefined,
+): TalerPreciseTimestamp | undefined {
+  if (!dbTs) {
+    return undefined;
+  }
+  return TalerPreciseTimestamp.fromMilliseconds(Math.floor(dbTs / 1000));
+}
+
+export function timestampPreciseToDb(
+  stamp: TalerPreciseTimestamp,
+): DbPreciseTimestamp {
+  if (stamp.t_s === "never") {
+    return DB_TIMESTAMP_FOREVER as DbPreciseTimestamp;
+  } else {
+    let tUs = stamp.t_s * 1000000;
+    if (stamp.off_us) {
+      tUs == stamp.off_us;
+    }
+    return tUs as DbPreciseTimestamp;
+  }
+}
+
 /**
  * Format of the operation status code: 0x0abc_nnnn
 
@@ -217,7 +259,7 @@ export enum WithdrawalGroupStatus {
    * Exchange is doing AML checks.
    */
   PendingAml = 0x0100_0006,
-  SuspendedAml = 0x0100_0006,
+  SuspendedAml = 0x0110_0006,
 
   /**
    * The corresponding withdraw record has been created.
@@ -268,14 +310,14 @@ export interface ReserveBankInfo {
    *
    * Set to undefined if that hasn't happened yet.
    */
-  timestampReserveInfoPosted: TalerPreciseTimestamp | undefined;
+  timestampReserveInfoPosted: DbPreciseTimestamp | undefined;
 
   /**
    * Time when the reserve was confirmed by the bank.
    *
    * Set to undefined if not confirmed yet.
    */
-  timestampBankConfirmed: TalerPreciseTimestamp | undefined;
+  timestampBankConfirmed: DbPreciseTimestamp | undefined;
 }
 
 /**
@@ -488,7 +530,7 @@ export interface ExchangeDetailsRecord {
   tosAccepted:
     | {
         etag: string;
-        timestamp: TalerPreciseTimestamp;
+        timestamp: DbPreciseTimestamp;
       }
     | undefined;
 
@@ -528,7 +570,7 @@ export interface ExchangeDetailsPointer {
    * Timestamp when the (masterPublicKey, currency) pointer
    * has been updated.
    */
-  updateClock: TalerPreciseTimestamp;
+  updateClock: DbPreciseTimestamp;
 }
 
 export enum ExchangeEntryDbRecordStatus {
@@ -567,7 +609,7 @@ export interface ExchangeEntryRecord {
    *
    * Used mostly in the UI to suggest exchanges.
    */
-  lastWithdrawal?: TalerPreciseTimestamp;
+  lastWithdrawal?: DbPreciseTimestamp;
 
   /**
    * Pointer to the current exchange details.
@@ -588,7 +630,7 @@ export interface ExchangeEntryRecord {
   /**
    * Last time when the exchange /keys info was updated.
    */
-  lastUpdate: TalerPreciseTimestamp | undefined;
+  lastUpdate: DbPreciseTimestamp | undefined;
 
   /**
    * Next scheduled update for the exchange.
@@ -816,7 +858,7 @@ export interface RewardRecord {
    * Has the user accepted the tip?  Only after the tip has been accepted coins
    * withdrawn from the tip may be used.
    */
-  acceptedTimestamp: TalerPreciseTimestamp | undefined;
+  acceptedTimestamp: DbPreciseTimestamp | undefined;
 
   /**
    * The tipped amount.
@@ -869,7 +911,7 @@ export interface RewardRecord {
    */
   merchantRewardId: string;
 
-  createdTimestamp: TalerPreciseTimestamp;
+  createdTimestamp: DbPreciseTimestamp;
 
   /**
    * The url to be redirected after the tip is accepted.
@@ -880,7 +922,7 @@ export interface RewardRecord {
    * Timestamp for when the wallet finished picking up the tip
    * from the merchant.
    */
-  pickedUpTimestamp: TalerPreciseTimestamp | undefined;
+  pickedUpTimestamp: DbPreciseTimestamp | undefined;
 
   status: RewardRecordStatus;
 }
@@ -978,12 +1020,12 @@ export interface RefreshGroupRecord {
    */
   statusPerCoin: RefreshCoinStatus[];
 
-  timestampCreated: TalerPreciseTimestamp;
+  timestampCreated: DbPreciseTimestamp;
 
   /**
    * Timestamp when the refresh session finished.
    */
-  timestampFinished: TalerPreciseTimestamp | undefined;
+  timestampFinished: DbPreciseTimestamp | undefined;
 }
 
 /**
@@ -1208,7 +1250,7 @@ export interface PurchaseRecord {
    * Timestamp of the first time that sending a payment to the merchant
    * for this purchase was successful.
    */
-  timestampFirstSuccessfulPay: TalerPreciseTimestamp | undefined;
+  timestampFirstSuccessfulPay: DbPreciseTimestamp | undefined;
 
   merchantPaySig: string | undefined;
 
@@ -1223,19 +1265,19 @@ export interface PurchaseRecord {
   /**
    * When was the purchase record created?
    */
-  timestamp: TalerPreciseTimestamp;
+  timestamp: DbPreciseTimestamp;
 
   /**
    * When was the purchase made?
    * Refers to the time that the user accepted.
    */
-  timestampAccept: TalerPreciseTimestamp | undefined;
+  timestampAccept: DbPreciseTimestamp | undefined;
 
   /**
    * When was the last refund made?
    * Set to 0 if no refund was made on the purchase.
    */
-  timestampLastRefundStatus: TalerPreciseTimestamp | undefined;
+  timestampLastRefundStatus: DbPreciseTimestamp | undefined;
 
   /**
    * Last session signature that we submitted to /pay (if any).
@@ -1285,12 +1327,12 @@ export interface WalletBackupConfState {
   /**
    * Timestamp stored in the last backup.
    */
-  lastBackupTimestamp?: TalerPreciseTimestamp;
+  lastBackupTimestamp?: DbPreciseTimestamp;
 
   /**
    * Last time we tried to do a backup.
    */
-  lastBackupCheckTimestamp?: TalerPreciseTimestamp;
+  lastBackupCheckTimestamp?: DbPreciseTimestamp;
   lastBackupNonce?: string;
 }
 
@@ -1398,12 +1440,12 @@ export interface WithdrawalGroupRecord {
    * When was the withdrawal operation started started?
    * Timestamp in milliseconds.
    */
-  timestampStart: TalerPreciseTimestamp;
+  timestampStart: DbPreciseTimestamp;
 
   /**
    * When was the withdrawal operation completed?
    */
-  timestampFinish?: TalerPreciseTimestamp;
+  timestampFinish?: DbPreciseTimestamp;
 
   /**
    * Current status of the reserve.
@@ -1494,9 +1536,9 @@ export interface RecoupGroupRecord {
 
   exchangeBaseUrl: string;
 
-  timestampStarted: TalerPreciseTimestamp;
+  timestampStarted: DbPreciseTimestamp;
 
-  timestampFinished: TalerPreciseTimestamp | undefined;
+  timestampFinished: DbPreciseTimestamp | undefined;
 
   /**
    * Public keys that identify the coins being recouped
@@ -1530,7 +1572,7 @@ export type BackupProviderState =
     }
   | {
       tag: BackupProviderStateTag.Ready;
-      nextBackupTimestamp: TalerPreciseTimestamp;
+      nextBackupTimestamp: DbPreciseTimestamp;
     }
   | {
       tag: BackupProviderStateTag.Retrying;
@@ -1575,7 +1617,7 @@ export interface BackupProviderRecord {
    * Does NOT correspond to the timestamp of the backup,
    * which only changes when the backup content changes.
    */
-  lastBackupCycleTimestamp?: TalerPreciseTimestamp;
+  lastBackupCycleTimestamp?: DbPreciseTimestamp;
 
   /**
    * Proposal that we're currently trying to pay for.
@@ -1678,9 +1720,9 @@ export interface DepositGroupRecord {
    */
   counterpartyEffectiveDepositAmount: AmountString;
 
-  timestampCreated: TalerPreciseTimestamp;
+  timestampCreated: DbPreciseTimestamp;
 
-  timestampFinished: TalerPreciseTimestamp | undefined;
+  timestampFinished: DbPreciseTimestamp | undefined;
 
   operationStatus: DepositOperationStatus;
 
@@ -1791,7 +1833,7 @@ export interface PeerPushDebitRecord {
 
   purseExpiration: TalerProtocolTimestamp;
 
-  timestampCreated: TalerPreciseTimestamp;
+  timestampCreated: DbPreciseTimestamp;
 
   abortRefreshGroupId?: string;
 
@@ -1864,7 +1906,7 @@ export interface PeerPullCreditRecord {
 
   contractEncNonce: string;
 
-  mergeTimestamp: TalerPreciseTimestamp;
+  mergeTimestamp: DbPreciseTimestamp;
 
   mergeReserveRowId: number;
 
@@ -1916,7 +1958,7 @@ export interface PeerPushPaymentIncomingRecord {
 
   contractPriv: string;
 
-  timestamp: TalerPreciseTimestamp;
+  timestamp: DbPreciseTimestamp;
 
   estimatedAmountEffective: AmountString;
 
@@ -1988,7 +2030,7 @@ export interface PeerPullPaymentIncomingRecord {
 
   contractTermsHash: string;
 
-  timestampCreated: TalerPreciseTimestamp;
+  timestampCreated: DbPreciseTimestamp;
 
   /**
    * Contract priv that we got from the other party.
@@ -2095,7 +2137,7 @@ export interface UserAttentionRecord {
   /**
    * When the user mark this notification as read.
    */
-  read: TalerPreciseTimestamp | undefined;
+  read: DbPreciseTimestamp | undefined;
 }
 
 export interface DbExchangeHandle {
@@ -2139,7 +2181,7 @@ export interface RefundGroupRecord {
   /**
    * Timestamp when the refund group was created.
    */
-  timestampCreated: TalerPreciseTimestamp;
+  timestampCreated: DbPreciseTimestamp;
 
   proposalId: string;
 
@@ -2196,7 +2238,7 @@ export interface RefundItemRecord {
   /**
    * Time when the wallet became aware of the refund.
    */
-  obtainedTime: TalerPreciseTimestamp;
+  obtainedTime: DbPreciseTimestamp;
 
   refundAmount: AmountString;
 
diff --git a/packages/taler-wallet-core/src/operations/attention.ts 
b/packages/taler-wallet-core/src/operations/attention.ts
index 7d84b43ef..1030db0a6 100644
--- a/packages/taler-wallet-core/src/operations/attention.ts
+++ b/packages/taler-wallet-core/src/operations/attention.ts
@@ -31,6 +31,7 @@ import {
   UserAttentionUnreadList,
 } from "@gnu-taler/taler-util";
 import { InternalWalletState } from "../internal-wallet-state.js";
+import { timestampPreciseToDb } from "../index.js";
 
 const logger = new Logger("operations/attention.ts");
 
@@ -94,7 +95,7 @@ export async function markAttentionRequestAsRead(
       if (!ua) throw Error("attention request not found");
       tx.userAttention.put({
         ...ua,
-        read: TalerPreciseTimestamp.now(),
+        read: timestampPreciseToDb(TalerPreciseTimestamp.now()),
       });
     });
 }
diff --git a/packages/taler-wallet-core/src/operations/backup/index.ts 
b/packages/taler-wallet-core/src/operations/backup/index.ts
index a5e8dbd42..7a2771c57 100644
--- a/packages/taler-wallet-core/src/operations/backup/index.ts
+++ b/packages/taler-wallet-core/src/operations/backup/index.ts
@@ -84,6 +84,9 @@ import {
   ConfigRecord,
   ConfigRecordKey,
   WalletBackupConfState,
+  timestampOptionalPreciseFromDb,
+  timestampPreciseFromDb,
+  timestampPreciseToDb,
 } from "../../db.js";
 import { InternalWalletState } from "../../internal-wallet-state.js";
 import { assertUnreachable } from "../../util/assertUnreachable.js";
@@ -259,10 +262,12 @@ async function runBackupCycleForProvider(
         if (!prov) {
           return;
         }
-        prov.lastBackupCycleTimestamp = TalerPreciseTimestamp.now();
+        prov.lastBackupCycleTimestamp = timestampPreciseToDb(
+          TalerPreciseTimestamp.now(),
+        );
         prov.state = {
           tag: BackupProviderStateTag.Ready,
-          nextBackupTimestamp: getNextBackupTimestamp(),
+          nextBackupTimestamp: timestampPreciseToDb(getNextBackupTimestamp()),
         };
         await tx.backupProviders.put(prov);
       });
@@ -361,10 +366,12 @@ async function runBackupCycleForProvider(
           return;
         }
         prov.lastBackupHash = encodeCrock(currentBackupHash);
-        prov.lastBackupCycleTimestamp = TalerPreciseTimestamp.now();
+        prov.lastBackupCycleTimestamp = timestampPreciseToDb(
+          TalerPreciseTimestamp.now(),
+        );
         prov.state = {
           tag: BackupProviderStateTag.Ready,
-          nextBackupTimestamp: getNextBackupTimestamp(),
+          nextBackupTimestamp: timestampPreciseToDb(getNextBackupTimestamp()),
         };
         await tx.backupProviders.put(prov);
       });
@@ -594,7 +601,9 @@ export async function addBackupProvider(
         if (req.activate) {
           oldProv.state = {
             tag: BackupProviderStateTag.Ready,
-            nextBackupTimestamp: TalerPreciseTimestamp.now(),
+            nextBackupTimestamp: timestampPreciseToDb(
+              TalerPreciseTimestamp.now(),
+            ),
           };
           logger.info("setting existing backup provider to active");
           await tx.backupProviders.put(oldProv);
@@ -616,7 +625,9 @@ export async function addBackupProvider(
       if (req.activate) {
         state = {
           tag: BackupProviderStateTag.Ready,
-          nextBackupTimestamp: TalerPreciseTimestamp.now(),
+          nextBackupTimestamp: timestampPreciseToDb(
+            TalerPreciseTimestamp.now(),
+          ),
         };
       } else {
         state = {
@@ -840,7 +851,9 @@ export async function getBackupInfo(
     providers.push({
       active: x.provider.state.tag !== BackupProviderStateTag.Provisional,
       syncProviderBaseUrl: x.provider.baseUrl,
-      lastSuccessfulBackupTimestamp: x.provider.lastBackupCycleTimestamp,
+      lastSuccessfulBackupTimestamp: timestampOptionalPreciseFromDb(
+        x.provider.lastBackupCycleTimestamp,
+      ),
       paymentProposalIds: x.provider.paymentProposalIds,
       lastError:
         x.provider.state.tag === BackupProviderStateTag.Retrying
@@ -917,7 +930,9 @@ async function backupRecoveryTheirs(
             shouldRetryFreshProposal: false,
             state: {
               tag: BackupProviderStateTag.Ready,
-              nextBackupTimestamp: TalerPreciseTimestamp.now(),
+              nextBackupTimestamp: timestampPreciseToDb(
+                TalerPreciseTimestamp.now(),
+              ),
             },
             uids: [encodeCrock(getRandomBytes(32))],
           });
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts 
b/packages/taler-wallet-core/src/operations/deposits.ts
index 2de8f30a1..cb40f8f22 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -73,6 +73,7 @@ import {
   RefreshOperationStatus,
   createRefreshGroup,
   getTotalRefreshCost,
+  timestampPreciseToDb,
 } from "../index.js";
 import { InternalWalletState } from "../internal-wallet-state.js";
 import { assertUnreachable } from "../util/assertUnreachable.js";
@@ -857,7 +858,9 @@ async function processDepositGroupPendingTrack(
         }
       }
       if (allWired) {
-        dg.timestampFinished = TalerPreciseTimestamp.now();
+        dg.timestampFinished = timestampPreciseToDb(
+          TalerPreciseTimestamp.now(),
+        );
         dg.operationStatus = DepositOperationStatus.Finished;
         await tx.depositGroups.put(dg);
       }
@@ -1375,7 +1378,9 @@ export async function createDepositGroup(
     amount: contractData.amount,
     noncePriv: noncePair.priv,
     noncePub: noncePair.pub,
-    timestampCreated: AbsoluteTime.toPreciseTimestamp(now),
+    timestampCreated: timestampPreciseToDb(
+      AbsoluteTime.toPreciseTimestamp(now),
+    ),
     timestampFinished: undefined,
     statusPerCoin: payCoinSel.coinSel.coinPubs.map(
       () => DepositElementStatus.DepositPending,
diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts 
b/packages/taler-wallet-core/src/operations/exchanges.ts
index 43a08ed3b..60d55252a 100644
--- a/packages/taler-wallet-core/src/operations/exchanges.ts
+++ b/packages/taler-wallet-core/src/operations/exchanges.ts
@@ -74,6 +74,7 @@ import {
   ExchangeEntryDbRecordStatus,
   ExchangeEntryDbUpdateStatus,
   isWithdrawableDenom,
+  timestampPreciseToDb,
   WalletDbReadWriteTransaction,
 } from "../index.js";
 import { InternalWalletState, TrustInfo } from "../internal-wallet-state.js";
@@ -174,7 +175,7 @@ export async function acceptExchangeTermsOfService(
       if (d) {
         d.tosAccepted = {
           etag: etag || d.tosCurrentEtag,
-          timestamp: TalerPreciseTimestamp.now(),
+          timestamp: timestampPreciseToDb(TalerPreciseTimestamp.now()),
         };
         await tx.exchangeDetails.put(d);
       }
@@ -753,7 +754,7 @@ export async function updateExchangeFromUrlHandler(
       if (existingDetails?.rowId) {
         newDetails.rowId = existingDetails.rowId;
       }
-      r.lastUpdate = TalerPreciseTimestamp.now();
+      r.lastUpdate = timestampPreciseToDb(TalerPreciseTimestamp.now());
       r.nextUpdateStampMs = AbsoluteTime.toStampMs(
         AbsoluteTime.fromProtocolTimestamp(keysInfo.expiry),
       );
@@ -763,7 +764,7 @@ export async function updateExchangeFromUrlHandler(
         r.detailsPointer = {
           currency: newDetails.currency,
           masterPublicKey: newDetails.masterPublicKey,
-          updateClock: TalerPreciseTimestamp.now(),
+          updateClock: timestampPreciseToDb(TalerPreciseTimestamp.now()),
         };
       }
       await tx.exchanges.put(r);
diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts 
b/packages/taler-wallet-core/src/operations/pay-merchant.ts
index fe0cbeda0..97bf6e2a6 100644
--- a/packages/taler-wallet-core/src/operations/pay-merchant.ts
+++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts
@@ -103,6 +103,7 @@ import {
   RefundGroupStatus,
   RefundItemRecord,
   RefundItemStatus,
+  timestampPreciseToDb,
 } from "../index.js";
 import {
   EXCHANGE_COINS_LOCK,
@@ -644,7 +645,7 @@ async function createPurchase(
     noncePriv: priv,
     noncePub: pub,
     claimToken,
-    timestamp: TalerPreciseTimestamp.now(),
+    timestamp: timestampPreciseToDb(TalerPreciseTimestamp.now()),
     merchantBaseUrl,
     orderId,
     proposalId: proposalId,
@@ -717,7 +718,7 @@ async function storeFirstPaySuccess(
       if (purchase.purchaseStatus === PurchaseStatus.PendingPaying) {
         purchase.purchaseStatus = PurchaseStatus.Done;
       }
-      purchase.timestampFirstSuccessfulPay = now;
+      purchase.timestampFirstSuccessfulPay = timestampPreciseToDb(now);
       purchase.lastSessionId = sessionId;
       purchase.merchantPaySig = payResponse.sig;
       purchase.posConfirmation = payResponse.pos_confirmation;
@@ -941,7 +942,9 @@ async function unblockBackup(
         .forEachAsync(async (bp) => {
           bp.state = {
             tag: BackupProviderStateTag.Ready,
-            nextBackupTimestamp: TalerPreciseTimestamp.now(),
+            nextBackupTimestamp: timestampPreciseToDb(
+              TalerPreciseTimestamp.now(),
+            ),
           };
           tx.backupProviders.put(bp);
         });
@@ -1447,7 +1450,7 @@ export async function confirmPay(
             totalPayCost: Amounts.stringify(payCostInfo),
           };
           p.lastSessionId = sessionId;
-          p.timestampAccept = TalerPreciseTimestamp.now();
+          p.timestampAccept = 
timestampPreciseToDb(TalerPreciseTimestamp.now());
           p.purchaseStatus = PurchaseStatus.PendingPaying;
           await tx.purchases.put(p);
           await spendCoins(ws, tx, {
@@ -2791,7 +2794,7 @@ async function storeRefunds(
               proposalId: purchase.proposalId,
               refundGroupId: newRefundGroupId,
               status: RefundGroupStatus.Pending,
-              timestampCreated: now,
+              timestampCreated: timestampPreciseToDb(now),
               amountEffective: Amounts.stringify(
                 Amounts.zeroOfCurrency(currency),
               ),
@@ -2802,7 +2805,7 @@ async function storeRefunds(
           const newItem: RefundItemRecord = {
             coinPub: rf.coin_pub,
             executionTime: rf.execution_time,
-            obtainedTime: now,
+            obtainedTime: timestampPreciseToDb(now),
             refundAmount: rf.refund_amount,
             refundGroupId: newGroup.refundGroupId,
             rtxid: rf.rtransaction_id,
diff --git a/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts 
b/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts
index 0355eb152..6ec8822ab 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts
@@ -60,6 +60,9 @@ import {
   PeerPullPaymentCreditStatus,
   WithdrawalGroupStatus,
   WithdrawalRecordType,
+  timestampOptionalPreciseFromDb,
+  timestampPreciseFromDb,
+  timestampPreciseToDb,
   updateExchangeFromUrl,
 } from "../index.js";
 import { InternalWalletState } from "../internal-wallet-state.js";
@@ -395,12 +398,14 @@ async function handlePeerPullCreditCreatePurse(
     nonce: pullIni.contractEncNonce,
   });
 
+  const mergeTimestamp = timestampPreciseFromDb(pullIni.mergeTimestamp);
+
   const purseExpiration = contractTerms.purse_expiration;
   const sigRes = await ws.cryptoApi.signReservePurseCreate({
     contractTermsHash: pullIni.contractTermsHash,
     flags: WalletAccountMergeFlags.CreateWithPurseFee,
     mergePriv: pullIni.mergePriv,
-    mergeTimestamp: TalerPreciseTimestamp.round(pullIni.mergeTimestamp),
+    mergeTimestamp: TalerPreciseTimestamp.round(mergeTimestamp),
     purseAmount: pullIni.amount,
     purseExpiration: purseExpiration,
     purseFee: purseFee,
@@ -412,7 +417,7 @@ async function handlePeerPullCreditCreatePurse(
 
   const reservePurseReqBody: ExchangeReservePurseRequest = {
     merge_sig: sigRes.mergeSig,
-    merge_timestamp: TalerPreciseTimestamp.round(pullIni.mergeTimestamp),
+    merge_timestamp: TalerPreciseTimestamp.round(mergeTimestamp),
     h_contract_terms: pullIni.contractTermsHash,
     merge_pub: pullIni.mergePub,
     min_age: 0,
@@ -695,11 +700,17 @@ async function getPreferredExchangeForCurrency(
         if (candidate.lastWithdrawal && !e.lastWithdrawal) {
           continue;
         }
-        if (candidate.lastWithdrawal && e.lastWithdrawal) {
+        const exchangeLastWithdrawal = timestampOptionalPreciseFromDb(
+          e.lastWithdrawal,
+        );
+        const candidateLastWithdrawal = timestampOptionalPreciseFromDb(
+          candidate.lastWithdrawal,
+        );
+        if (exchangeLastWithdrawal && candidateLastWithdrawal) {
           if (
             AbsoluteTime.cmp(
-              AbsoluteTime.fromPreciseTimestamp(e.lastWithdrawal),
-              AbsoluteTime.fromPreciseTimestamp(candidate.lastWithdrawal),
+              AbsoluteTime.fromPreciseTimestamp(exchangeLastWithdrawal),
+              AbsoluteTime.fromPreciseTimestamp(candidateLastWithdrawal),
             ) > 0
           ) {
             candidate = e;
@@ -741,8 +752,6 @@ export async function initiatePeerPullPayment(
     exchangeBaseUrl: exchangeBaseUrl,
   });
 
-  const mergeTimestamp = TalerPreciseTimestamp.now();
-
   const pursePair = await ws.cryptoApi.createEddsaKeypair({});
   const mergePair = await ws.cryptoApi.createEddsaKeypair({});
 
@@ -766,6 +775,8 @@ export async function initiatePeerPullPayment(
     undefined,
   );
 
+  const mergeTimestamp = TalerPreciseTimestamp.now();
+
   const transitionInfo = await ws.db
     .mktx((x) => [x.peerPullCredit, x.contractTerms])
     .runReadWrite(async (tx) => {
@@ -778,7 +789,7 @@ export async function initiatePeerPullPayment(
         mergePriv: mergePair.priv,
         mergePub: mergePair.pub,
         status: PeerPullPaymentCreditStatus.PendingCreatePurse,
-        mergeTimestamp,
+        mergeTimestamp: timestampPreciseToDb(mergeTimestamp),
         contractEncNonce,
         mergeReserveRowId: mergeReserveRowId,
         contractPriv: contractKeyPair.priv,
diff --git a/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts 
b/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts
index 5bcfa3418..48cbf574f 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts
@@ -59,6 +59,7 @@ import {
   PendingTaskType,
   RefreshOperationStatus,
   createRefreshGroup,
+  timestampPreciseToDb,
 } from "../index.js";
 import { assertUnreachable } from "../util/assertUnreachable.js";
 import { checkLogicInvariant } from "../util/invariants.js";
@@ -595,7 +596,7 @@ export async function preparePeerPullDebit(
           contractPriv: contractPriv,
           exchangeBaseUrl: exchangeBaseUrl,
           pursePub: pursePub,
-          timestampCreated: TalerPreciseTimestamp.now(),
+          timestampCreated: timestampPreciseToDb(TalerPreciseTimestamp.now()),
           contractTermsHash,
           amount: contractTerms.amount,
           status: PeerPullDebitRecordStatus.DialogProposed,
diff --git a/packages/taler-wallet-core/src/operations/pay-peer-push-credit.ts 
b/packages/taler-wallet-core/src/operations/pay-peer-push-credit.ts
index 89d9e3b49..e4698c203 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer-push-credit.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer-push-credit.ts
@@ -59,6 +59,7 @@ import {
   PendingTaskType,
   WithdrawalGroupStatus,
   WithdrawalRecordType,
+  timestampPreciseToDb,
 } from "../index.js";
 import { assertUnreachable } from "../util/assertUnreachable.js";
 import { checkDbInvariant } from "../util/invariants.js";
@@ -129,12 +130,10 @@ export async function preparePeerPushCredit(
       amountEffective: existing.existingPushInc.estimatedAmountEffective,
       amountRaw: existing.existingContractTerms.amount,
       contractTerms: existing.existingContractTerms,
-      peerPushCreditId:
-        existing.existingPushInc.peerPushCreditId,
+      peerPushCreditId: existing.existingPushInc.peerPushCreditId,
       transactionId: constructTransactionIdentifier({
         tag: TransactionType.PeerPushCredit,
-        peerPushCreditId:
-          existing.existingPushInc.peerPushCreditId,
+        peerPushCreditId: existing.existingPushInc.peerPushCreditId,
       }),
     };
   }
@@ -196,7 +195,7 @@ export async function preparePeerPushCredit(
         exchangeBaseUrl: exchangeBaseUrl,
         mergePriv: dec.mergePriv,
         pursePub: pursePub,
-        timestamp: TalerPreciseTimestamp.now(),
+        timestamp: timestampPreciseToDb(TalerPreciseTimestamp.now()),
         contractTermsHash,
         status: PeerPushCreditStatus.DialogProposed,
         withdrawalGroupId,
@@ -263,16 +262,11 @@ async function longpollKycStatus(
       const transitionInfo = await ws.db
         .mktx((x) => [x.peerPushCredit])
         .runReadWrite(async (tx) => {
-          const peerInc = await tx.peerPushCredit.get(
-            peerPushCreditId,
-          );
+          const peerInc = await tx.peerPushCredit.get(peerPushCreditId);
           if (!peerInc) {
             return;
           }
-          if (
-            peerInc.status !==
-            PeerPushCreditStatus.PendingMergeKycRequired
-          ) {
+          if (peerInc.status !== PeerPushCreditStatus.PendingMergeKycRequired) 
{
             return;
           }
           const oldTxState = computePeerPushCreditTransactionState(peerInc);
@@ -333,9 +327,7 @@ async function processPeerPushCreditKycRequired(
     const { transitionInfo, result } = await ws.db
       .mktx((x) => [x.peerPushCredit])
       .runReadWrite(async (tx) => {
-        const peerInc = await tx.peerPushCredit.get(
-          peerPushCreditId,
-        );
+        const peerInc = await tx.peerPushCredit.get(peerPushCreditId);
         if (!peerInc) {
           return {
             transitionInfo: undefined,
@@ -466,9 +458,7 @@ async function handlePendingMerge(
       x.exchangeDetails,
     ])
     .runReadWrite(async (tx) => {
-      const peerInc = await tx.peerPushCredit.get(
-        peerPushCreditId,
-      );
+      const peerInc = await tx.peerPushCredit.get(peerPushCreditId);
       if (!peerInc) {
         return undefined;
       }
@@ -520,9 +510,7 @@ async function handlePendingWithdrawing(
   const transitionInfo = await ws.db
     .mktx((x) => [x.peerPushCredit, x.withdrawalGroups])
     .runReadWrite(async (tx) => {
-      const ppi = await tx.peerPushCredit.get(
-        peerInc.peerPushCreditId,
-      );
+      const ppi = await tx.peerPushCredit.get(peerInc.peerPushCreditId);
       if (!ppi) {
         finished = true;
         return;
@@ -631,9 +619,7 @@ export async function confirmPeerPushCredit(
     }
     peerPushCreditId = parsedTx.peerPushCreditId;
   } else {
-    throw Error(
-      "no transaction ID (or deprecated peerPushCreditId) provided",
-    );
+    throw Error("no transaction ID (or deprecated peerPushCreditId) provided");
   }
 
   await ws.db
@@ -683,9 +669,7 @@ export async function suspendPeerPushCreditTransaction(
   const transitionInfo = await ws.db
     .mktx((x) => [x.peerPushCredit])
     .runReadWrite(async (tx) => {
-      const pushCreditRec = await tx.peerPushCredit.get(
-        peerPushCreditId,
-      );
+      const pushCreditRec = await tx.peerPushCredit.get(peerPushCreditId);
       if (!pushCreditRec) {
         logger.warn(`peer push credit ${peerPushCreditId} not found`);
         return;
@@ -746,9 +730,7 @@ export async function abortPeerPushCreditTransaction(
   const transitionInfo = await ws.db
     .mktx((x) => [x.peerPushCredit])
     .runReadWrite(async (tx) => {
-      const pushCreditRec = await tx.peerPushCredit.get(
-        peerPushCreditId,
-      );
+      const pushCreditRec = await tx.peerPushCredit.get(peerPushCreditId);
       if (!pushCreditRec) {
         logger.warn(`peer push credit ${peerPushCreditId} not found`);
         return;
@@ -820,9 +802,7 @@ export async function resumePeerPushCreditTransaction(
   const transitionInfo = await ws.db
     .mktx((x) => [x.peerPushCredit])
     .runReadWrite(async (tx) => {
-      const pushCreditRec = await tx.peerPushCredit.get(
-        peerPushCreditId,
-      );
+      const pushCreditRec = await tx.peerPushCredit.get(peerPushCreditId);
       if (!pushCreditRec) {
         logger.warn(`peer push credit ${peerPushCreditId} not found`);
         return;
diff --git a/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts 
b/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts
index e80ffc059..b3d0eb132 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts
@@ -55,6 +55,7 @@ import {
   PeerPushDebitStatus,
   RefreshOperationStatus,
   createRefreshGroup,
+  timestampPreciseToDb,
 } from "../index.js";
 import { InternalWalletState } from "../internal-wallet-state.js";
 import { PendingTaskType } from "../pending-types.js";
@@ -669,7 +670,7 @@ export async function initiatePeerPushDebit(
         purseExpiration: purseExpiration,
         pursePriv: pursePair.priv,
         pursePub: pursePair.pub,
-        timestampCreated: TalerPreciseTimestamp.now(),
+        timestampCreated: timestampPreciseToDb(TalerPreciseTimestamp.now()),
         status: PeerPushDebitStatus.PendingCreatePurse,
         contractEncNonce,
         coinSel: {
diff --git a/packages/taler-wallet-core/src/operations/pending.ts 
b/packages/taler-wallet-core/src/operations/pending.ts
index 6115f848b..120d316ce 100644
--- a/packages/taler-wallet-core/src/operations/pending.ts
+++ b/packages/taler-wallet-core/src/operations/pending.ts
@@ -47,6 +47,7 @@ import {
   ExchangeEntryDbUpdateStatus,
   RefreshOperationStatus,
   DepositElementStatus,
+  timestampPreciseFromDb,
 } from "../db.js";
 import {
   PendingOperationsResponse,
@@ -445,7 +446,7 @@ async function gatherBackupPending(
     const retryRecord = await tx.operationRetries.get(opId);
     if (bp.state.tag === BackupProviderStateTag.Ready) {
       const timestampDue = AbsoluteTime.fromPreciseTimestamp(
-        bp.state.nextBackupTimestamp,
+        timestampPreciseFromDb(bp.state.nextBackupTimestamp),
       );
       resp.pendingOperations.push({
         type: PendingTaskType.Backup,
diff --git a/packages/taler-wallet-core/src/operations/recoup.ts 
b/packages/taler-wallet-core/src/operations/recoup.ts
index 6a18e5de6..782e98d1c 100644
--- a/packages/taler-wallet-core/src/operations/recoup.ts
+++ b/packages/taler-wallet-core/src/operations/recoup.ts
@@ -47,6 +47,7 @@ import {
   WithdrawCoinSource,
   WithdrawalGroupStatus,
   WithdrawalRecordType,
+  timestampPreciseToDb,
 } from "../db.js";
 import { InternalWalletState } from "../internal-wallet-state.js";
 import { checkDbInvariant } from "../util/invariants.js";
@@ -391,7 +392,7 @@ export async function processRecoupGroup(
       if (!rg2) {
         return;
       }
-      rg2.timestampFinished = TalerPreciseTimestamp.now();
+      rg2.timestampFinished = 
timestampPreciseToDb(TalerPreciseTimestamp.now());
       if (rg2.scheduleRefreshCoins.length > 0) {
         const refreshGroupId = await createRefreshGroup(
           ws,
@@ -424,7 +425,7 @@ export async function createRecoupGroup(
     exchangeBaseUrl: exchangeBaseUrl,
     coinPubs: coinPubs,
     timestampFinished: undefined,
-    timestampStarted: TalerPreciseTimestamp.now(),
+    timestampStarted: timestampPreciseToDb(TalerPreciseTimestamp.now()),
     recoupFinishedPerCoin: coinPubs.map(() => false),
     scheduleRefreshCoins: [],
   };
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts 
b/packages/taler-wallet-core/src/operations/refresh.ts
index 75adbc860..dc1d53627 100644
--- a/packages/taler-wallet-core/src/operations/refresh.ts
+++ b/packages/taler-wallet-core/src/operations/refresh.ts
@@ -80,6 +80,7 @@ import {
   isWithdrawableDenom,
   PendingTaskType,
   RefreshSessionRecord,
+  timestampPreciseToDb,
 } from "../index.js";
 import {
   EXCHANGE_COINS_LOCK,
@@ -157,10 +158,10 @@ function updateGroupStatus(rg: RefreshGroupRecord): { 
final: boolean } {
   );
   if (allFinal) {
     if (anyFailed) {
-      rg.timestampFinished = TalerPreciseTimestamp.now();
+      rg.timestampFinished = timestampPreciseToDb(TalerPreciseTimestamp.now());
       rg.operationStatus = RefreshOperationStatus.Failed;
     } else {
-      rg.timestampFinished = TalerPreciseTimestamp.now();
+      rg.timestampFinished = timestampPreciseToDb(TalerPreciseTimestamp.now());
       rg.operationStatus = RefreshOperationStatus.Finished;
     }
     return { final: true };
@@ -1099,12 +1100,14 @@ export async function createRefreshGroup(
     expectedOutputPerCoin: estimatedOutputPerCoin.map((x) =>
       Amounts.stringify(x),
     ),
-    timestampCreated: TalerPreciseTimestamp.now(),
+    timestampCreated: timestampPreciseToDb(TalerPreciseTimestamp.now()),
   };
 
   if (oldCoinPubs.length == 0) {
     logger.warn("created refresh group with zero coins");
-    refreshGroup.timestampFinished = TalerPreciseTimestamp.now();
+    refreshGroup.timestampFinished = timestampPreciseToDb(
+      TalerPreciseTimestamp.now(),
+    );
     refreshGroup.operationStatus = RefreshOperationStatus.Finished;
   }
 
diff --git a/packages/taler-wallet-core/src/operations/reward.ts 
b/packages/taler-wallet-core/src/operations/reward.ts
index 6ae021174..3681dc4f5 100644
--- a/packages/taler-wallet-core/src/operations/reward.ts
+++ b/packages/taler-wallet-core/src/operations/reward.ts
@@ -50,6 +50,8 @@ import {
   DenominationRecord,
   RewardRecord,
   RewardRecordStatus,
+  timestampPreciseFromDb,
+  timestampPreciseToDb,
 } from "../db.js";
 import { makeErrorDetail } from "@gnu-taler/taler-util";
 import { InternalWalletState } from "../internal-wallet-state.js";
@@ -203,7 +205,7 @@ export async function prepareTip(
       exchangeBaseUrl: tipPickupStatus.exchange_url,
       next_url: tipPickupStatus.next_url,
       merchantBaseUrl: res.merchantBaseUrl,
-      createdTimestamp: TalerPreciseTimestamp.now(),
+      createdTimestamp: timestampPreciseToDb(TalerPreciseTimestamp.now()),
       merchantRewardId: res.merchantRewardId,
       rewardAmountEffective: Amounts.stringify(selectedDenoms.totalCoinValue),
       denomsSel: selectedDenoms,
@@ -411,7 +413,7 @@ export async function processTip(
         return;
       }
       const oldTxState = computeRewardTransactionStatus(tr);
-      tr.pickedUpTimestamp = TalerPreciseTimestamp.now();
+      tr.pickedUpTimestamp = timestampPreciseToDb(TalerPreciseTimestamp.now());
       tr.status = RewardRecordStatus.Done;
       await tx.rewards.put(tr);
       const newTxState = computeRewardTransactionStatus(tr);
@@ -448,7 +450,9 @@ export async function acceptTip(
         return { tipRecord };
       }
       const oldTxState = computeRewardTransactionStatus(tipRecord);
-      tipRecord.acceptedTimestamp = TalerPreciseTimestamp.now();
+      tipRecord.acceptedTimestamp = timestampPreciseToDb(
+        TalerPreciseTimestamp.now(),
+      );
       tipRecord.status = RewardRecordStatus.PendingPickup;
       await tx.rewards.put(tipRecord);
       const newTxState = computeRewardTransactionStatus(tipRecord);
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts 
b/packages/taler-wallet-core/src/operations/transactions.ts
index d7b277faf..41bdae249 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -65,7 +65,12 @@ import {
   WithdrawalGroupStatus,
   WithdrawalRecordType,
 } from "../db.js";
-import { GetReadOnlyAccess, WalletStoresV1 } from "../index.js";
+import {
+  GetReadOnlyAccess,
+  timestampOptionalPreciseFromDb,
+  timestampPreciseFromDb,
+  WalletStoresV1,
+} from "../index.js";
 import { InternalWalletState } from "../internal-wallet-state.js";
 import { PendingTaskType } from "../pending-types.js";
 import { assertUnreachable } from "../util/assertUnreachable.js";
@@ -470,7 +475,7 @@ function buildTransactionForPushPaymentDebit(
       expiration: contractTerms.purse_expiration,
       summary: contractTerms.summary,
     },
-    timestamp: pi.timestampCreated,
+    timestamp: timestampPreciseFromDb(pi.timestampCreated),
     talerUri: stringifyPayPushUri({
       exchangeBaseUrl: pi.exchangeBaseUrl,
       contractPriv: pi.contractPriv,
@@ -501,7 +506,7 @@ function buildTransactionForPullPaymentDebit(
       expiration: contractTerms.purse_expiration,
       summary: contractTerms.summary,
     },
-    timestamp: pi.timestampCreated,
+    timestamp: timestampPreciseFromDb(pi.timestampCreated),
     transactionId: constructTransactionIdentifier({
       tag: TransactionType.PeerPullDebit,
       peerPullDebitId: pi.peerPullDebitId,
@@ -543,8 +548,7 @@ function buildTransactionForPeerPullCredit(
       amountEffective: Amounts.stringify(wsr.denomsSel.totalCoinValue),
       amountRaw: Amounts.stringify(wsr.instructedAmount),
       exchangeBaseUrl: wsr.exchangeBaseUrl,
-      // Old transactions don't have it!
-      timestamp: pullCredit.mergeTimestamp ?? TalerPreciseTimestamp.now(),
+      timestamp: timestampPreciseFromDb(pullCredit.mergeTimestamp),
       info: {
         expiration: peerContractTerms.purse_expiration,
         summary: peerContractTerms.summary,
@@ -575,8 +579,7 @@ function buildTransactionForPeerPullCredit(
     amountEffective: Amounts.stringify(pullCredit.estimatedAmountEffective),
     amountRaw: Amounts.stringify(peerContractTerms.amount),
     exchangeBaseUrl: pullCredit.exchangeBaseUrl,
-    // Old transactions don't have it!
-    timestamp: pullCredit.mergeTimestamp ?? TalerProtocolTimestamp.now(),
+    timestamp: timestampPreciseFromDb(pullCredit.mergeTimestamp),
     info: {
       expiration: peerContractTerms.purse_expiration,
       summary: peerContractTerms.summary,
@@ -617,7 +620,7 @@ function buildTransactionForPeerPushCredit(
         expiration: peerContractTerms.purse_expiration,
         summary: peerContractTerms.summary,
       },
-      timestamp: wsr.timestampStart,
+      timestamp: timestampPreciseFromDb(wsr.timestampStart),
       transactionId: constructTransactionIdentifier({
         tag: TransactionType.PeerPushCredit,
         peerPushCreditId: pushInc.peerPushCreditId,
@@ -640,7 +643,7 @@ function buildTransactionForPeerPushCredit(
       summary: peerContractTerms.summary,
     },
     kycUrl: pushInc.kycUrl,
-    timestamp: pushInc.timestamp,
+    timestamp: timestampPreciseFromDb(pushInc.timestamp),
     transactionId: constructTransactionIdentifier({
       tag: TransactionType.PeerPushCredit,
       peerPushCreditId: pushInc.peerPushCreditId,
@@ -673,7 +676,7 @@ function buildTransactionForBankIntegratedWithdraw(
     },
     kycUrl: wgRecord.kycUrl,
     exchangeBaseUrl: wgRecord.exchangeBaseUrl,
-    timestamp: wgRecord.timestampStart,
+    timestamp: timestampPreciseFromDb(wgRecord.timestampStart),
     transactionId: constructTransactionIdentifier({
       tag: TransactionType.Withdrawal,
       withdrawalGroupId: wgRecord.withdrawalGroupId,
@@ -717,7 +720,7 @@ function buildTransactionForManualWithdraw(
     },
     kycUrl: withdrawalGroup.kycUrl,
     exchangeBaseUrl: withdrawalGroup.exchangeBaseUrl,
-    timestamp: withdrawalGroup.timestampStart,
+    timestamp: timestampPreciseFromDb(withdrawalGroup.timestampStart),
     transactionId: constructTransactionIdentifier({
       tag: TransactionType.Withdrawal,
       withdrawalGroupId: withdrawalGroup.withdrawalGroupId,
@@ -748,7 +751,7 @@ function buildTransactionForRefund(
       tag: TransactionType.Payment,
       proposalId: refundRecord.proposalId,
     }),
-    timestamp: refundRecord.timestampCreated,
+    timestamp: timestampPreciseFromDb(refundRecord.timestampCreated),
     transactionId: constructTransactionIdentifier({
       tag: TransactionType.Refund,
       refundGroupId: refundRecord.refundGroupId,
@@ -786,7 +789,7 @@ function buildTransactionForRefresh(
     refreshOutputAmount: Amounts.stringify(outputAmount),
     originatingTransactionId:
       refreshGroupRecord.reasonDetails?.originatingTransactionId,
-    timestamp: refreshGroupRecord.timestampCreated,
+    timestamp: timestampPreciseFromDb(refreshGroupRecord.timestampCreated),
     transactionId: constructTransactionIdentifier({
       tag: TransactionType.Refresh,
       refreshGroupId: refreshGroupRecord.refreshGroupId,
@@ -812,7 +815,7 @@ function buildTransactionForDeposit(
     txActions: computeDepositTransactionActions(dg),
     amountRaw: Amounts.stringify(dg.counterpartyEffectiveDepositAmount),
     amountEffective: Amounts.stringify(dg.totalPayCost),
-    timestamp: dg.timestampCreated,
+    timestamp: timestampPreciseFromDb(dg.timestampCreated),
     targetPaytoUri: dg.wire.payto_uri,
     wireTransferDeadline: dg.wireTransferDeadline,
     transactionId: constructTransactionIdentifier({
@@ -845,7 +848,7 @@ function buildTransactionForTip(
     txActions: computeTipTransactionActions(tipRecord),
     amountEffective: Amounts.stringify(tipRecord.rewardAmountEffective),
     amountRaw: Amounts.stringify(tipRecord.rewardAmountRaw),
-    timestamp: tipRecord.acceptedTimestamp,
+    timestamp: timestampPreciseFromDb(tipRecord.acceptedTimestamp),
     transactionId: constructTransactionIdentifier({
       tag: TransactionType.Reward,
       walletRewardId: tipRecord.walletRewardId,
@@ -922,7 +925,7 @@ async function buildTransactionForPurchase(
         : Amounts.stringify(purchaseRecord.refundAmountAwaiting),
     refunds,
     posConfirmation: purchaseRecord.posConfirmation,
-    timestamp,
+    timestamp: timestampPreciseFromDb(timestamp),
     transactionId: constructTransactionIdentifier({
       tag: TransactionType.Payment,
       proposalId: purchaseRecord.proposalId,
diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts 
b/packages/taler-wallet-core/src/operations/withdraw.ts
index 32e63f4f6..fb503d75f 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.ts
@@ -131,6 +131,7 @@ import {
   ExchangeEntryDbUpdateStatus,
   PendingTaskType,
   isWithdrawableDenom,
+  timestampPreciseToDb,
 } from "../index.js";
 import {
   TransitionInfo,
@@ -1325,7 +1326,7 @@ async function processWithdrawalGroupAbortingBank(
       }
       const txStatusOld = computeWithdrawalTransactionStatus(wg);
       wg.status = WithdrawalGroupStatus.AbortedBank;
-      wg.timestampFinish = TalerPreciseTimestamp.now();
+      wg.timestampFinish = timestampPreciseToDb(TalerPreciseTimestamp.now());
       const txStatusNew = computeWithdrawalTransactionStatus(wg);
       await tx.withdrawalGroups.put(wg);
       return {
@@ -1458,7 +1459,7 @@ async function processWithdrawalGroupPendingReady(
         }
         const txStatusOld = computeWithdrawalTransactionStatus(wg);
         wg.status = WithdrawalGroupStatus.Done;
-        wg.timestampFinish = TalerPreciseTimestamp.now();
+        wg.timestampFinish = timestampPreciseToDb(TalerPreciseTimestamp.now());
         const txStatusNew = computeWithdrawalTransactionStatus(wg);
         await tx.withdrawalGroups.put(wg);
         return {
@@ -1554,7 +1555,7 @@ async function processWithdrawalGroupPendingReady(
       const oldTxState = computeWithdrawalTransactionStatus(wg);
       logger.info(`now withdrawn ${numFinished} of ${numTotalCoins} coins`);
       if (wg.timestampFinish === undefined && numFinished === numTotalCoins) {
-        wg.timestampFinish = TalerPreciseTimestamp.now();
+        wg.timestampFinish = timestampPreciseToDb(TalerPreciseTimestamp.now());
         wg.status = WithdrawalGroupStatus.Done;
         await makeCoinsVisible(ws, tx, transactionId);
       }
@@ -2047,8 +2048,9 @@ async function registerReserveWithBank(
       if (r.wgInfo.withdrawalType !== WithdrawalRecordType.BankIntegrated) {
         throw Error("invariant failed");
       }
-      r.wgInfo.bankInfo.timestampReserveInfoPosted =
-        AbsoluteTime.toPreciseTimestamp(AbsoluteTime.now());
+      r.wgInfo.bankInfo.timestampReserveInfoPosted = timestampPreciseToDb(
+        AbsoluteTime.toPreciseTimestamp(AbsoluteTime.now()),
+      );
       const oldTxState = computeWithdrawalTransactionStatus(r);
       r.status = WithdrawalGroupStatus.PendingWaitConfirmBank;
       const newTxState = computeWithdrawalTransactionStatus(r);
@@ -2130,7 +2132,7 @@ async function processReserveBankStatus(
         }
         const now = AbsoluteTime.toPreciseTimestamp(AbsoluteTime.now());
         const oldTxState = computeWithdrawalTransactionStatus(r);
-        r.wgInfo.bankInfo.timestampBankConfirmed = now;
+        r.wgInfo.bankInfo.timestampBankConfirmed = timestampPreciseToDb(now);
         r.status = WithdrawalGroupStatus.FailedBankAborted;
         const newTxState = computeWithdrawalTransactionStatus(r);
         await tx.withdrawalGroups.put(r);
@@ -2179,7 +2181,7 @@ async function processReserveBankStatus(
       if (status.transfer_done) {
         logger.info("withdrawal: transfer confirmed by bank.");
         const now = AbsoluteTime.toPreciseTimestamp(AbsoluteTime.now());
-        r.wgInfo.bankInfo.timestampBankConfirmed = now;
+        r.wgInfo.bankInfo.timestampBankConfirmed = timestampPreciseToDb(now);
         r.status = WithdrawalGroupStatus.PendingQueryingStatus;
       } else {
         logger.info("withdrawal: transfer not yet confirmed by bank");
@@ -2285,7 +2287,7 @@ export async function 
internalPrepareCreateWithdrawalGroup(
     denomsSel: initialDenomSel,
     exchangeBaseUrl: canonExchange,
     instructedAmount: Amounts.stringify(amount),
-    timestampStart: now,
+    timestampStart: timestampPreciseToDb(now),
     rawWithdrawalAmount: initialDenomSel.totalWithdrawCost,
     effectiveWithdrawalAmount: initialDenomSel.totalCoinValue,
     secretSeed,
@@ -2339,8 +2341,7 @@ export async function 
internalPerformCreateWithdrawalGroup(
   if (!prep.creationInfo) {
     return { withdrawalGroup, transitionInfo: undefined };
   }
-  const { amount, canonExchange, exchangeDetails } =
-    prep.creationInfo;
+  const { amount, canonExchange, exchangeDetails } = prep.creationInfo;
 
   await tx.withdrawalGroups.add(withdrawalGroup);
   await tx.reserves.put({
@@ -2350,7 +2351,7 @@ export async function 
internalPerformCreateWithdrawalGroup(
 
   const exchange = await tx.exchanges.get(withdrawalGroup.exchangeBaseUrl);
   if (exchange) {
-    exchange.lastWithdrawal = TalerPreciseTimestamp.now();
+    exchange.lastWithdrawal = 
timestampPreciseToDb(TalerPreciseTimestamp.now());
     exchange.entryStatus = ExchangeEntryDbRecordStatus.Used;
     await tx.exchanges.put(exchange);
   }
@@ -2541,11 +2542,7 @@ export async function createManualWithdrawal(
   });
 
   const exchangePaytoUris = await ws.db
-    .mktx((x) => [
-      x.withdrawalGroups,
-      x.exchanges,
-      x.exchangeDetails,
-    ])
+    .mktx((x) => [x.withdrawalGroups, x.exchanges, x.exchangeDetails])
     .runReadOnly(async (tx) => {
       return await getFundingPaytoUris(tx, withdrawalGroup.withdrawalGroupId);
     });

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]