summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core/src/operations
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-core/src/operations')
-rw-r--r--packages/taler-wallet-core/src/operations/backup/export.ts11
-rw-r--r--packages/taler-wallet-core/src/operations/backup/import.ts10
-rw-r--r--packages/taler-wallet-core/src/operations/backup/index.ts40
-rw-r--r--packages/taler-wallet-core/src/operations/deposits.ts59
-rw-r--r--packages/taler-wallet-core/src/operations/exchanges.ts66
-rw-r--r--packages/taler-wallet-core/src/operations/pay.ts33
-rw-r--r--packages/taler-wallet-core/src/operations/pending.ts42
-rw-r--r--packages/taler-wallet-core/src/operations/recoup.ts6
-rw-r--r--packages/taler-wallet-core/src/operations/refresh.ts74
-rw-r--r--packages/taler-wallet-core/src/operations/refund.ts41
-rw-r--r--packages/taler-wallet-core/src/operations/reserves.ts19
-rw-r--r--packages/taler-wallet-core/src/operations/testing.ts4
-rw-r--r--packages/taler-wallet-core/src/operations/tip.ts11
-rw-r--r--packages/taler-wallet-core/src/operations/transactions.ts29
-rw-r--r--packages/taler-wallet-core/src/operations/withdraw.test.ts60
-rw-r--r--packages/taler-wallet-core/src/operations/withdraw.ts37
16 files changed, 277 insertions, 265 deletions
diff --git a/packages/taler-wallet-core/src/operations/backup/export.ts b/packages/taler-wallet-core/src/operations/backup/export.ts
index 12b309418..35306da63 100644
--- a/packages/taler-wallet-core/src/operations/backup/export.ts
+++ b/packages/taler-wallet-core/src/operations/backup/export.ts
@@ -49,14 +49,13 @@ import {
BackupWithdrawalGroup,
canonicalizeBaseUrl,
canonicalJson,
- getTimestampNow,
Logger,
- timestampToIsoString,
WalletBackupContentV1,
hash,
encodeCrock,
getRandomBytes,
stringToBytes,
+ AbsoluteTime,
} from "@gnu-taler/taler-util";
import { InternalWalletState } from "../../common.js";
import {
@@ -455,7 +454,7 @@ export async function exportBackup(
});
});
- const ts = getTimestampNow();
+ const ts = AbsoluteTime.toTimestamp(AbsoluteTime.now());
if (!bs.lastBackupTimestamp) {
bs.lastBackupTimestamp = ts;
@@ -496,9 +495,9 @@ export async function exportBackup(
);
bs.lastBackupNonce = encodeCrock(getRandomBytes(32));
logger.trace(
- `setting timestamp to ${timestampToIsoString(ts)} and nonce to ${
- bs.lastBackupNonce
- }`,
+ `setting timestamp to ${AbsoluteTime.toIsoString(
+ AbsoluteTime.fromTimestamp(ts),
+ )} and nonce to ${bs.lastBackupNonce}`,
);
await tx.config.put({
key: WALLET_BACKUP_STATE_KEY,
diff --git a/packages/taler-wallet-core/src/operations/backup/import.ts b/packages/taler-wallet-core/src/operations/backup/import.ts
index 35b62c2e4..4b17a5f33 100644
--- a/packages/taler-wallet-core/src/operations/backup/import.ts
+++ b/packages/taler-wallet-core/src/operations/backup/import.ts
@@ -20,7 +20,6 @@ import {
Amounts,
BackupDenomSel,
WalletBackupContentV1,
- getTimestampNow,
BackupCoinSourceType,
BackupProposalStatus,
codecForContractTerms,
@@ -28,6 +27,8 @@ import {
RefreshReason,
BackupRefreshReason,
DenomKeyType,
+ AbsoluteTime,
+ TalerProtocolTimestamp,
} from "@gnu-taler/taler-util";
import {
WalletContractData,
@@ -277,8 +278,8 @@ export async function importBackup(
permanent: true,
retryInfo: initRetryInfo(),
lastUpdate: undefined,
- nextUpdate: getTimestampNow(),
- nextRefreshCheck: getTimestampNow(),
+ nextUpdate: TalerProtocolTimestamp.now(),
+ nextRefreshCheck: TalerProtocolTimestamp.now(),
});
}
@@ -465,7 +466,6 @@ export async function importBackup(
senderWire: backupReserve.sender_wire,
retryInfo: initRetryInfo(),
lastError: undefined,
- lastSuccessfulStatusQuery: { t_ms: "never" },
initialWithdrawalGroupId:
backupReserve.initial_withdrawal_group_id,
initialWithdrawalStarted:
@@ -752,7 +752,7 @@ export async function importBackup(
noncePub:
cryptoComp.proposalNoncePrivToPub[backupPurchase.nonce_priv],
lastPayError: undefined,
- autoRefundDeadline: { t_ms: "never" },
+ autoRefundDeadline: TalerProtocolTimestamp.never(),
refundStatusRetryInfo: initRetryInfo(),
lastRefundStatusError: undefined,
timestampAccept: backupPurchase.timestamp_accept,
diff --git a/packages/taler-wallet-core/src/operations/backup/index.ts b/packages/taler-wallet-core/src/operations/backup/index.ts
index 2a1a774f1..48eea56ad 100644
--- a/packages/taler-wallet-core/src/operations/backup/index.ts
+++ b/packages/taler-wallet-core/src/operations/backup/index.ts
@@ -40,21 +40,19 @@ import {
ConfirmPayResultType,
DenomKeyType,
durationFromSpec,
- getTimestampNow,
hashDenomPub,
HttpStatusCode,
j2s,
- LibtoolVersion,
Logger,
notEmpty,
PreparePayResultType,
RecoveryLoadRequest,
RecoveryMergeStrategy,
TalerErrorDetails,
- Timestamp,
- timestampAddDuration,
+ AbsoluteTime,
URL,
WalletBackupContentV1,
+ TalerProtocolTimestamp,
} from "@gnu-taler/taler-util";
import { gunzipSync, gzipSync } from "fflate";
import { InternalWalletState } from "../../common.js";
@@ -250,11 +248,13 @@ interface BackupForProviderArgs {
retryAfterPayment: boolean;
}
-function getNextBackupTimestamp(): Timestamp {
+function getNextBackupTimestamp(): TalerProtocolTimestamp {
// FIXME: Randomize!
- return timestampAddDuration(
- getTimestampNow(),
- durationFromSpec({ minutes: 5 }),
+ return AbsoluteTime.toTimestamp(
+ AbsoluteTime.addDuration(
+ AbsoluteTime.now(),
+ durationFromSpec({ minutes: 5 }),
+ ),
);
}
@@ -324,7 +324,7 @@ async function runBackupCycleForProvider(
if (!prov) {
return;
}
- prov.lastBackupCycleTimestamp = getTimestampNow();
+ prov.lastBackupCycleTimestamp = TalerProtocolTimestamp.now();
prov.state = {
tag: BackupProviderStateTag.Ready,
nextBackupTimestamp: getNextBackupTimestamp(),
@@ -404,7 +404,7 @@ async function runBackupCycleForProvider(
return;
}
prov.lastBackupHash = encodeCrock(currentBackupHash);
- prov.lastBackupCycleTimestamp = getTimestampNow();
+ prov.lastBackupCycleTimestamp = TalerProtocolTimestamp.now();
prov.state = {
tag: BackupProviderStateTag.Ready,
nextBackupTimestamp: getNextBackupTimestamp(),
@@ -641,7 +641,7 @@ export async function addBackupProvider(
if (req.activate) {
oldProv.state = {
tag: BackupProviderStateTag.Ready,
- nextBackupTimestamp: getTimestampNow(),
+ nextBackupTimestamp: TalerProtocolTimestamp.now(),
};
logger.info("setting existing backup provider to active");
await tx.backupProviders.put(oldProv);
@@ -662,7 +662,7 @@ export async function addBackupProvider(
if (req.activate) {
state = {
tag: BackupProviderStateTag.Ready,
- nextBackupTimestamp: getTimestampNow(),
+ nextBackupTimestamp: TalerProtocolTimestamp.now(),
};
} else {
state = {
@@ -701,8 +701,8 @@ export interface ProviderInfo {
* Last communication issue with the provider.
*/
lastError?: TalerErrorDetails;
- lastSuccessfulBackupTimestamp?: Timestamp;
- lastAttemptedBackupTimestamp?: Timestamp;
+ lastSuccessfulBackupTimestamp?: TalerProtocolTimestamp;
+ lastAttemptedBackupTimestamp?: TalerProtocolTimestamp;
paymentProposalIds: string[];
backupProblem?: BackupProblem;
paymentStatus: ProviderPaymentStatus;
@@ -724,7 +724,7 @@ export interface BackupConflictingDeviceProblem {
type: "backup-conflicting-device";
otherDeviceId: string;
myDeviceId: string;
- backupTimestamp: Timestamp;
+ backupTimestamp: AbsoluteTime;
}
export type ProviderPaymentStatus =
@@ -774,12 +774,12 @@ export interface ProviderPaymentPending {
export interface ProviderPaymentPaid {
type: ProviderPaymentType.Paid;
- paidUntil: Timestamp;
+ paidUntil: AbsoluteTime;
}
export interface ProviderPaymentTermsChanged {
type: ProviderPaymentType.TermsChanged;
- paidUntil: Timestamp;
+ paidUntil: AbsoluteTime;
oldTerms: BackupProviderTerms;
newTerms: BackupProviderTerms;
}
@@ -811,8 +811,8 @@ async function getProviderPaymentInfo(
if (status.paid) {
return {
type: ProviderPaymentType.Paid,
- paidUntil: timestampAddDuration(
- status.contractTerms.timestamp,
+ paidUntil: AbsoluteTime.addDuration(
+ AbsoluteTime.fromTimestamp(status.contractTerms.timestamp),
durationFromSpec({ years: 1 }),
),
};
@@ -915,7 +915,7 @@ async function backupRecoveryTheirs(
paymentProposalIds: [],
state: {
tag: BackupProviderStateTag.Ready,
- nextBackupTimestamp: getTimestampNow(),
+ nextBackupTimestamp: TalerProtocolTimestamp.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 a5d6c93cf..4b976011b 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -15,6 +15,7 @@
*/
import {
+ AbsoluteTime,
AmountJson,
Amounts,
buildCodecForObject,
@@ -27,21 +28,16 @@ import {
ContractTerms,
CreateDepositGroupRequest,
CreateDepositGroupResponse,
- DenomKeyType,
durationFromSpec,
encodeCrock,
GetFeeForDepositRequest,
getRandomBytes,
- getTimestampNow,
hashWire,
Logger,
NotificationType,
parsePaytoUri,
TalerErrorDetails,
- Timestamp,
- timestampAddDuration,
- timestampIsBetween,
- timestampTruncateToSecond,
+ TalerProtocolTimestamp,
TrackDepositGroupRequest,
TrackDepositGroupResponse,
URL,
@@ -212,7 +208,7 @@ async function processDepositGroupImpl(
}
}
if (allDeposited) {
- dg.timestampFinished = getTimestampNow();
+ dg.timestampFinished = TalerProtocolTimestamp.now();
dg.operationStatus = OperationStatus.Finished;
delete dg.lastError;
delete dg.retryInfo;
@@ -310,13 +306,8 @@ export async function getFeeForDeposit(
}
});
- const timestamp = getTimestampNow();
- const timestampRound = timestampTruncateToSecond(timestamp);
- // const noncePair = await ws.cryptoApi.createEddsaKeypair();
- // const merchantPair = await ws.cryptoApi.createEddsaKeypair();
- // const wireSalt = encodeCrock(getRandomBytes(16));
- // const wireHash = hashWire(req.depositPaytoUri, wireSalt);
- // const wireHashLegacy = hashWireLegacy(req.depositPaytoUri, wireSalt);
+ const timestamp = AbsoluteTime.now();
+ const timestampRound = AbsoluteTime.toTimestamp(timestamp);
const contractTerms: ContractTerms = {
auditors: [],
exchanges: exchangeInfos,
@@ -331,15 +322,14 @@ export async function getFeeForDeposit(
wire_transfer_deadline: timestampRound,
order_id: "",
h_wire: "",
- pay_deadline: timestampAddDuration(
- timestampRound,
- durationFromSpec({ hours: 1 }),
+ pay_deadline: AbsoluteTime.toTimestamp(
+ AbsoluteTime.addDuration(timestamp, durationFromSpec({ hours: 1 })),
),
merchant: {
name: "",
},
merchant_pub: "",
- refund_deadline: { t_ms: 0 },
+ refund_deadline: TalerProtocolTimestamp.zero(),
};
const contractData = extractContractData(contractTerms, "", "");
@@ -399,8 +389,8 @@ export async function createDepositGroup(
}
});
- const timestamp = getTimestampNow();
- const timestampRound = timestampTruncateToSecond(timestamp);
+ const now = AbsoluteTime.now();
+ const nowRounded = AbsoluteTime.toTimestamp(now);
const noncePair = await ws.cryptoApi.createEddsaKeypair();
const merchantPair = await ws.cryptoApi.createEddsaKeypair();
const wireSalt = encodeCrock(getRandomBytes(16));
@@ -412,24 +402,23 @@ export async function createDepositGroup(
max_fee: Amounts.stringify(amount),
max_wire_fee: Amounts.stringify(amount),
wire_method: p.targetType,
- timestamp: timestampRound,
+ timestamp: nowRounded,
merchant_base_url: "",
summary: "",
nonce: noncePair.pub,
- wire_transfer_deadline: timestampRound,
+ wire_transfer_deadline: nowRounded,
order_id: "",
// This is always the v2 wire hash, as we're the "merchant" and support v2.
h_wire: wireHash,
// Required for older exchanges.
- pay_deadline: timestampAddDuration(
- timestampRound,
- durationFromSpec({ hours: 1 }),
+ pay_deadline: AbsoluteTime.toTimestamp(
+ AbsoluteTime.addDuration(now, durationFromSpec({ hours: 1 })),
),
merchant: {
name: "",
},
merchant_pub: merchantPair.pub,
- refund_deadline: { t_ms: 0 },
+ refund_deadline: TalerProtocolTimestamp.zero(),
};
const contractTermsHash = await ws.cryptoApi.hashString(
@@ -482,7 +471,7 @@ export async function createDepositGroup(
depositGroupId,
noncePriv: noncePair.priv,
noncePub: noncePair.pub,
- timestampCreated: timestamp,
+ timestampCreated: AbsoluteTime.toTimestamp(now),
timestampFinished: undefined,
payCoinSelection: payCoinSel,
payCoinSelectionUid: encodeCrock(getRandomBytes(32)),
@@ -570,10 +559,10 @@ export async function getEffectiveDepositAmount(
// about "find method not found on undefined" when the wireType
// is not supported by the Exchange.
const fee = exchangeDetails.wireInfo.feesForType[wireType].find((x) => {
- return timestampIsBetween(
- getTimestampNow(),
- x.startStamp,
- x.endStamp,
+ return AbsoluteTime.isBetween(
+ AbsoluteTime.now(),
+ AbsoluteTime.fromTimestamp(x.startStamp),
+ AbsoluteTime.fromTimestamp(x.endStamp),
);
})?.wireFee;
if (fee) {
@@ -656,10 +645,10 @@ export async function getTotalFeeForDepositAmount(
// about "find method not found on undefined" when the wireType
// is not supported by the Exchange.
const fee = exchangeDetails.wireInfo.feesForType[wireType].find((x) => {
- return timestampIsBetween(
- getTimestampNow(),
- x.startStamp,
- x.endStamp,
+ return AbsoluteTime.isBetween(
+ AbsoluteTime.now(),
+ AbsoluteTime.fromTimestamp(x.startStamp),
+ AbsoluteTime.fromTimestamp(x.endStamp),
);
})?.wireFee;
if (fee) {
diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts
index 536d4e3bf..df7eee76d 100644
--- a/packages/taler-wallet-core/src/operations/exchanges.ts
+++ b/packages/taler-wallet-core/src/operations/exchanges.ts
@@ -28,8 +28,6 @@ import {
durationFromSpec,
ExchangeSignKeyJson,
ExchangeWireJson,
- getTimestampNow,
- isTimestampExpired,
Logger,
NotificationType,
parsePaytoUri,
@@ -37,13 +35,15 @@ import {
TalerErrorCode,
URL,
TalerErrorDetails,
- Timestamp,
+ AbsoluteTime,
hashDenomPub,
LibtoolVersion,
codecForAny,
DenominationPubKey,
DenomKeyType,
ExchangeKeysJson,
+ TalerProtocolTimestamp,
+ TalerProtocolDuration,
} from "@gnu-taler/taler-util";
import { decodeCrock, encodeCrock, hash } from "@gnu-taler/taler-util";
import { CryptoApi } from "../crypto/workers/cryptoApi.js";
@@ -57,7 +57,7 @@ import {
WireInfo,
} from "../db.js";
import {
- getExpiryTimestamp,
+ getExpiry,
HttpRequestLibrary,
readSuccessResponseJsonOrThrow,
readSuccessResponseTextOrThrow,
@@ -80,7 +80,7 @@ const logger = new Logger("exchanges.ts");
function denominationRecordFromKeys(
exchangeBaseUrl: string,
exchangeMasterPub: string,
- listIssueDate: Timestamp,
+ listIssueDate: TalerProtocolTimestamp,
denomIn: ExchangeDenomination,
): DenominationRecord {
let denomPub: DenominationPubKey;
@@ -132,7 +132,9 @@ async function handleExchangeUpdateError(
}
export function getExchangeRequestTimeout(): Duration {
- return { d_ms: 5000 };
+ return Duration.fromSpec({
+ seconds: 5,
+ });
}
export interface ExchangeTosDownloadResult {
@@ -362,12 +364,11 @@ export async function updateExchangeFromUrl(
async function provideExchangeRecord(
ws: InternalWalletState,
baseUrl: string,
- now: Timestamp,
+ now: AbsoluteTime,
): Promise<{
exchange: ExchangeRecord;
exchangeDetails: ExchangeDetailsRecord | undefined;
}> {
-
return await ws.db
.mktx((x) => ({
exchanges: x.exchanges,
@@ -376,14 +377,14 @@ async function provideExchangeRecord(
.runReadWrite(async (tx) => {
let exchange = await tx.exchanges.get(baseUrl);
if (!exchange) {
- const r = {
+ const r: ExchangeRecord = {
permanent: true,
baseUrl: baseUrl,
retryInfo: initRetryInfo(),
detailsPointer: undefined,
lastUpdate: undefined,
- nextUpdate: now,
- nextRefreshCheck: now,
+ nextUpdate: AbsoluteTime.toTimestamp(now),
+ nextRefreshCheck: AbsoluteTime.toTimestamp(now),
};
await tx.exchanges.put(r);
exchange = r;
@@ -400,10 +401,10 @@ interface ExchangeKeysDownloadResult {
currentDenominations: DenominationRecord[];
protocolVersion: string;
signingKeys: ExchangeSignKeyJson[];
- reserveClosingDelay: Duration;
- expiry: Timestamp;
+ reserveClosingDelay: TalerProtocolDuration;
+ expiry: TalerProtocolTimestamp;
recoup: Recoup[];
- listIssueDate: Timestamp;
+ listIssueDate: TalerProtocolTimestamp;
}
/**
@@ -475,9 +476,11 @@ async function downloadExchangeKeysInfo(
protocolVersion: exchangeKeysJsonUnchecked.version,
signingKeys: exchangeKeysJsonUnchecked.signkeys,
reserveClosingDelay: exchangeKeysJsonUnchecked.reserve_closing_delay,
- expiry: getExpiryTimestamp(resp, {
- minDuration: durationFromSpec({ hours: 1 }),
- }),
+ expiry: AbsoluteTime.toTimestamp(
+ getExpiry(resp, {
+ minDuration: durationFromSpec({ hours: 1 }),
+ }),
+ ),
recoup: exchangeKeysJsonUnchecked.recoup ?? [],
listIssueDate: exchangeKeysJsonUnchecked.list_issue_date,
};
@@ -529,12 +532,20 @@ async function updateExchangeFromUrlImpl(
exchangeDetails: ExchangeDetailsRecord;
}> {
logger.info(`updating exchange info for ${baseUrl}, forced: ${forceNow}`);
- const now = getTimestampNow();
+ const now = AbsoluteTime.now();
baseUrl = canonicalizeBaseUrl(baseUrl);
- const { exchange, exchangeDetails } = await provideExchangeRecord(ws, baseUrl, now);
+ const { exchange, exchangeDetails } = await provideExchangeRecord(
+ ws,
+ baseUrl,
+ now,
+ );
- if (!forceNow && exchangeDetails !== undefined && !isTimestampExpired(exchange.nextUpdate)) {
+ if (
+ !forceNow &&
+ exchangeDetails !== undefined &&
+ !AbsoluteTime.isExpired(AbsoluteTime.fromTimestamp(exchange.nextUpdate))
+ ) {
logger.info("using existing exchange info");
return { exchange, exchangeDetails };
}
@@ -575,7 +586,8 @@ async function updateExchangeFromUrlImpl(
timeout,
acceptedFormat,
);
- const tosHasBeenAccepted = exchangeDetails?.termsOfServiceAcceptedEtag === tosDownload.tosEtag
+ const tosHasBeenAccepted =
+ exchangeDetails?.termsOfServiceAcceptedEtag === tosDownload.tosEtag;
let recoupGroupId: string | undefined;
@@ -611,23 +623,25 @@ async function updateExchangeFromUrlImpl(
exchangeBaseUrl: r.baseUrl,
wireInfo,
termsOfServiceText: tosDownload.tosText,
- termsOfServiceAcceptedEtag: tosHasBeenAccepted ? tosDownload.tosEtag : undefined,
+ termsOfServiceAcceptedEtag: tosHasBeenAccepted
+ ? tosDownload.tosEtag
+ : undefined,
termsOfServiceContentType: tosDownload.tosContentType,
termsOfServiceLastEtag: tosDownload.tosEtag,
- termsOfServiceAcceptedTimestamp: getTimestampNow(),
+ termsOfServiceAcceptedTimestamp: TalerProtocolTimestamp.now(),
};
// FIXME: only update if pointer got updated
r.lastError = undefined;
r.retryInfo = initRetryInfo();
- r.lastUpdate = getTimestampNow();
+ r.lastUpdate = TalerProtocolTimestamp.now();
r.nextUpdate = keysInfo.expiry;
// New denominations might be available.
- r.nextRefreshCheck = getTimestampNow();
+ r.nextRefreshCheck = TalerProtocolTimestamp.now();
r.detailsPointer = {
currency: details.currency,
masterPublicKey: details.masterPublicKey,
// FIXME: only change if pointer really changed
- updateClock: getTimestampNow(),
+ updateClock: TalerProtocolTimestamp.now(),
protocolVersionRange: keysInfo.protocolVersion,
};
await tx.exchanges.put(r);
diff --git a/packages/taler-wallet-core/src/operations/pay.ts b/packages/taler-wallet-core/src/operations/pay.ts
index 9844dc52e..9521d544f 100644
--- a/packages/taler-wallet-core/src/operations/pay.ts
+++ b/packages/taler-wallet-core/src/operations/pay.ts
@@ -27,7 +27,6 @@
import {
AmountJson,
Amounts,
- CheckPaymentResponse,
codecForContractTerms,
codecForMerchantPayResponse,
codecForProposal,
@@ -41,11 +40,8 @@ import {
durationMin,
durationMul,
encodeCrock,
- getDurationRemaining,
getRandomBytes,
- getTimestampNow,
HttpStatusCode,
- isTimestampExpired,
j2s,
kdf,
Logger,
@@ -57,9 +53,9 @@ import {
stringToBytes,
TalerErrorCode,
TalerErrorDetails,
- Timestamp,
- timestampAddDuration,
+ AbsoluteTime,
URL,
+ TalerProtocolTimestamp,
} from "@gnu-taler/taler-util";
import { EXCHANGE_COINS_LOCK, InternalWalletState } from "../common.js";
import {
@@ -172,7 +168,9 @@ function isSpendableCoin(coin: CoinRecord, denom: DenominationRecord): boolean {
if (coin.status !== CoinStatus.Fresh) {
return false;
}
- if (isTimestampExpired(denom.stampExpireDeposit)) {
+ if (
+ AbsoluteTime.isExpired(AbsoluteTime.fromTimestamp(denom.stampExpireDeposit))
+ ) {
return false;
}
return true;
@@ -187,7 +185,7 @@ export interface CoinSelectionRequest {
/**
* Timestamp of the contract.
*/
- timestamp: Timestamp;
+ timestamp: TalerProtocolTimestamp;
wireMethod: string;
@@ -422,7 +420,7 @@ async function recordConfirmPay(
payCoinSelectionUid: encodeCrock(getRandomBytes(32)),
totalPayCost: payCostInfo,
coinDepositPermissions,
- timestampAccept: getTimestampNow(),
+ timestampAccept: AbsoluteTime.toTimestamp(AbsoluteTime.now()),
timestampLastRefundStatus: undefined,
proposalId: proposal.proposalId,
lastPayError: undefined,
@@ -784,7 +782,7 @@ async function processDownloadProposalImpl(
} catch (e) {
const err = makeErrorDetails(
TalerErrorCode.WALLET_CONTRACT_TERMS_MALFORMED,
- "schema validation failed",
+ `schema validation failed: ${e}`,
{},
);
await failProposalPermanently(ws, proposalId, err);
@@ -921,7 +919,7 @@ async function startDownloadProposal(
noncePriv: priv,
noncePub: pub,
claimToken,
- timestamp: getTimestampNow(),
+ timestamp: AbsoluteTime.toTimestamp(AbsoluteTime.now()),
merchantBaseUrl,
orderId,
proposalId: proposalId,
@@ -956,7 +954,7 @@ async function storeFirstPaySuccess(
sessionId: string | undefined,
paySig: string,
): Promise<void> {
- const now = getTimestampNow();
+ const now = AbsoluteTime.toTimestamp(AbsoluteTime.now());
await ws.db
.mktx((x) => ({ purchases: x.purchases }))
.runReadWrite(async (tx) => {
@@ -978,13 +976,16 @@ async function storeFirstPaySuccess(
purchase.payRetryInfo = initRetryInfo();
purchase.merchantPaySig = paySig;
if (isFirst) {
- const ar = purchase.download.contractData.autoRefund;
- if (ar) {
+ const protoAr = purchase.download.contractData.autoRefund;
+ if (protoAr) {
+ const ar = Duration.fromTalerProtocolDuration(protoAr);
logger.info("auto_refund present");
purchase.refundQueryRequested = true;
purchase.refundStatusRetryInfo = initRetryInfo();
purchase.lastRefundStatusError = undefined;
- purchase.autoRefundDeadline = timestampAddDuration(now, ar);
+ purchase.autoRefundDeadline = AbsoluteTime.toTimestamp(
+ AbsoluteTime.addDuration(AbsoluteTime.now(), ar),
+ );
}
}
await tx.purchases.put(purchase);
@@ -1150,7 +1151,7 @@ async function unblockBackup(
if (bp.state.tag === BackupProviderStateTag.Retrying) {
bp.state = {
tag: BackupProviderStateTag.Ready,
- nextBackupTimestamp: getTimestampNow(),
+ nextBackupTimestamp: TalerProtocolTimestamp.now(),
};
}
});
diff --git a/packages/taler-wallet-core/src/operations/pending.ts b/packages/taler-wallet-core/src/operations/pending.ts
index 6d686fb3a..fc76eeb19 100644
--- a/packages/taler-wallet-core/src/operations/pending.ts
+++ b/packages/taler-wallet-core/src/operations/pending.ts
@@ -35,7 +35,7 @@ import {
PendingTaskType,
ReserveType,
} from "../pending-types.js";
-import { getTimestampNow, Timestamp } from "@gnu-taler/taler-util";
+import { AbsoluteTime } from "@gnu-taler/taler-util";
import { InternalWalletState } from "../common.js";
import { GetReadOnlyAccess } from "../util/query.js";
@@ -44,21 +44,25 @@ async function gatherExchangePending(
exchanges: typeof WalletStoresV1.exchanges;
exchangeDetails: typeof WalletStoresV1.exchangeDetails;
}>,
- now: Timestamp,
+ now: AbsoluteTime,
resp: PendingOperationsResponse,
): Promise<void> {
await tx.exchanges.iter().forEachAsync(async (e) => {
resp.pendingOperations.push({
type: PendingTaskType.ExchangeUpdate,
givesLifeness: false,
- timestampDue: e.lastError ? e.retryInfo.nextRetry : e.nextUpdate,
+ timestampDue: e.lastError
+ ? e.retryInfo.nextRetry
+ : AbsoluteTime.fromTimestamp(e.nextUpdate),
exchangeBaseUrl: e.baseUrl,
lastError: e.lastError,
});
resp.pendingOperations.push({
type: PendingTaskType.ExchangeCheckRefresh,
- timestampDue: e.lastError ? e.retryInfo.nextRetry : e.nextRefreshCheck,
+ timestampDue: e.lastError
+ ? e.retryInfo.nextRetry
+ : AbsoluteTime.fromTimestamp(e.nextRefreshCheck),
givesLifeness: false,
exchangeBaseUrl: e.baseUrl,
});
@@ -67,7 +71,7 @@ async function gatherExchangePending(
async function gatherReservePending(
tx: GetReadOnlyAccess<{ reserves: typeof WalletStoresV1.reserves }>,
- now: Timestamp,
+ now: AbsoluteTime,
resp: PendingOperationsResponse,
): Promise<void> {
const reserves = await tx.reserves.indexes.byStatus.getAll(
@@ -87,7 +91,7 @@ async function gatherReservePending(
resp.pendingOperations.push({
type: PendingTaskType.Reserve,
givesLifeness: true,
- timestampDue: reserve.retryInfo?.nextRetry ?? Timestamp.now(),
+ timestampDue: reserve.retryInfo?.nextRetry ?? AbsoluteTime.now(),
stage: reserve.reserveStatus,
timestampCreated: reserve.timestampCreated,
reserveType,
@@ -105,7 +109,7 @@ async function gatherReservePending(
async function gatherRefreshPending(
tx: GetReadOnlyAccess<{ refreshGroups: typeof WalletStoresV1.refreshGroups }>,
- now: Timestamp,
+ now: AbsoluteTime,
resp: PendingOperationsResponse,
): Promise<void> {
const refreshGroups = await tx.refreshGroups.indexes.byStatus.getAll(
@@ -136,7 +140,7 @@ async function gatherWithdrawalPending(
withdrawalGroups: typeof WalletStoresV1.withdrawalGroups;
planchets: typeof WalletStoresV1.planchets;
}>,
- now: Timestamp,
+ now: AbsoluteTime,
resp: PendingOperationsResponse,
): Promise<void> {
const wsrs = await tx.withdrawalGroups.indexes.byStatus.getAll(
@@ -169,14 +173,14 @@ async function gatherWithdrawalPending(
async function gatherProposalPending(
tx: GetReadOnlyAccess<{ proposals: typeof WalletStoresV1.proposals }>,
- now: Timestamp,
+ now: AbsoluteTime,
resp: PendingOperationsResponse,
): Promise<void> {
await tx.proposals.iter().forEach((proposal) => {
if (proposal.proposalStatus == ProposalStatus.Proposed) {
// Nothing to do, user needs to choose.
} else if (proposal.proposalStatus == ProposalStatus.Downloading) {
- const timestampDue = proposal.retryInfo?.nextRetry ?? getTimestampNow();
+ const timestampDue = proposal.retryInfo?.nextRetry ?? AbsoluteTime.now();
resp.pendingOperations.push({
type: PendingTaskType.ProposalDownload,
givesLifeness: true,
@@ -194,7 +198,7 @@ async function gatherProposalPending(
async function gatherDepositPending(
tx: GetReadOnlyAccess<{ depositGroups: typeof WalletStoresV1.depositGroups }>,
- now: Timestamp,
+ now: AbsoluteTime,
resp: PendingOperationsResponse,
): Promise<void> {
const dgs = await tx.depositGroups.indexes.byStatus.getAll(
@@ -204,7 +208,7 @@ async function gatherDepositPending(
if (dg.timestampFinished) {
return;
}
- const timestampDue = dg.retryInfo?.nextRetry ?? getTimestampNow();
+ const timestampDue = dg.retryInfo?.nextRetry ?? AbsoluteTime.now();
resp.pendingOperations.push({
type: PendingTaskType.Deposit,
givesLifeness: true,
@@ -218,7 +222,7 @@ async function gatherDepositPending(
async function gatherTipPending(
tx: GetReadOnlyAccess<{ tips: typeof WalletStoresV1.tips }>,
- now: Timestamp,
+ now: AbsoluteTime,
resp: PendingOperationsResponse,
): Promise<void> {
await tx.tips.iter().forEach((tip) => {
@@ -240,7 +244,7 @@ async function gatherTipPending(
async function gatherPurchasePending(
tx: GetReadOnlyAccess<{ purchases: typeof WalletStoresV1.purchases }>,
- now: Timestamp,
+ now: AbsoluteTime,
resp: PendingOperationsResponse,
): Promise<void> {
await tx.purchases.iter().forEach((pr) => {
@@ -249,7 +253,7 @@ async function gatherPurchasePending(
pr.abortStatus === AbortStatus.None &&
!pr.payFrozen
) {
- const timestampDue = pr.payRetryInfo?.nextRetry ?? getTimestampNow();
+ const timestampDue = pr.payRetryInfo?.nextRetry ?? AbsoluteTime.now();
resp.pendingOperations.push({
type: PendingTaskType.Pay,
givesLifeness: true,
@@ -275,7 +279,7 @@ async function gatherPurchasePending(
async function gatherRecoupPending(
tx: GetReadOnlyAccess<{ recoupGroups: typeof WalletStoresV1.recoupGroups }>,
- now: Timestamp,
+ now: AbsoluteTime,
resp: PendingOperationsResponse,
): Promise<void> {
await tx.recoupGroups.iter().forEach((rg) => {
@@ -297,7 +301,7 @@ async function gatherBackupPending(
tx: GetReadOnlyAccess<{
backupProviders: typeof WalletStoresV1.backupProviders;
}>,
- now: Timestamp,
+ now: AbsoluteTime,
resp: PendingOperationsResponse,
): Promise<void> {
await tx.backupProviders.iter().forEach((bp) => {
@@ -305,7 +309,7 @@ async function gatherBackupPending(
resp.pendingOperations.push({
type: PendingTaskType.Backup,
givesLifeness: false,
- timestampDue: bp.state.nextBackupTimestamp,
+ timestampDue: AbsoluteTime.fromTimestamp(bp.state.nextBackupTimestamp),
backupProviderBaseUrl: bp.baseUrl,
lastError: undefined,
});
@@ -325,7 +329,7 @@ async function gatherBackupPending(
export async function getPendingOperations(
ws: InternalWalletState,
): Promise<PendingOperationsResponse> {
- const now = getTimestampNow();
+ const now = AbsoluteTime.now();
return await ws.db
.mktx((x) => ({
backupProviders: x.backupProviders,
diff --git a/packages/taler-wallet-core/src/operations/recoup.ts b/packages/taler-wallet-core/src/operations/recoup.ts
index 23d14f212..84a27966d 100644
--- a/packages/taler-wallet-core/src/operations/recoup.ts
+++ b/packages/taler-wallet-core/src/operations/recoup.ts
@@ -27,11 +27,11 @@
import {
Amounts,
codecForRecoupConfirmation,
- getTimestampNow,
j2s,
NotificationType,
RefreshReason,
TalerErrorDetails,
+ TalerProtocolTimestamp,
} from "@gnu-taler/taler-util";
import { encodeCrock, getRandomBytes } from "@gnu-taler/taler-util";
import {
@@ -110,7 +110,7 @@ async function putGroupAsFinished(
}
if (allFinished) {
logger.info("all recoups of recoup group are finished");
- recoupGroup.timestampFinished = getTimestampNow();
+ recoupGroup.timestampFinished = TalerProtocolTimestamp.now();
recoupGroup.retryInfo = initRetryInfo();
recoupGroup.lastError = undefined;
if (recoupGroup.scheduleRefreshCoins.length > 0) {
@@ -467,7 +467,7 @@ export async function createRecoupGroup(
coinPubs: coinPubs,
lastError: undefined,
timestampFinished: undefined,
- timestampStarted: getTimestampNow(),
+ timestampStarted: TalerProtocolTimestamp.now(),
retryInfo: initRetryInfo(),
recoupFinishedPerCoin: coinPubs.map(() => false),
// Will be populated later
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts b/packages/taler-wallet-core/src/operations/refresh.ts
index 8b6d8b2e4..11f0f6c51 100644
--- a/packages/taler-wallet-core/src/operations/refresh.ts
+++ b/packages/taler-wallet-core/src/operations/refresh.ts
@@ -23,7 +23,7 @@ import {
ExchangeRefreshRevealRequest,
getRandomBytes,
HttpStatusCode,
- j2s,
+ TalerProtocolTimestamp,
} from "@gnu-taler/taler-util";
import {
CoinRecord,
@@ -42,11 +42,8 @@ import {
fnutil,
NotificationType,
RefreshGroupId,
- RefreshPlanchetInfo,
RefreshReason,
- stringifyTimestamp,
TalerErrorDetails,
- timestampToIsoString,
} from "@gnu-taler/taler-util";
import { AmountJson, Amounts } from "@gnu-taler/taler-util";
import { amountToPretty } from "@gnu-taler/taler-util";
@@ -61,12 +58,7 @@ import {
Duration,
durationFromSpec,
durationMul,
- getTimestampNow,
- isTimestampExpired,
- Timestamp,
- timestampAddDuration,
- timestampDifference,
- timestampMin,
+ AbsoluteTime,
URL,
} from "@gnu-taler/taler-util";
import { guardOperationException } from "../errors.js";
@@ -139,7 +131,7 @@ function updateGroupStatus(rg: RefreshGroupRecord): void {
rg.frozen = true;
rg.retryInfo = initRetryInfo();
} else {
- rg.timestampFinished = getTimestampNow();
+ rg.timestampFinished = AbsoluteTime.toTimestamp(AbsoluteTime.now());
rg.operationStatus = OperationStatus.Finished;
rg.retryInfo = initRetryInfo();
}
@@ -234,19 +226,6 @@ async function refreshCreateSession(
availableDenoms,
);
- if (logger.shouldLogTrace()) {
- logger.trace(`printing selected denominations for refresh`);
- logger.trace(`current time: ${stringifyTimestamp(getTimestampNow())}`);
- for (const denom of newCoinDenoms.selectedDenoms) {
- logger.trace(`denom ${denom.denom}, count ${denom.count}`);
- logger.trace(
- `withdrawal expiration ${stringifyTimestamp(
- denom.denom.stampExpireWithdraw,
- )}`,
- );
- }
- }
-
if (newCoinDenoms.selectedDenoms.length === 0) {
logger.trace(
`not refreshing, available amount ${amountToPretty(
@@ -306,7 +285,9 @@ async function refreshCreateSession(
}
function getRefreshRequestTimeout(rg: RefreshGroupRecord): Duration {
- return { d_ms: 5000 };
+ return Duration.fromSpec({
+ seconds: 5,
+ });
}
async function refreshMelt(
@@ -949,12 +930,12 @@ export async function createRefreshGroup(
retryInfo: initRetryInfo(),
inputPerCoin,
estimatedOutputPerCoin,
- timestampCreated: getTimestampNow(),
+ timestampCreated: TalerProtocolTimestamp.now(),
};
if (oldCoinPubs.length == 0) {
logger.warn("created refresh group with zero coins");
- refreshGroup.timestampFinished = getTimestampNow();
+ refreshGroup.timestampFinished = TalerProtocolTimestamp.now();
refreshGroup.operationStatus = OperationStatus.Finished;
}
@@ -974,25 +955,23 @@ export async function createRefreshGroup(
/**
* Timestamp after which the wallet would do the next check for an auto-refresh.
*/
-function getAutoRefreshCheckThreshold(d: DenominationRecord): Timestamp {
- const delta = timestampDifference(
- d.stampExpireWithdraw,
- d.stampExpireDeposit,
- );
+function getAutoRefreshCheckThreshold(d: DenominationRecord): AbsoluteTime {
+ const expireWithdraw = AbsoluteTime.fromTimestamp(d.stampExpireWithdraw);
+ const expireDeposit = AbsoluteTime.fromTimestamp(d.stampExpireDeposit);
+ const delta = AbsoluteTime.difference(expireWithdraw, expireDeposit);
const deltaDiv = durationMul(delta, 0.75);
- return timestampAddDuration(d.stampExpireWithdraw, deltaDiv);
+ return AbsoluteTime.addDuration(expireWithdraw, deltaDiv);
}
/**
* Timestamp after which the wallet would do an auto-refresh.
*/
-function getAutoRefreshExecuteThreshold(d: DenominationRecord): Timestamp {
- const delta = timestampDifference(
- d.stampExpireWithdraw,
- d.stampExpireDeposit,
- );
+function getAutoRefreshExecuteThreshold(d: DenominationRecord): AbsoluteTime {
+ const expireWithdraw = AbsoluteTime.fromTimestamp(d.stampExpireWithdraw);
+ const expireDeposit = AbsoluteTime.fromTimestamp(d.stampExpireDeposit);
+ const delta = AbsoluteTime.difference(expireWithdraw, expireDeposit);
const deltaDiv = durationMul(delta, 0.5);
- return timestampAddDuration(d.stampExpireWithdraw, deltaDiv);
+ return AbsoluteTime.addDuration(expireWithdraw, deltaDiv);
}
export async function autoRefresh(
@@ -1001,8 +980,8 @@ export async function autoRefresh(
): Promise<void> {
logger.info(`doing auto-refresh check for '${exchangeBaseUrl}'`);
await updateExchangeFromUrl(ws, exchangeBaseUrl, undefined, true);
- let minCheckThreshold = timestampAddDuration(
- getTimestampNow(),
+ let minCheckThreshold = AbsoluteTime.addDuration(
+ AbsoluteTime.now(),
durationFromSpec({ days: 1 }),
);
await ws.db
@@ -1037,11 +1016,14 @@ export async function autoRefresh(
continue;
}
const executeThreshold = getAutoRefreshExecuteThreshold(denom);
- if (isTimestampExpired(executeThreshold)) {
+ if (AbsoluteTime.isExpired(executeThreshold)) {
refreshCoins.push(coin);
} else {
const checkThreshold = getAutoRefreshCheckThreshold(denom);
- minCheckThreshold = timestampMin(minCheckThreshold, checkThreshold);
+ minCheckThreshold = AbsoluteTime.min(
+ minCheckThreshold,
+ checkThreshold,
+ );
}
}
if (refreshCoins.length > 0) {
@@ -1056,12 +1038,12 @@ export async function autoRefresh(
);
}
logger.info(
- `current wallet time: ${timestampToIsoString(getTimestampNow())}`,
+ `current wallet time: ${AbsoluteTime.toIsoString(AbsoluteTime.now())}`,
);
logger.info(
- `next refresh check at ${timestampToIsoString(minCheckThreshold)}`,
+ `next refresh check at ${AbsoluteTime.toIsoString(minCheckThreshold)}`,
);
- exchange.nextRefreshCheck = minCheckThreshold;
+ exchange.nextRefreshCheck = AbsoluteTime.toTimestamp(minCheckThreshold);
await tx.exchanges.put(exchange);
});
}
diff --git a/packages/taler-wallet-core/src/operations/refund.ts b/packages/taler-wallet-core/src/operations/refund.ts
index 106c79365..686d545df 100644
--- a/packages/taler-wallet-core/src/operations/refund.ts
+++ b/packages/taler-wallet-core/src/operations/refund.ts
@@ -32,7 +32,6 @@ import {
codecForAbortResponse,
codecForMerchantOrderRefundPickupResponse,
CoinPublicKey,
- getTimestampNow,
Logger,
MerchantCoinRefundFailureStatus,
MerchantCoinRefundStatus,
@@ -43,9 +42,10 @@ import {
TalerErrorCode,
TalerErrorDetails,
URL,
- timestampAddDuration,
codecForMerchantOrderStatusPaid,
- isTimestampExpired,
+ AbsoluteTime,
+ TalerProtocolTimestamp,
+ Duration,
} from "@gnu-taler/taler-util";
import {
AbortStatus,
@@ -170,7 +170,7 @@ async function applySuccessfulRefund(
p.refunds[refundKey] = {
type: RefundState.Applied,
- obtainedTime: getTimestampNow(),
+ obtainedTime: AbsoluteTime.toTimestamp(AbsoluteTime.now()),
executionTime: r.execution_time,
refundAmount: Amounts.parseOrThrow(r.refund_amount),
refundFee: denom.feeRefund,
@@ -222,7 +222,7 @@ async function storePendingRefund(
p.refunds[refundKey] = {
type: RefundState.Pending,
- obtainedTime: getTimestampNow(),
+ obtainedTime: AbsoluteTime.toTimestamp(AbsoluteTime.now()),
executionTime: r.execution_time,
refundAmount: Amounts.parseOrThrow(r.refund_amount),
refundFee: denom.feeRefund,
@@ -275,7 +275,7 @@ async function storeFailedRefund(
p.refunds[refundKey] = {
type: RefundState.Failed,
- obtainedTime: getTimestampNow(),
+ obtainedTime: TalerProtocolTimestamp.now(),
executionTime: r.execution_time,
refundAmount: Amounts.parseOrThrow(r.refund_amount),
refundFee: denom.feeRefund,
@@ -327,7 +327,7 @@ async function acceptRefunds(
reason: RefundReason,
): Promise<void> {
logger.trace("handling refunds", refunds);
- const now = getTimestampNow();
+ const now = TalerProtocolTimestamp.now();
await ws.db
.mktx((x) => ({
@@ -401,7 +401,10 @@ async function acceptRefunds(
if (
p.timestampFirstSuccessfulPay &&
p.autoRefundDeadline &&
- p.autoRefundDeadline.t_ms > now.t_ms
+ AbsoluteTime.cmp(
+ AbsoluteTime.fromTimestamp(p.autoRefundDeadline),
+ AbsoluteTime.fromTimestamp(now),
+ ) > 0
) {
queryDone = false;
}
@@ -556,8 +559,10 @@ export async function applyRefund(
).amount,
).amount;
} else {
- amountRefundGone = Amounts.add(amountRefundGone, refund.refundAmount)
- .amount;
+ amountRefundGone = Amounts.add(
+ amountRefundGone,
+ refund.refundAmount,
+ ).amount;
}
});
@@ -623,7 +628,9 @@ async function processPurchaseQueryRefundImpl(
if (
waitForAutoRefund &&
purchase.autoRefundDeadline &&
- !isTimestampExpired(purchase.autoRefundDeadline)
+ !AbsoluteTime.isExpired(
+ AbsoluteTime.fromTimestamp(purchase.autoRefundDeadline),
+ )
) {
const requestUrl = new URL(
`orders/${purchase.download.contractData.orderId}`,
@@ -731,11 +738,13 @@ async function processPurchaseQueryRefundImpl(
purchase.payCoinSelection.coinContributions[i],
),
rtransaction_id: 0,
- execution_time: timestampAddDuration(
- purchase.download.contractData.timestamp,
- {
- d_ms: 1000,
- },
+ execution_time: AbsoluteTime.toTimestamp(
+ AbsoluteTime.addDuration(
+ AbsoluteTime.fromTimestamp(
+ purchase.download.contractData.timestamp,
+ ),
+ Duration.fromSpec({ seconds: 1 }),
+ ),
),
});
}
diff --git a/packages/taler-wallet-core/src/operations/reserves.ts b/packages/taler-wallet-core/src/operations/reserves.ts
index d91ce89f1..ac9483631 100644
--- a/packages/taler-wallet-core/src/operations/reserves.ts
+++ b/packages/taler-wallet-core/src/operations/reserves.ts
@@ -29,15 +29,13 @@ import {
durationMin,
encodeCrock,
getRandomBytes,
- getTimestampNow,
j2s,
Logger,
NotificationType,
randomBytes,
- ReserveTransactionType,
TalerErrorCode,
TalerErrorDetails,
- Timestamp,
+ AbsoluteTime,
URL,
} from "@gnu-taler/taler-util";
import { InternalWalletState } from "../common.js";
@@ -172,7 +170,7 @@ export async function createReserve(
req: CreateReserveRequest,
): Promise<CreateReserveResponse> {
const keypair = await ws.cryptoApi.createEddsaKeypair();
- const now = getTimestampNow();
+ const now = AbsoluteTime.toTimestamp(AbsoluteTime.now());
const canonExchange = canonicalizeBaseUrl(req.exchange);
let reserveStatus;
@@ -217,7 +215,6 @@ export async function createReserve(
timestampReserveInfoPosted: undefined,
bankInfo,
reserveStatus,
- lastSuccessfulStatusQuery: undefined,
retryInfo: initRetryInfo(),
lastError: undefined,
currency: req.amount.currency,
@@ -403,7 +400,9 @@ async function registerReserveWithBank(
default:
return;
}
- r.timestampReserveInfoPosted = getTimestampNow();
+ r.timestampReserveInfoPosted = AbsoluteTime.toTimestamp(
+ AbsoluteTime.now(),
+ );
r.reserveStatus = ReserveRecordStatus.WaitConfirmBank;
r.operationStatus = OperationStatus.Pending;
if (!r.bankInfo) {
@@ -472,7 +471,7 @@ async function processReserveBankStatus(
default:
return;
}
- const now = getTimestampNow();
+ const now = AbsoluteTime.toTimestamp(AbsoluteTime.now());
r.timestampBankConfirmed = now;
r.reserveStatus = ReserveRecordStatus.BankAborted;
r.operationStatus = OperationStatus.Finished;
@@ -509,7 +508,7 @@ async function processReserveBankStatus(
default:
return;
}
- const now = getTimestampNow();
+ const now = AbsoluteTime.toTimestamp(AbsoluteTime.now());
r.timestampBankConfirmed = now;
r.reserveStatus = ReserveRecordStatus.QueryingStatus;
r.operationStatus = OperationStatus.Pending;
@@ -683,7 +682,7 @@ async function updateReserve(
exchangeBaseUrl: reserve.exchangeBaseUrl,
reservePub: reserve.reservePub,
rawWithdrawalAmount: remainingAmount,
- timestampStart: getTimestampNow(),
+ timestampStart: AbsoluteTime.toTimestamp(AbsoluteTime.now()),
retryInfo: initRetryInfo(),
lastError: undefined,
denomsSel: denomSelectionInfoToState(denomSelInfo),
@@ -736,7 +735,7 @@ async function processReserveImpl(
await resetReserveRetry(ws, reservePub);
} else if (
reserve.retryInfo &&
- !Timestamp.isExpired(reserve.retryInfo.nextRetry)
+ !AbsoluteTime.isExpired(reserve.retryInfo.nextRetry)
) {
logger.trace("processReserve retry not due yet");
return;
diff --git a/packages/taler-wallet-core/src/operations/testing.ts b/packages/taler-wallet-core/src/operations/testing.ts
index 93f48fb83..23fee56c1 100644
--- a/packages/taler-wallet-core/src/operations/testing.ts
+++ b/packages/taler-wallet-core/src/operations/testing.ts
@@ -229,8 +229,8 @@ async function createOrder(
amount,
summary,
fulfillment_url: fulfillmentUrl,
- refund_deadline: { t_ms: t * 1000 },
- wire_transfer_deadline: { t_ms: t * 1000 },
+ refund_deadline: { t_s: t },
+ wire_transfer_deadline: { t_s: t },
},
};
const resp = await http.postJson(reqUrl, orderReq, {
diff --git a/packages/taler-wallet-core/src/operations/tip.ts b/packages/taler-wallet-core/src/operations/tip.ts
index a2a4e6f49..765120294 100644
--- a/packages/taler-wallet-core/src/operations/tip.ts
+++ b/packages/taler-wallet-core/src/operations/tip.ts
@@ -22,7 +22,6 @@ import {
parseTipUri,
codecForTipPickupGetResponse,
Amounts,
- getTimestampNow,
TalerErrorDetails,
NotificationType,
TipPlanchetDetail,
@@ -32,6 +31,7 @@ import {
DenomKeyType,
BlindedDenominationSignature,
codecForMerchantTipResponseV2,
+ TalerProtocolTimestamp,
} from "@gnu-taler/taler-util";
import { DerivedTipPlanchet } from "../crypto/cryptoTypes.js";
import {
@@ -39,6 +39,7 @@ import {
CoinRecord,
CoinSourceType,
CoinStatus,
+ TipRecord,
} from "../db.js";
import { j2s } from "@gnu-taler/taler-util";
import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
@@ -115,14 +116,14 @@ export async function prepareTip(
const secretSeed = encodeCrock(getRandomBytes(64));
const denomSelUid = encodeCrock(getRandomBytes(32));
- const newTipRecord = {
+ const newTipRecord: TipRecord = {
walletTipId: walletTipId,
acceptedTimestamp: undefined,
tipAmountRaw: amount,
tipExpiration: tipPickupStatus.expiration,
exchangeBaseUrl: tipPickupStatus.exchange_url,
merchantBaseUrl: res.merchantBaseUrl,
- createdTimestamp: getTimestampNow(),
+ createdTimestamp: TalerProtocolTimestamp.now(),
merchantTipId: res.merchantTipId,
tipAmountEffective: Amounts.sub(
amount,
@@ -397,7 +398,7 @@ async function processTipImpl(
if (tr.pickedUpTimestamp) {
return;
}
- tr.pickedUpTimestamp = getTimestampNow();
+ tr.pickedUpTimestamp = TalerProtocolTimestamp.now();
tr.lastError = undefined;
tr.retryInfo = initRetryInfo();
await tx.tips.put(tr);
@@ -421,7 +422,7 @@ export async function acceptTip(
logger.error("tip not found");
return false;
}
- tipRecord.acceptedTimestamp = getTimestampNow();
+ tipRecord.acceptedTimestamp = TalerProtocolTimestamp.now();
await tx.tips.put(tipRecord);
return true;
});
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts
index 23ab39052..bc466f5a0 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -18,12 +18,12 @@
* Imports.
*/
import {
+ AbsoluteTime,
AmountJson,
Amounts,
Logger,
OrderShortInfo,
PaymentStatus,
- timestampCmp,
Transaction,
TransactionsRequest,
TransactionsResponse,
@@ -309,7 +309,7 @@ export async function getTransactions(
for (const rk of Object.keys(pr.refunds)) {
const refund = pr.refunds[rk];
- const groupKey = `${refund.executionTime.t_ms}`;
+ const groupKey = `${refund.executionTime.t_s}`;
refundGroupKeys.add(groupKey);
}
@@ -333,7 +333,7 @@ export async function getTransactions(
let amountEffective = Amounts.getZero(contractData.amount.currency);
for (const rk of Object.keys(pr.refunds)) {
const refund = pr.refunds[rk];
- const myGroupKey = `${refund.executionTime.t_ms}`;
+ const myGroupKey = `${refund.executionTime.t_s}`;
if (myGroupKey !== groupKey) {
continue;
}
@@ -403,8 +403,18 @@ export async function getTransactions(
const txPending = transactions.filter((x) => x.pending);
const txNotPending = transactions.filter((x) => !x.pending);
- txPending.sort((h1, h2) => timestampCmp(h1.timestamp, h2.timestamp));
- txNotPending.sort((h1, h2) => timestampCmp(h1.timestamp, h2.timestamp));
+ txPending.sort((h1, h2) =>
+ AbsoluteTime.cmp(
+ AbsoluteTime.fromTimestamp(h1.timestamp),
+ AbsoluteTime.fromTimestamp(h2.timestamp),
+ ),
+ );
+ txNotPending.sort((h1, h2) =>
+ AbsoluteTime.cmp(
+ AbsoluteTime.fromTimestamp(h1.timestamp),
+ AbsoluteTime.fromTimestamp(h2.timestamp),
+ ),
+ );
return { transactions: [...txNotPending, ...txPending] };
}
@@ -485,11 +495,10 @@ export async function deleteTransaction(
});
return;
}
- const reserveRecord:
- | ReserveRecord
- | undefined = await tx.reserves.indexes.byInitialWithdrawalGroupId.get(
- withdrawalGroupId,
- );
+ const reserveRecord: ReserveRecord | undefined =
+ await tx.reserves.indexes.byInitialWithdrawalGroupId.get(
+ withdrawalGroupId,
+ );
if (reserveRecord && !reserveRecord.initialWithdrawalStarted) {
const reservePub = reserveRecord.reservePub;
await tx.reserves.delete(reservePub);
diff --git a/packages/taler-wallet-core/src/operations/withdraw.test.ts b/packages/taler-wallet-core/src/operations/withdraw.test.ts
index 02540848a..e5894a3e7 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.test.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.test.ts
@@ -62,16 +62,16 @@ test("withdrawal selection bug repro", (t) => {
masterSig:
"4F0P456CNNTTWK8BFJHGM3JTD6FVVNZY8EP077GYAHDJ5Y81S5RQ3SMS925NXMDVG9A88JAAP0E2GDZBC21PP5NHFFVWHAW3AVT8J3R",
stampExpireDeposit: {
- t_ms: 1742909388000,
+ t_s: 1742909388,
},
stampExpireLegal: {
- t_ms: 1900589388000,
+ t_s: 1900589388,
},
stampExpireWithdraw: {
- t_ms: 1679837388000,
+ t_s: 1679837388,
},
stampStart: {
- t_ms: 1585229388000,
+ t_s: 1585229388,
},
verificationStatus: DenominationVerificationStatus.Unverified,
value: {
@@ -79,7 +79,7 @@ test("withdrawal selection bug repro", (t) => {
fraction: 0,
value: 1000,
},
- listIssueDate: { t_ms: 0 },
+ listIssueDate: { t_s: 0 },
},
{
denomPub: {
@@ -117,16 +117,16 @@ test("withdrawal selection bug repro", (t) => {
masterSig:
"P99AW82W46MZ0AKW7Z58VQPXFNTJQM9DVTYPBDF6KVYF38PPVDAZTV7JQ8TY7HGEC7JJJAY4E7AY7J3W1WV10DAZZQHHKTAVTSRAC20",
stampExpireDeposit: {
- t_ms: 1742909388000,
+ t_s: 1742909388,
},
stampExpireLegal: {
- t_ms: 1900589388000,
+ t_s: 1900589388,
},
stampExpireWithdraw: {
- t_ms: 1679837388000,
+ t_s: 1679837388,
},
stampStart: {
- t_ms: 1585229388000,
+ t_s: 1585229388,
},
verificationStatus: DenominationVerificationStatus.Unverified,
value: {
@@ -134,7 +134,7 @@ test("withdrawal selection bug repro", (t) => {
fraction: 0,
value: 10,
},
- listIssueDate: { t_ms: 0 },
+ listIssueDate: { t_s: 0 },
},
{
denomPub: {
@@ -171,16 +171,16 @@ test("withdrawal selection bug repro", (t) => {
masterSig:
"8S4VZGHE5WE0N5ZVCHYW9KZZR4YAKK15S46MV1HR1QB9AAMH3NWPW4DCR4NYGJK33Q8YNFY80SWNS6XKAP5DEVK933TM894FJ2VGE3G",
stampExpireDeposit: {
- t_ms: 1742909388000,
+ t_s: 1742909388,
},
stampExpireLegal: {
- t_ms: 1900589388000,
+ t_s: 1900589388,
},
stampExpireWithdraw: {
- t_ms: 1679837388000,
+ t_s: 1679837388,
},
stampStart: {
- t_ms: 1585229388000,
+ t_s: 1585229388,
},
verificationStatus: DenominationVerificationStatus.Unverified,
value: {
@@ -188,7 +188,7 @@ test("withdrawal selection bug repro", (t) => {
fraction: 0,
value: 5,
},
- listIssueDate: { t_ms: 0 },
+ listIssueDate: { t_s: 0 },
},
{
denomPub: {
@@ -226,16 +226,16 @@ test("withdrawal selection bug repro", (t) => {
masterSig:
"E3AWGAG8VB42P3KXM8B04Z6M483SX59R3Y4T53C3NXCA2NPB6C7HVCMVX05DC6S58E9X40NGEBQNYXKYMYCF3ASY2C4WP1WCZ4ME610",
stampExpireDeposit: {
- t_ms: 1742909388000,
+ t_s: 1742909388,
},
stampExpireLegal: {
- t_ms: 1900589388000,
+ t_s: 1900589388,
},
stampExpireWithdraw: {
- t_ms: 1679837388000,
+ t_s: 1679837388,
},
stampStart: {
- t_ms: 1585229388000,
+ t_s: 1585229388,
},
verificationStatus: DenominationVerificationStatus.Unverified,
value: {
@@ -243,7 +243,7 @@ test("withdrawal selection bug repro", (t) => {
fraction: 0,
value: 1,
},
- listIssueDate: { t_ms: 0 },
+ listIssueDate: { t_s: 0 },
},
{
denomPub: {
@@ -280,16 +280,16 @@ test("withdrawal selection bug repro", (t) => {
masterSig:
"0ES1RKV002XB4YP21SN0QB7RSDHGYT0XAE65JYN8AVJAA6H7JZFN7JADXT521DJS89XMGPZGR8GCXF1516Y0Q9QDV00E6NMFA6CF838",
stampExpireDeposit: {
- t_ms: 1742909388000,
+ t_s: 1742909388,
},
stampExpireLegal: {
- t_ms: 1900589388000,
+ t_s: 1900589388,
},
stampExpireWithdraw: {
- t_ms: 1679837388000,
+ t_s: 1679837388,
},
stampStart: {
- t_ms: 1585229388000,
+ t_s: 1585229388,
},
verificationStatus: DenominationVerificationStatus.Unverified,
value: {
@@ -297,7 +297,7 @@ test("withdrawal selection bug repro", (t) => {
fraction: 10000000,
value: 0,
},
- listIssueDate: { t_ms: 0 },
+ listIssueDate: { t_s: 0 },
},
{
denomPub: {
@@ -334,16 +334,16 @@ test("withdrawal selection bug repro", (t) => {
masterSig:
"58QEB6C6N7602E572E3JYANVVJ9BRW0V9E2ZFDW940N47YVQDK9SAFPWBN5YGT3G1742AFKQ0CYR4DM2VWV0Z0T1XMEKWN6X2EZ9M0R",
stampExpireDeposit: {
- t_ms: 1742909388000,
+ t_s: 1742909388,
},
stampExpireLegal: {
- t_ms: 1900589388000,
+ t_s: 1900589388,
},
stampExpireWithdraw: {
- t_ms: 1679837388000,
+ t_s: 1679837388,
},
stampStart: {
- t_ms: 1585229388000,
+ t_s: 1585229388,
},
verificationStatus: DenominationVerificationStatus.Unverified,
value: {
@@ -351,7 +351,7 @@ test("withdrawal selection bug repro", (t) => {
fraction: 0,
value: 2,
},
- listIssueDate: { t_ms: 0 },
+ listIssueDate: { t_s: 0 },
},
];
diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts
index 392cecf0b..e4c6f2a6a 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.ts
@@ -26,16 +26,12 @@ import {
codecForWithdrawResponse,
durationFromSpec,
ExchangeListItem,
- getDurationRemaining,
- getTimestampNow,
Logger,
NotificationType,
parseWithdrawUri,
TalerErrorCode,
TalerErrorDetails,
- Timestamp,
- timestampCmp,
- timestampSubtractDuraction,
+ AbsoluteTime,
WithdrawResponse,
URL,
WithdrawUriInfoResponse,
@@ -44,6 +40,8 @@ import {
LibtoolVersion,
UnblindedSignature,
ExchangeWithdrawRequest,
+ Duration,
+ TalerProtocolTimestamp,
} from "@gnu-taler/taler-util";
import {
CoinRecord,
@@ -147,7 +145,7 @@ export interface ExchangeWithdrawDetails {
/**
* The earliest deposit expiration of the selected coins.
*/
- earliestDepositExpiration: Timestamp;
+ earliestDepositExpiration: TalerProtocolTimestamp;
/**
* Number of currently offered denominations.
@@ -184,18 +182,20 @@ export interface ExchangeWithdrawDetails {
* revocation and offered state.
*/
export function isWithdrawableDenom(d: DenominationRecord): boolean {
- const now = getTimestampNow();
- const started = timestampCmp(now, d.stampStart) >= 0;
- let lastPossibleWithdraw: Timestamp;
+ const now = AbsoluteTime.now();
+ const start = AbsoluteTime.fromTimestamp(d.stampStart);
+ const withdrawExpire = AbsoluteTime.fromTimestamp(d.stampExpireWithdraw);
+ const started = AbsoluteTime.cmp(now, start) >= 0;
+ let lastPossibleWithdraw: AbsoluteTime;
if (walletCoreDebugFlags.denomselAllowLate) {
- lastPossibleWithdraw = d.stampExpireWithdraw;
+ lastPossibleWithdraw = start;
} else {
- lastPossibleWithdraw = timestampSubtractDuraction(
- d.stampExpireWithdraw,
+ lastPossibleWithdraw = AbsoluteTime.subtractDuraction(
+ withdrawExpire,
durationFromSpec({ minutes: 5 }),
);
}
- const remaining = getDurationRemaining(lastPossibleWithdraw, now);
+ const remaining = Duration.getRemaining(lastPossibleWithdraw, now);
const stillOkay = remaining.d_ms !== 0;
return started && stillOkay && !d.isRevoked && d.isOffered;
}
@@ -274,7 +274,7 @@ export function selectWithdrawalDenominations(
/**
* Get information about a withdrawal from
* a taler://withdraw URI by asking the bank.
- *
+ *
* FIXME: Move into bank client.
*/
export async function getBankWithdrawalInfo(
@@ -947,7 +947,7 @@ async function processWithdrawGroupImpl(
logger.trace(`now withdrawn ${numFinished} of ${numTotalCoins} coins`);
if (wg.timestampFinish === undefined && numFinished === numTotalCoins) {
finishedForFirstTime = true;
- wg.timestampFinish = getTimestampNow();
+ wg.timestampFinish = TalerProtocolTimestamp.now();
wg.operationStatus = OperationStatus.Finished;
delete wg.lastError;
wg.retryInfo = initRetryInfo();
@@ -999,7 +999,12 @@ export async function getExchangeWithdrawalInfo(
for (let i = 1; i < selectedDenoms.selectedDenoms.length; i++) {
const expireDeposit =
selectedDenoms.selectedDenoms[i].denom.stampExpireDeposit;
- if (expireDeposit.t_ms < earliestDepositExpiration.t_ms) {
+ if (
+ AbsoluteTime.cmp(
+ AbsoluteTime.fromTimestamp(expireDeposit),
+ AbsoluteTime.fromTimestamp(earliestDepositExpiration),
+ ) < 0
+ ) {
earliestDepositExpiration = expireDeposit;
}
}