diff options
Diffstat (limited to 'packages/taler-util/src')
-rw-r--r-- | packages/taler-util/src/RequestThrottler.ts | 10 | ||||
-rw-r--r-- | packages/taler-util/src/ReserveTransaction.ts | 96 | ||||
-rw-r--r-- | packages/taler-util/src/backupTypes.ts | 74 | ||||
-rw-r--r-- | packages/taler-util/src/talerTypes.ts | 51 | ||||
-rw-r--r-- | packages/taler-util/src/time.ts | 356 | ||||
-rw-r--r-- | packages/taler-util/src/transactionsTypes.ts | 4 | ||||
-rw-r--r-- | packages/taler-util/src/types-test.ts | 16 | ||||
-rw-r--r-- | packages/taler-util/src/walletTypes.ts | 14 |
8 files changed, 340 insertions, 281 deletions
diff --git a/packages/taler-util/src/RequestThrottler.ts b/packages/taler-util/src/RequestThrottler.ts index 7689b4215..a151cc634 100644 --- a/packages/taler-util/src/RequestThrottler.ts +++ b/packages/taler-util/src/RequestThrottler.ts @@ -15,7 +15,7 @@ */ import { Logger } from "./logging.js"; -import { getTimestampNow, timestampCmp, timestampDifference } from "./time.js"; +import { AbsoluteTime } from "./time.js"; /** * Implementation of token bucket throttling. @@ -46,16 +46,16 @@ class OriginState { tokensSecond: number = MAX_PER_SECOND; tokensMinute: number = MAX_PER_MINUTE; tokensHour: number = MAX_PER_HOUR; - private lastUpdate = getTimestampNow(); + private lastUpdate = AbsoluteTime.now(); private refill(): void { - const now = getTimestampNow(); - if (timestampCmp(now, this.lastUpdate) < 0) { + const now = AbsoluteTime.now(); + if (AbsoluteTime.cmp(now, this.lastUpdate) < 0) { // Did the system time change? this.lastUpdate = now; return; } - const d = timestampDifference(now, this.lastUpdate); + const d = AbsoluteTime.difference(now, this.lastUpdate); if (d.d_ms === "forever") { throw Error("assertion failed"); } diff --git a/packages/taler-util/src/ReserveTransaction.ts b/packages/taler-util/src/ReserveTransaction.ts index b282ef189..50610483f 100644 --- a/packages/taler-util/src/ReserveTransaction.ts +++ b/packages/taler-util/src/ReserveTransaction.ts @@ -38,7 +38,11 @@ import { EddsaPublicKeyString, CoinPublicKeyString, } from "./talerTypes"; -import { Timestamp, codecForTimestamp } from "./time.js"; +import { + AbsoluteTime, + codecForTimestamp, + TalerProtocolTimestamp, +} from "./time.js"; export enum ReserveTransactionType { Withdraw = "WITHDRAW", @@ -98,7 +102,7 @@ export interface ReserveCreditTransaction { /** * Timestamp of the incoming wire transfer. */ - timestamp: Timestamp; + timestamp: TalerProtocolTimestamp; } export interface ReserveClosingTransaction { @@ -139,7 +143,7 @@ export interface ReserveClosingTransaction { /** * Time when the reserve was closed. */ - timestamp: Timestamp; + timestamp: TalerProtocolTimestamp; } export interface ReserveRecoupTransaction { @@ -165,7 +169,7 @@ export interface ReserveRecoupTransaction { /** * Time when the funds were paid back into the reserve. */ - timestamp: Timestamp; + timestamp: TalerProtocolTimestamp; /** * Public key of the coin that was paid back. @@ -182,46 +186,50 @@ export type ReserveTransaction = | ReserveClosingTransaction | ReserveRecoupTransaction; -export const codecForReserveWithdrawTransaction = (): Codec<ReserveWithdrawTransaction> => - buildCodecForObject<ReserveWithdrawTransaction>() - .property("amount", codecForString()) - .property("h_coin_envelope", codecForString()) - .property("h_denom_pub", codecForString()) - .property("reserve_sig", codecForString()) - .property("type", codecForConstString(ReserveTransactionType.Withdraw)) - .property("withdraw_fee", codecForString()) - .build("ReserveWithdrawTransaction"); - -export const codecForReserveCreditTransaction = (): Codec<ReserveCreditTransaction> => - buildCodecForObject<ReserveCreditTransaction>() - .property("amount", codecForString()) - .property("sender_account_url", codecForString()) - .property("timestamp", codecForTimestamp) - .property("wire_reference", codecForNumber()) - .property("type", codecForConstString(ReserveTransactionType.Credit)) - .build("ReserveCreditTransaction"); - -export const codecForReserveClosingTransaction = (): Codec<ReserveClosingTransaction> => - buildCodecForObject<ReserveClosingTransaction>() - .property("amount", codecForString()) - .property("closing_fee", codecForString()) - .property("exchange_pub", codecForString()) - .property("exchange_sig", codecForString()) - .property("h_wire", codecForString()) - .property("timestamp", codecForTimestamp) - .property("type", codecForConstString(ReserveTransactionType.Closing)) - .property("wtid", codecForString()) - .build("ReserveClosingTransaction"); - -export const codecForReserveRecoupTransaction = (): Codec<ReserveRecoupTransaction> => - buildCodecForObject<ReserveRecoupTransaction>() - .property("amount", codecForString()) - .property("coin_pub", codecForString()) - .property("exchange_pub", codecForString()) - .property("exchange_sig", codecForString()) - .property("timestamp", codecForTimestamp) - .property("type", codecForConstString(ReserveTransactionType.Recoup)) - .build("ReserveRecoupTransaction"); +export const codecForReserveWithdrawTransaction = + (): Codec<ReserveWithdrawTransaction> => + buildCodecForObject<ReserveWithdrawTransaction>() + .property("amount", codecForString()) + .property("h_coin_envelope", codecForString()) + .property("h_denom_pub", codecForString()) + .property("reserve_sig", codecForString()) + .property("type", codecForConstString(ReserveTransactionType.Withdraw)) + .property("withdraw_fee", codecForString()) + .build("ReserveWithdrawTransaction"); + +export const codecForReserveCreditTransaction = + (): Codec<ReserveCreditTransaction> => + buildCodecForObject<ReserveCreditTransaction>() + .property("amount", codecForString()) + .property("sender_account_url", codecForString()) + .property("timestamp", codecForTimestamp) + .property("wire_reference", codecForNumber()) + .property("type", codecForConstString(ReserveTransactionType.Credit)) + .build("ReserveCreditTransaction"); + +export const codecForReserveClosingTransaction = + (): Codec<ReserveClosingTransaction> => + buildCodecForObject<ReserveClosingTransaction>() + .property("amount", codecForString()) + .property("closing_fee", codecForString()) + .property("exchange_pub", codecForString()) + .property("exchange_sig", codecForString()) + .property("h_wire", codecForString()) + .property("timestamp", codecForTimestamp) + .property("type", codecForConstString(ReserveTransactionType.Closing)) + .property("wtid", codecForString()) + .build("ReserveClosingTransaction"); + +export const codecForReserveRecoupTransaction = + (): Codec<ReserveRecoupTransaction> => + buildCodecForObject<ReserveRecoupTransaction>() + .property("amount", codecForString()) + .property("coin_pub", codecForString()) + .property("exchange_pub", codecForString()) + .property("exchange_sig", codecForString()) + .property("timestamp", codecForTimestamp) + .property("type", codecForConstString(ReserveTransactionType.Recoup)) + .build("ReserveRecoupTransaction"); export const codecForReserveTransaction = (): Codec<ReserveTransaction> => buildCodecForUnion<ReserveTransaction>() diff --git a/packages/taler-util/src/backupTypes.ts b/packages/taler-util/src/backupTypes.ts index 41a9ce98e..b31a83831 100644 --- a/packages/taler-util/src/backupTypes.ts +++ b/packages/taler-util/src/backupTypes.ts @@ -54,7 +54,7 @@ * Imports. */ import { DenominationPubKey, UnblindedSignature } from "./talerTypes.js"; -import { Duration, Timestamp } from "./time.js"; +import { TalerProtocolDuration, TalerProtocolTimestamp } from "./time.js"; /** * Type alias for strings that are to be treated like amounts. @@ -120,7 +120,7 @@ export interface WalletBackupContentV1 { * This timestamp should only be advanced if the content * of the backup changes. */ - timestamp: Timestamp; + timestamp: TalerProtocolTimestamp; /** * Per-exchange data sorted by exchange master public key. @@ -333,10 +333,10 @@ export interface BackupRecoupGroup { /** * Timestamp when the recoup was started. */ - timestamp_created: Timestamp; + timestamp_created: TalerProtocolTimestamp; - timestamp_finish?: Timestamp; - finish_clock?: Timestamp; + timestamp_finish?: TalerProtocolTimestamp; + finish_clock?: TalerProtocolTimestamp; finish_is_failure?: boolean; /** @@ -486,14 +486,14 @@ export interface BackupTip { * Has the user accepted the tip? Only after the tip has been accepted coins * withdrawn from the tip may be used. */ - timestamp_accepted: Timestamp | undefined; + timestamp_accepted: TalerProtocolTimestamp | undefined; /** * When was the tip first scanned by the wallet? */ - timestamp_created: Timestamp; + timestamp_created: TalerProtocolTimestamp; - timestamp_finished?: Timestamp; + timestamp_finished?: TalerProtocolTimestamp; finish_is_failure?: boolean; /** @@ -504,7 +504,7 @@ export interface BackupTip { /** * Timestamp, the tip can't be picked up anymore after this deadline. */ - timestamp_expiration: Timestamp; + timestamp_expiration: TalerProtocolTimestamp; /** * The exchange that will sign our coins, chosen by the merchant. @@ -613,9 +613,9 @@ export interface BackupRefreshGroup { */ old_coins: BackupRefreshOldCoin[]; - timestamp_created: Timestamp; + timestamp_created: TalerProtocolTimestamp; - timestamp_finish?: Timestamp; + timestamp_finish?: TalerProtocolTimestamp; finish_is_failure?: boolean; } @@ -636,9 +636,9 @@ export interface BackupWithdrawalGroup { * When was the withdrawal operation started started? * Timestamp in milliseconds. */ - timestamp_created: Timestamp; + timestamp_created: TalerProtocolTimestamp; - timestamp_finish?: Timestamp; + timestamp_finish?: TalerProtocolTimestamp; finish_is_failure?: boolean; /** @@ -672,12 +672,12 @@ export interface BackupRefundItemCommon { /** * Execution time as claimed by the merchant */ - execution_time: Timestamp; + execution_time: TalerProtocolTimestamp; /** * Time when the wallet became aware of the refund. */ - obtained_time: Timestamp; + obtained_time: TalerProtocolTimestamp; /** * Amount refunded for the coin. @@ -788,7 +788,7 @@ export interface BackupPurchase { * Timestamp of the first time that sending a payment to the merchant * for this purchase was successful. */ - timestamp_first_successful_pay: Timestamp | undefined; + timestamp_first_successful_pay: TalerProtocolTimestamp | undefined; /** * Signature by the merchant confirming the payment. @@ -799,7 +799,7 @@ export interface BackupPurchase { * When was the purchase made? * Refers to the time that the user accepted. */ - timestamp_accept: Timestamp; + timestamp_accept: TalerProtocolTimestamp; /** * Pending refunds for the purchase. A refund is pending @@ -815,7 +815,7 @@ export interface BackupPurchase { /** * Continue querying the refund status until this deadline has expired. */ - auto_refund_deadline: Timestamp | undefined; + auto_refund_deadline: TalerProtocolTimestamp | undefined; } /** @@ -857,22 +857,22 @@ export interface BackupDenomination { /** * Validity start date of the denomination. */ - stamp_start: Timestamp; + stamp_start: TalerProtocolTimestamp; /** * Date after which the currency can't be withdrawn anymore. */ - stamp_expire_withdraw: Timestamp; + stamp_expire_withdraw: TalerProtocolTimestamp; /** * Date after the denomination officially doesn't exist anymore. */ - stamp_expire_legal: Timestamp; + stamp_expire_legal: TalerProtocolTimestamp; /** * Data after which coins of this denomination can't be deposited anymore. */ - stamp_expire_deposit: Timestamp; + stamp_expire_deposit: TalerProtocolTimestamp; /** * Signature by the exchange's master key over the denomination @@ -903,7 +903,7 @@ export interface BackupDenomination { * The list issue date of the exchange "/keys" response * that this denomination was last seen in. */ - list_issue_date: Timestamp; + list_issue_date: TalerProtocolTimestamp; } /** @@ -923,14 +923,14 @@ export interface BackupReserve { /** * Time when the reserve was created. */ - timestamp_created: Timestamp; + timestamp_created: TalerProtocolTimestamp; /** * Timestamp of the last observed activity. * * Used to compute when to give up querying the exchange. */ - timestamp_last_activity: Timestamp; + timestamp_last_activity: TalerProtocolTimestamp; /** * Timestamp of when the reserve closed. @@ -938,7 +938,7 @@ export interface BackupReserve { * Note that the last activity can be after the closing time * due to recouping. */ - timestamp_closed?: Timestamp; + timestamp_closed?: TalerProtocolTimestamp; /** * Wire information (as payto URI) for the bank account that @@ -977,14 +977,14 @@ export interface BackupReserve { /** * Time when the information about this reserve was posted to the bank. */ - timestamp_reserve_info_posted: Timestamp | undefined; + timestamp_reserve_info_posted: TalerProtocolTimestamp | undefined; /** * Time when the reserve was confirmed by the bank. * * Set to undefined if not confirmed yet. */ - timestamp_bank_confirmed: Timestamp | undefined; + timestamp_bank_confirmed: TalerProtocolTimestamp | undefined; }; /** @@ -1033,12 +1033,12 @@ export interface BackupExchangeWireFee { /** * Start date of the fee. */ - start_stamp: Timestamp; + start_stamp: TalerProtocolTimestamp; /** * End date of the fee. */ - end_stamp: Timestamp; + end_stamp: TalerProtocolTimestamp; /** * Signature made by the exchange master key. @@ -1050,9 +1050,9 @@ export interface BackupExchangeWireFee { * Structure of one exchange signing key in the /keys response. */ export class BackupExchangeSignKey { - stamp_start: Timestamp; - stamp_expire: Timestamp; - stamp_end: Timestamp; + stamp_start: TalerProtocolTimestamp; + stamp_expire: TalerProtocolTimestamp; + stamp_end: TalerProtocolTimestamp; key: string; master_sig: string; } @@ -1112,7 +1112,7 @@ export interface BackupExchange { * * Used to facilitate automatic merging. */ - update_clock: Timestamp; + update_clock: TalerProtocolTimestamp; } /** @@ -1161,7 +1161,7 @@ export interface BackupExchangeDetails { /** * Closing delay of reserves. */ - reserve_closing_delay: Duration; + reserve_closing_delay: TalerProtocolDuration; /** * Signing keys we got from the exchange, can also contain @@ -1187,7 +1187,7 @@ export interface BackupExchangeDetails { /** * Timestamp when the ToS has been accepted. */ - tos_accepted_timestamp: Timestamp | undefined; + tos_accepted_timestamp: TalerProtocolTimestamp | undefined; } export enum BackupProposalStatus { @@ -1248,7 +1248,7 @@ export interface BackupProposal { * Timestamp of when the record * was created. */ - timestamp: Timestamp; + timestamp: TalerProtocolTimestamp; /** * Private key for the nonce. diff --git a/packages/taler-util/src/talerTypes.ts b/packages/taler-util/src/talerTypes.ts index 4ccfffce0..b1bf6ab38 100644 --- a/packages/taler-util/src/talerTypes.ts +++ b/packages/taler-util/src/talerTypes.ts @@ -38,15 +38,14 @@ import { codecForConstNumber, buildCodecForUnion, codecForConstString, - codecForEither, } from "./codec.js"; import { - Timestamp, codecForTimestamp, - Duration, codecForDuration, + TalerProtocolTimestamp, + TalerProtocolDuration, } from "./time.js"; -import { Amounts, codecForAmountString } from "./amounts.js"; +import { codecForAmountString } from "./amounts.js"; import { strcmp } from "./helpers.js"; /** @@ -86,24 +85,24 @@ export class ExchangeDenomination { /** * Start date from which withdraw is allowed. */ - stamp_start: Timestamp; + stamp_start: TalerProtocolTimestamp; /** * End date for withdrawing. */ - stamp_expire_withdraw: Timestamp; + stamp_expire_withdraw: TalerProtocolTimestamp; /** * Expiration date after which the exchange can forget about * the currency. */ - stamp_expire_legal: Timestamp; + stamp_expire_legal: TalerProtocolTimestamp; /** * Date after which the coins of this denomination can't be * deposited anymore. */ - stamp_expire_deposit: Timestamp; + stamp_expire_deposit: TalerProtocolTimestamp; /** * Signature over the denomination information by the exchange's master @@ -394,7 +393,7 @@ export interface Product { taxes?: Tax[]; // time indicating when this product should be delivered - delivery_date?: Timestamp; + delivery_date?: TalerProtocolTimestamp; } export interface InternationalizedString { @@ -413,7 +412,7 @@ export interface ContractTerms { /** * Hash of the merchant's wire details. */ - auto_refund?: Duration; + auto_refund?: TalerProtocolDuration; /** * Wire method the merchant wants to use. @@ -445,7 +444,7 @@ export interface ContractTerms { /** * Deadline to pay for the contract. */ - pay_deadline: Timestamp; + pay_deadline: TalerProtocolTimestamp; /** * Maximum deposit fee covered by the merchant. @@ -466,7 +465,7 @@ export interface ContractTerms { * Time indicating when the order should be delivered. * May be overwritten by individual products. */ - delivery_date?: Timestamp; + delivery_date?: TalerProtocolTimestamp; /** * Delivery location for (all!) products. @@ -486,17 +485,17 @@ export interface ContractTerms { /** * Deadline for refunds. */ - refund_deadline: Timestamp; + refund_deadline: TalerProtocolTimestamp; /** * Deadline for the wire transfer. */ - wire_transfer_deadline: Timestamp; + wire_transfer_deadline: TalerProtocolTimestamp; /** * Time when the contract was generated by the merchant. */ - timestamp: Timestamp; + timestamp: TalerProtocolTimestamp; /** * Order id to uniquely identify the purchase within @@ -700,9 +699,9 @@ export class Recoup { * Structure of one exchange signing key in the /keys response. */ export class ExchangeSignKeyJson { - stamp_start: Timestamp; - stamp_expire: Timestamp; - stamp_end: Timestamp; + stamp_start: TalerProtocolTimestamp; + stamp_expire: TalerProtocolTimestamp; + stamp_end: TalerProtocolTimestamp; key: EddsaPublicKeyString; master_sig: EddsaSignatureString; } @@ -729,7 +728,7 @@ export class ExchangeKeysJson { /** * Timestamp when this response was issued. */ - list_issue_date: Timestamp; + list_issue_date: TalerProtocolTimestamp; /** * List of revoked denominations. @@ -747,7 +746,7 @@ export class ExchangeKeysJson { */ version: string; - reserve_closing_delay: Duration; + reserve_closing_delay: TalerProtocolDuration; } /** @@ -774,12 +773,12 @@ export class WireFeesJson { /** * Date from which the fee applies. */ - start_date: Timestamp; + start_date: TalerProtocolTimestamp; /** * Data after which the fee doesn't apply anymore. */ - end_date: Timestamp; + end_date: TalerProtocolTimestamp; } export interface AccountInfo { @@ -850,7 +849,7 @@ export class TipPickupGetResponse { exchange_url: string; - expiration: Timestamp; + expiration: TalerProtocolTimestamp; } export enum DenomKeyType { @@ -1067,7 +1066,7 @@ export interface MerchantCoinRefundSuccessStatus { // to the customer. refund_amount: AmountString; - execution_time: Timestamp; + execution_time: TalerProtocolTimestamp; } export interface MerchantCoinRefundFailureStatus { @@ -1092,7 +1091,7 @@ export interface MerchantCoinRefundFailureStatus { // to the customer. refund_amount: AmountString; - execution_time: Timestamp; + execution_time: TalerProtocolTimestamp; } export interface MerchantOrderStatusUnpaid { @@ -1733,7 +1732,7 @@ export interface DepositSuccess { transaction_base_url?: string; // timestamp when the deposit was received by the exchange. - exchange_timestamp: Timestamp; + exchange_timestamp: TalerProtocolTimestamp; // the EdDSA signature of TALER_DepositConfirmationPS using a current // signing key of the exchange affirming the successful diff --git a/packages/taler-util/src/time.ts b/packages/taler-util/src/time.ts index 9f9571019..43cb7ad4d 100644 --- a/packages/taler-util/src/time.ts +++ b/packages/taler-util/src/time.ts @@ -23,13 +23,41 @@ */ import { Codec, renderContext, Context } from "./codec.js"; -export interface Timestamp { +export interface AbsoluteTime { /** * Timestamp in milliseconds. */ readonly t_ms: number | "never"; } +export interface TalerProtocolTimestamp { + readonly t_s: number | "never"; +} + +export namespace TalerProtocolTimestamp { + export function now(): TalerProtocolTimestamp { + return AbsoluteTime.toTimestamp(AbsoluteTime.now()); + } + + export function zero(): TalerProtocolTimestamp { + return { + t_s: 0, + }; + } + + export function never(): TalerProtocolTimestamp { + return { + t_s: "never", + }; + } + + export function fromSeconds(s: number): TalerProtocolTimestamp { + return { + t_s: s, + }; + } +} + export interface Duration { /** * Duration in milliseconds. @@ -37,40 +65,32 @@ export interface Duration { readonly d_ms: number | "forever"; } +export interface TalerProtocolDuration { + readonly d_us: number | "forever"; +} + let timeshift = 0; export function setDangerousTimetravel(dt: number): void { timeshift = dt; } -export function getTimestampNow(): Timestamp { - return { - t_ms: new Date().getTime() + timeshift, - }; -} - -export function isTimestampExpired(t: Timestamp) { - return timestampCmp(t, getTimestampNow()) <= 0; -} - -export function getDurationRemaining( - deadline: Timestamp, - now = getTimestampNow(), -): Duration { - if (deadline.t_ms === "never") { - return { d_ms: "forever" }; - } - if (now.t_ms === "never") { - throw Error("invalid argument for 'now'"); - } - if (deadline.t_ms < now.t_ms) { - return { d_ms: 0 }; - } - return { d_ms: deadline.t_ms - now.t_ms }; -} - export namespace Duration { - export const getRemaining = getDurationRemaining; + export function getRemaining( + deadline: AbsoluteTime, + now = AbsoluteTime.now(), + ): Duration { + if (deadline.t_ms === "never") { + return { d_ms: "forever" }; + } + if (now.t_ms === "never") { + throw Error("invalid argument for 'now'"); + } + if (deadline.t_ms < now.t_ms) { + return { d_ms: 0 }; + } + return { d_ms: deadline.t_ms - now.t_ms }; + } export function toIntegerYears(d: Duration): number { if (typeof d.d_ms !== "number") { throw Error("infinite duration"); @@ -81,33 +101,152 @@ export namespace Duration { export function getForever(): Duration { return { d_ms: "forever" }; } + export function fromTalerProtocolDuration( + d: TalerProtocolDuration, + ): Duration { + if (d.d_us === "forever") { + return { + d_ms: "forever", + }; + } + return { + d_ms: d.d_us / 1000, + }; + } } -export namespace Timestamp { - export const now = getTimestampNow; - export const min = timestampMin; - export const isExpired = isTimestampExpired; - export const truncateToSecond = timestampTruncateToSecond; -} +export namespace AbsoluteTime { + export function now(): AbsoluteTime { + return { + t_ms: new Date().getTime() + timeshift, + }; + } -export function timestampMin(t1: Timestamp, t2: Timestamp): Timestamp { - if (t1.t_ms === "never") { - return { t_ms: t2.t_ms }; + export function never(): AbsoluteTime { + return { + t_ms: "never", + }; } - if (t2.t_ms === "never") { - return { t_ms: t2.t_ms }; + + export function cmp(t1: AbsoluteTime, t2: AbsoluteTime): number { + if (t1.t_ms === "never") { + if (t2.t_ms === "never") { + return 0; + } + return 1; + } + if (t2.t_ms === "never") { + return -1; + } + if (t1.t_ms == t2.t_ms) { + return 0; + } + if (t1.t_ms > t2.t_ms) { + return 1; + } + return -1; + } + + export function min(t1: AbsoluteTime, t2: AbsoluteTime): AbsoluteTime { + if (t1.t_ms === "never") { + return { t_ms: t2.t_ms }; + } + if (t2.t_ms === "never") { + return { t_ms: t2.t_ms }; + } + return { t_ms: Math.min(t1.t_ms, t2.t_ms) }; } - return { t_ms: Math.min(t1.t_ms, t2.t_ms) }; -} -export function timestampMax(t1: Timestamp, t2: Timestamp): Timestamp { - if (t1.t_ms === "never") { - return { t_ms: "never" }; + export function max(t1: AbsoluteTime, t2: AbsoluteTime): AbsoluteTime { + if (t1.t_ms === "never") { + return { t_ms: "never" }; + } + if (t2.t_ms === "never") { + return { t_ms: "never" }; + } + return { t_ms: Math.max(t1.t_ms, t2.t_ms) }; } - if (t2.t_ms === "never") { - return { t_ms: "never" }; + + export function difference(t1: AbsoluteTime, t2: AbsoluteTime): Duration { + if (t1.t_ms === "never") { + return { d_ms: "forever" }; + } + if (t2.t_ms === "never") { + return { d_ms: "forever" }; + } + return { d_ms: Math.abs(t1.t_ms - t2.t_ms) }; + } + + export function isExpired(t: AbsoluteTime) { + return cmp(t, now()) <= 0; + } + + export function fromTimestamp(t: TalerProtocolTimestamp): AbsoluteTime { + if (t.t_s === "never") { + return { t_ms: "never" }; + } + return { + t_ms: t.t_s * 1000, + }; + } + + export function toTimestamp(at: AbsoluteTime): TalerProtocolTimestamp { + if (at.t_ms === "never") { + return { t_s: "never" }; + } + return { + t_s: Math.floor(at.t_ms / 1000), + }; + } + + export function isBetween( + t: AbsoluteTime, + start: AbsoluteTime, + end: AbsoluteTime, + ): boolean { + if (cmp(t, start) < 0) { + return false; + } + if (cmp(t, end) > 0) { + return false; + } + return true; + } + + export function toIsoString(t: AbsoluteTime): string { + if (t.t_ms === "never") { + return "<never>"; + } else { + return new Date(t.t_ms).toISOString(); + } + } + + export function addDuration(t1: AbsoluteTime, d: Duration): AbsoluteTime { + if (t1.t_ms === "never" || d.d_ms === "forever") { + return { t_ms: "never" }; + } + return { t_ms: t1.t_ms + d.d_ms }; + } + + export function subtractDuraction( + t1: AbsoluteTime, + d: Duration, + ): AbsoluteTime { + if (t1.t_ms === "never") { + return { t_ms: "never" }; + } + if (d.d_ms === "forever") { + return { t_ms: 0 }; + } + return { t_ms: Math.max(0, t1.t_ms - d.d_ms) }; + } + + export function stringify(t: AbsoluteTime): string { + if (t.t_ms === "never") { + return "never"; + } + return new Date(t.t_ms).toISOString(); } - return { t_ms: Math.max(t1.t_ms, t2.t_ms) }; } const SECONDS = 1000; @@ -135,19 +274,6 @@ export function durationFromSpec(spec: { return { d_ms }; } -/** - * Truncate a timestamp so that that it represents a multiple - * of seconds. The timestamp is always rounded down. - */ -export function timestampTruncateToSecond(t1: Timestamp): Timestamp { - if (t1.t_ms === "never") { - return { t_ms: "never" }; - } - return { - t_ms: Math.floor(t1.t_ms / 1000) * 1000, - }; -} - export function durationMin(d1: Duration, d2: Duration): Duration { if (d1.d_ms === "forever") { return { d_ms: d2.d_ms }; @@ -182,111 +308,33 @@ export function durationAdd(d1: Duration, d2: Duration): Duration { return { d_ms: d1.d_ms + d2.d_ms }; } -export function timestampCmp(t1: Timestamp, t2: Timestamp): number { - if (t1.t_ms === "never") { - if (t2.t_ms === "never") { - return 0; - } - return 1; - } - if (t2.t_ms === "never") { - return -1; - } - if (t1.t_ms == t2.t_ms) { - return 0; - } - if (t1.t_ms > t2.t_ms) { - return 1; - } - return -1; -} - -export function timestampAddDuration(t1: Timestamp, d: Duration): Timestamp { - if (t1.t_ms === "never" || d.d_ms === "forever") { - return { t_ms: "never" }; - } - return { t_ms: t1.t_ms + d.d_ms }; -} - -export function timestampSubtractDuraction( - t1: Timestamp, - d: Duration, -): Timestamp { - if (t1.t_ms === "never") { - return { t_ms: "never" }; - } - if (d.d_ms === "forever") { - return { t_ms: 0 }; - } - return { t_ms: Math.max(0, t1.t_ms - d.d_ms) }; -} - -export function stringifyTimestamp(t: Timestamp): string { - if (t.t_ms === "never") { - return "never"; - } - return new Date(t.t_ms).toISOString(); -} - -export function timestampDifference(t1: Timestamp, t2: Timestamp): Duration { - if (t1.t_ms === "never") { - return { d_ms: "forever" }; - } - if (t2.t_ms === "never") { - return { d_ms: "forever" }; - } - return { d_ms: Math.abs(t1.t_ms - t2.t_ms) }; -} - -export function timestampToIsoString(t: Timestamp): string { - if (t.t_ms === "never") { - return "<never>"; - } else { - return new Date(t.t_ms).toISOString(); - } -} - -export function timestampIsBetween( - t: Timestamp, - start: Timestamp, - end: Timestamp, -): boolean { - if (timestampCmp(t, start) < 0) { - return false; - } - if (timestampCmp(t, end) > 0) { - return false; - } - return true; -} - -export const codecForTimestamp: Codec<Timestamp> = { - decode(x: any, c?: Context): Timestamp { - const t_ms = x.t_ms; - if (typeof t_ms === "string") { - if (t_ms === "never") { - return { t_ms: "never" }; +export const codecForTimestamp: Codec<TalerProtocolTimestamp> = { + decode(x: any, c?: Context): TalerProtocolTimestamp { + const t_s = x.t_s; + if (typeof t_s === "string") { + if (t_s === "never") { + return { t_s: "never" }; } throw Error(`expected timestamp at ${renderContext(c)}`); } - if (typeof t_ms === "number") { - return { t_ms }; + if (typeof t_s === "number") { + return { t_s }; } throw Error(`expected timestamp at ${renderContext(c)}`); }, }; -export const codecForDuration: Codec<Duration> = { - decode(x: any, c?: Context): Duration { - const d_ms = x.d_ms; - if (typeof d_ms === "string") { - if (d_ms === "forever") { - return { d_ms: "forever" }; +export const codecForDuration: Codec<TalerProtocolDuration> = { + decode(x: any, c?: Context): TalerProtocolDuration { + const d_us = x.d_us; + if (typeof d_us === "string") { + if (d_us === "forever") { + return { d_us: "forever" }; } throw Error(`expected duration at ${renderContext(c)}`); } - if (typeof d_ms === "number") { - return { d_ms }; + if (typeof d_us === "number") { + return { d_us }; } throw Error(`expected duration at ${renderContext(c)}`); }, diff --git a/packages/taler-util/src/transactionsTypes.ts b/packages/taler-util/src/transactionsTypes.ts index e780ca411..bccbc7737 100644 --- a/packages/taler-util/src/transactionsTypes.ts +++ b/packages/taler-util/src/transactionsTypes.ts @@ -24,7 +24,7 @@ /** * Imports. */ -import { Timestamp } from "./time.js"; +import { TalerProtocolTimestamp } from "./time.js"; import { AmountString, Product, @@ -73,7 +73,7 @@ export interface TransactionCommon { type: TransactionType; // main timestamp of the transaction - timestamp: Timestamp; + timestamp: TalerProtocolTimestamp; // true if the transaction is still pending, false otherwise // If a transaction is not longer pending, its timestamp will be updated, diff --git a/packages/taler-util/src/types-test.ts b/packages/taler-util/src/types-test.ts index 6998bb5fb..e8af13119 100644 --- a/packages/taler-util/src/types-test.ts +++ b/packages/taler-util/src/types-test.ts @@ -29,13 +29,13 @@ test("contract terms validation", (t) => { merchant_pub: "12345", merchant: { name: "Foo" }, order_id: "test_order", - pay_deadline: { t_ms: 42 }, - wire_transfer_deadline: { t_ms: 42 }, + pay_deadline: { t_s: 42 }, + wire_transfer_deadline: { t_s: 42 }, merchant_base_url: "https://example.com/pay", products: [], - refund_deadline: { t_ms: 42 }, + refund_deadline: { t_s: 42 }, summary: "hello", - timestamp: { t_ms: 42 }, + timestamp: { t_s: 42 }, wire_method: "test", }; @@ -71,13 +71,13 @@ test("contract terms validation (locations)", (t) => { }, }, order_id: "test_order", - pay_deadline: { t_ms: 42 }, - wire_transfer_deadline: { t_ms: 42 }, + pay_deadline: { t_s: 42 }, + wire_transfer_deadline: { t_s: 42 }, merchant_base_url: "https://example.com/pay", products: [], - refund_deadline: { t_ms: 42 }, + refund_deadline: { t_s: 42 }, summary: "hello", - timestamp: { t_ms: 42 }, + timestamp: { t_s: 42 }, wire_method: "test", delivery_location: { country: "FR", diff --git a/packages/taler-util/src/walletTypes.ts b/packages/taler-util/src/walletTypes.ts index 9a3f1f8f8..3c4fa96c7 100644 --- a/packages/taler-util/src/walletTypes.ts +++ b/packages/taler-util/src/walletTypes.ts @@ -32,7 +32,11 @@ import { codecForAmountJson, codecForAmountString, } from "./amounts.js"; -import { Timestamp, codecForTimestamp } from "./time.js"; +import { + AbsoluteTime, + codecForTimestamp, + TalerProtocolTimestamp, +} from "./time.js"; import { buildCodecForObject, codecForString, @@ -299,7 +303,7 @@ export interface PrepareTipResult { * Time when the tip will expire. After it expired, it can't be picked * up anymore. */ - expirationTimestamp: Timestamp; + expirationTimestamp: TalerProtocolTimestamp; } export const codecForPrepareTipResult = (): Codec<PrepareTipResult> => @@ -460,7 +464,7 @@ export interface TalerErrorDetails { /** * Minimal information needed about a planchet for unblinding a signature. - * + * * Can be a withdrawal/tipping/refresh planchet. */ export interface PlanchetUnblindInfo { @@ -527,8 +531,8 @@ export interface DepositInfo { coinPub: string; coinPriv: string; spendAmount: AmountJson; - timestamp: Timestamp; - refundDeadline: Timestamp; + timestamp: TalerProtocolTimestamp; + refundDeadline: TalerProtocolTimestamp; merchantPub: string; feeDeposit: AmountJson; wireInfoHash: string; |