diff options
Diffstat (limited to 'src/types')
-rw-r--r-- | src/types/ReserveStatus.ts | 18 | ||||
-rw-r--r-- | src/types/ReserveTransaction.ts | 48 | ||||
-rw-r--r-- | src/types/dbTypes.ts | 132 | ||||
-rw-r--r-- | src/types/history.ts | 3 | ||||
-rw-r--r-- | src/types/pending.ts | 3 | ||||
-rw-r--r-- | src/types/talerTypes.ts | 522 | ||||
-rw-r--r-- | src/types/types-test.ts | 17 | ||||
-rw-r--r-- | src/types/walletTypes.ts | 97 |
8 files changed, 402 insertions, 438 deletions
diff --git a/src/types/ReserveStatus.ts b/src/types/ReserveStatus.ts index d9b5d9496..8ab7225e8 100644 --- a/src/types/ReserveStatus.ts +++ b/src/types/ReserveStatus.ts @@ -29,14 +29,15 @@ import { makeCodecForUnion, makeCodecForList, } from "../util/codec"; -import { runBlock } from "../util/helpers"; import { AmountString } from "./talerTypes"; -import { ReserveTransaction, codecForReserveTransaction } from "./ReserveTransaction"; - +import { + ReserveTransaction, + codecForReserveTransaction, +} from "./ReserveTransaction"; /** * Status of a reserve. - * + * * Schema type for the exchange's response to "/reserve/status". */ export interface ReserveStatus { @@ -51,11 +52,10 @@ export interface ReserveStatus { history: ReserveTransaction[]; } -export const codecForReserveStatus = runBlock(() => ( +export const codecForReserveStatus = () => typecheckedCodec<ReserveStatus>( makeCodecForObject<ReserveStatus>() .property("balance", codecForString) - .property("history", makeCodecForList(codecForReserveTransaction)) - .build("ReserveStatus") - ) -));
\ No newline at end of file + .property("history", makeCodecForList(codecForReserveTransaction())) + .build("ReserveStatus"), + ); diff --git a/src/types/ReserveTransaction.ts b/src/types/ReserveTransaction.ts index 2ec859498..e889f36a8 100644 --- a/src/types/ReserveTransaction.ts +++ b/src/types/ReserveTransaction.ts @@ -28,15 +28,14 @@ import { makeCodecForConstString, makeCodecForUnion, } from "../util/codec"; -import { runBlock } from "../util/helpers"; import { AmountString, Base32String, EddsaSignatureString, - TimestampString, EddsaPublicKeyString, CoinPublicKeyString, } from "./talerTypes"; +import { Timestamp, codecForTimestamp } from "../util/time"; export const enum ReserveTransactionType { Withdraw = "WITHDRAW", @@ -96,7 +95,7 @@ export interface ReserveDepositTransaction { /** * Timestamp of the incoming wire transfer. */ - timestamp: TimestampString; + timestamp: Timestamp; } export interface ReserveClosingTransaction { @@ -137,7 +136,7 @@ export interface ReserveClosingTransaction { /** * Time when the reserve was closed. */ - timestamp: TimestampString; + timestamp: Timestamp; } export interface ReservePaybackTransaction { @@ -173,7 +172,7 @@ export interface ReservePaybackTransaction { /** * Time when the funds were paid back into the reserve. */ - timestamp: TimestampString; + timestamp: Timestamp; /** * Public key of the coin that was paid back. @@ -190,7 +189,7 @@ export type ReserveTransaction = | ReserveClosingTransaction | ReservePaybackTransaction; -export const codecForReserveWithdrawTransaction = runBlock(() => +export const codecForReserveWithdrawTransaction = () => typecheckedCodec<ReserveWithdrawTransaction>( makeCodecForObject<ReserveWithdrawTransaction>() .property("amount", codecForString) @@ -203,22 +202,20 @@ export const codecForReserveWithdrawTransaction = runBlock(() => ) .property("withdraw_fee", codecForString) .build("ReserveWithdrawTransaction"), - ), -); + ); -export const codecForReserveDepositTransaction = runBlock(() => +export const codecForReserveDepositTransaction = () => typecheckedCodec<ReserveDepositTransaction>( makeCodecForObject<ReserveDepositTransaction>() .property("amount", codecForString) .property("sender_account_url", codecForString) - .property("timestamp", codecForString) + .property("timestamp", codecForTimestamp) .property("wire_reference", codecForString) .property("type", makeCodecForConstString(ReserveTransactionType.Deposit)) .build("ReserveDepositTransaction"), - ), -); + ); -export const codecForReserveClosingTransaction = runBlock(() => +export const codecForReserveClosingTransaction = () => typecheckedCodec<ReserveClosingTransaction>( makeCodecForObject<ReserveClosingTransaction>() .property("amount", codecForString) @@ -226,14 +223,13 @@ export const codecForReserveClosingTransaction = runBlock(() => .property("exchange_pub", codecForString) .property("exchange_sig", codecForString) .property("h_wire", codecForString) - .property("timestamp", codecForString) + .property("timestamp", codecForTimestamp) .property("type", makeCodecForConstString(ReserveTransactionType.Closing)) .property("wtid", codecForString) .build("ReserveClosingTransaction"), - ), -); + ); -export const codecForReservePaybackTransaction = runBlock(() => +export const codecForReservePaybackTransaction = () => typecheckedCodec<ReservePaybackTransaction>( makeCodecForObject<ReservePaybackTransaction>() .property("amount", codecForString) @@ -241,33 +237,31 @@ export const codecForReservePaybackTransaction = runBlock(() => .property("exchange_pub", codecForString) .property("exchange_sig", codecForString) .property("receiver_account_details", codecForString) - .property("timestamp", codecForString) + .property("timestamp", codecForTimestamp) .property("type", makeCodecForConstString(ReserveTransactionType.Payback)) .property("wire_transfer", codecForString) .build("ReservePaybackTransaction"), - ), -); + ); -export const codecForReserveTransaction = runBlock(() => +export const codecForReserveTransaction = () => typecheckedCodec<ReserveTransaction>( makeCodecForUnion<ReserveTransaction>() .discriminateOn("type") .alternative( ReserveTransactionType.Withdraw, - codecForReserveWithdrawTransaction, + codecForReserveWithdrawTransaction(), ) .alternative( ReserveTransactionType.Closing, - codecForReserveClosingTransaction, + codecForReserveClosingTransaction(), ) .alternative( ReserveTransactionType.Payback, - codecForReservePaybackTransaction, + codecForReservePaybackTransaction(), ) .alternative( ReserveTransactionType.Deposit, - codecForReserveDepositTransaction, + codecForReserveDepositTransaction(), ) .build<ReserveTransaction>("ReserveTransaction"), - ), -); + ); diff --git a/src/types/dbTypes.ts b/src/types/dbTypes.ts index f8f9880dd..55559ab57 100644 --- a/src/types/dbTypes.ts +++ b/src/types/dbTypes.ts @@ -24,7 +24,6 @@ * Imports. */ import { AmountJson } from "../util/amounts"; -import { Checkable } from "../util/checkable"; import { Auditor, CoinPaySig, @@ -33,17 +32,16 @@ import { MerchantRefundPermission, PayReq, TipResponse, + ExchangeHandle, } from "./talerTypes"; import { Index, Store } from "../util/query"; import { - Timestamp, OperationError, - Duration, - getTimestampNow, RefreshReason, } from "./walletTypes"; import { ReserveTransaction } from "./ReserveTransaction"; +import { Timestamp, Duration, getTimestampNow } from "../util/time"; export enum ReserveRecordStatus { /** @@ -104,6 +102,13 @@ export function updateRetryInfoTimeout( p: RetryPolicy = defaultRetryPolicy, ): void { const now = getTimestampNow(); + if (now.t_ms === "never") { + throw Error("assertion failed"); + } + if (p.backoffDelta.d_ms === "forever") { + r.nextRetry = { t_ms: "never" }; + return; + } const t = now.t_ms + p.backoffDelta.d_ms * Math.pow(p.backoffBase, r.retryCounter); r.nextRetry = { t_ms: t }; @@ -319,86 +324,72 @@ export enum DenominationStatus { /** * Denomination record as stored in the wallet's database. */ -@Checkable.Class() -export class DenominationRecord { +export interface DenominationRecord { /** * Value of one coin of the denomination. */ - @Checkable.Value(() => AmountJson) value: AmountJson; /** * The denomination public key. */ - @Checkable.String() denomPub: string; /** * Hash of the denomination public key. * Stored in the database for faster lookups. */ - @Checkable.String() denomPubHash: string; /** * Fee for withdrawing. */ - @Checkable.Value(() => AmountJson) feeWithdraw: AmountJson; /** * Fee for depositing. */ - @Checkable.Value(() => AmountJson) feeDeposit: AmountJson; /** * Fee for refreshing. */ - @Checkable.Value(() => AmountJson) feeRefresh: AmountJson; /** * Fee for refunding. */ - @Checkable.Value(() => AmountJson) feeRefund: AmountJson; /** * Validity start date of the denomination. */ - @Checkable.Value(() => Timestamp) stampStart: Timestamp; /** * Date after which the currency can't be withdrawn anymore. */ - @Checkable.Value(() => Timestamp) stampExpireWithdraw: Timestamp; /** * Date after the denomination officially doesn't exist anymore. */ - @Checkable.Value(() => Timestamp) stampExpireLegal: Timestamp; /** * Data after which coins of this denomination can't be deposited anymore. */ - @Checkable.Value(() => Timestamp) stampExpireDeposit: Timestamp; /** * Signature by the exchange's master key over the denomination * information. */ - @Checkable.String() masterSig: string; /** * Did we verify the signature on the denomination? */ - @Checkable.Number() status: DenominationStatus; /** @@ -406,20 +397,12 @@ export class DenominationRecord { * we checked? * Only false when the exchange redacts a previously published denomination. */ - @Checkable.Boolean() isOffered: boolean; /** * Base URL of the exchange. */ - @Checkable.String() exchangeBaseUrl: string; - - /** - * Verify that a value matches the schema of this class and convert it into a - * member. - */ - static checked: (obj: any) => Denomination; } /** @@ -713,36 +696,21 @@ export const enum ProposalStatus { REPURCHASE = "repurchase", } -@Checkable.Class() -export class ProposalDownload { +export interface ProposalDownload { /** * The contract that was offered by the merchant. */ - @Checkable.Value(() => ContractTerms) - contractTerms: ContractTerms; + contractTermsRaw: string; - /** - * Signature by the merchant over the contract details. - */ - @Checkable.String() - merchantSig: string; - - /** - * Signature by the merchant over the contract details. - */ - @Checkable.String() - contractTermsHash: string; + contractData: WalletContractData; } /** * Record for a downloaded order, stored in the wallet's database. */ -@Checkable.Class() -export class ProposalRecord { - @Checkable.String() +export interface ProposalRecord { orderId: string; - @Checkable.String() merchantBaseUrl: string; /** @@ -753,38 +721,31 @@ export class ProposalRecord { /** * Unique ID when the order is stored in the wallet DB. */ - @Checkable.String() proposalId: string; /** * Timestamp (in ms) of when the record * was created. */ - @Checkable.Number() timestamp: Timestamp; /** * Private key for the nonce. */ - @Checkable.String() noncePriv: string; /** * Public key for the nonce. */ - @Checkable.String() noncePub: string; - @Checkable.String() proposalStatus: ProposalStatus; - @Checkable.String() repurchaseProposalId: string | undefined; /** * Session ID we got when downloading the contract. */ - @Checkable.Optional(Checkable.String()) downloadSessionId?: string; /** @@ -793,12 +754,6 @@ export class ProposalRecord { */ retryInfo: RetryInfo; - /** - * Verify that a value matches the schema of this class and convert it into a - * member. - */ - static checked: (obj: any) => ProposalRecord; - lastError: OperationError | undefined; } @@ -1120,6 +1075,38 @@ export interface ReserveUpdatedEventRecord { newHistoryTransactions: ReserveTransaction[]; } +export interface AllowedAuditorInfo { + auditorBaseUrl: string; + auditorPub: string; +} + +export interface AllowedExchangeInfo { + exchangeBaseUrl: string; + exchangePub: string; +} + +export interface WalletContractData { + fulfillmentUrl: string; + contractTermsHash: string; + merchantSig: string; + merchantPub: string; + amount: AmountJson; + orderId: string; + merchantBaseUrl: string; + summary: string; + autoRefund: Duration | undefined; + maxWireFee: AmountJson; + wireFeeAmortization: number; + payDeadline: Timestamp; + refundDeadline: Timestamp; + allowedAuditors: AllowedAuditorInfo[]; + allowedExchanges: AllowedExchangeInfo[]; + timestamp: Timestamp; + wireMethod: string; + wireInfoHash: string; + maxDepositFee: AmountJson; +} + /** * Record that stores status information about one purchase, starting from when * the customer accepts a proposal. Includes refund status if applicable. @@ -1132,14 +1119,11 @@ export interface PurchaseRecord { proposalId: string; /** - * Hash of the contract terms. - */ - contractTermsHash: string; - - /** * Contract terms we got from the merchant. */ - contractTerms: ContractTerms; + contractTermsRaw: string; + + contractData: WalletContractData; /** * The payment request, ready to be send to the merchant's @@ -1148,11 +1132,6 @@ export interface PurchaseRecord { payReq: PayReq; /** - * Signature from the merchant over the contract terms. - */ - merchantSig: string; - - /** * Timestamp of the first time that sending a payment to the merchant * for this purchase was successful. */ @@ -1266,12 +1245,9 @@ export interface DepositCoin { * the wallet itself, where the wallet acts as a "merchant" for the customer. */ export interface CoinsReturnRecord { - /** - * Hash of the contract for sending coins to our own bank account. - */ - contractTermsHash: string; + contractTermsRaw: string; - contractTerms: ContractTerms; + contractData: WalletContractData; /** * Private key where corresponding @@ -1446,11 +1422,11 @@ export namespace Stores { fulfillmentUrlIndex = new Index<string, PurchaseRecord>( this, "fulfillmentUrlIndex", - "contractTerms.fulfillment_url", + "contractData.fulfillmentUrl", ); orderIdIndex = new Index<string, PurchaseRecord>(this, "orderIdIndex", [ - "contractTerms.merchant_base_url", - "contractTerms.order_id", + "contractData.merchantBaseUrl", + "contractData.orderId", ]); } diff --git a/src/types/history.ts b/src/types/history.ts index c49afd476..783b55913 100644 --- a/src/types/history.ts +++ b/src/types/history.ts @@ -18,9 +18,10 @@ * Type and schema definitions for the wallet's history. */ -import { Timestamp, RefreshReason } from "./walletTypes"; +import { RefreshReason } from "./walletTypes"; import { ReserveTransaction } from "./ReserveTransaction"; import { WithdrawalSource } from "./dbTypes"; +import { Timestamp } from "../util/time"; /** diff --git a/src/types/pending.ts b/src/types/pending.ts index efb97f536..f3979ac81 100644 --- a/src/types/pending.ts +++ b/src/types/pending.ts @@ -21,8 +21,9 @@ /** * Imports. */ -import { OperationError, Timestamp, Duration } from "./walletTypes"; +import { OperationError } from "./walletTypes"; import { WithdrawalSource, RetryInfo } from "./dbTypes"; +import { Timestamp, Duration } from "../util/time"; export const enum PendingOperationType { Bug = "bug", diff --git a/src/types/talerTypes.ts b/src/types/talerTypes.ts index bb286b648..f8e2b1c64 100644 --- a/src/types/talerTypes.ts +++ b/src/types/talerTypes.ts @@ -26,132 +26,115 @@ /** * Imports. */ -import { Checkable } from "../util/checkable"; -import * as Amounts from "../util/amounts"; - -import { timestampCheck } from "../util/helpers"; +import { + typecheckedCodec, + makeCodecForObject, + codecForString, + makeCodecForList, + makeCodecOptional, + codecForAny, + codecForNumber, + codecForBoolean, + makeCodecForMap, +} from "../util/codec"; +import { Timestamp, codecForTimestamp, Duration, codecForDuration } from "../util/time"; /** * Denomination as found in the /keys response from the exchange. */ -@Checkable.Class() export class Denomination { /** * Value of one coin of the denomination. */ - @Checkable.String(Amounts.check) value: string; /** * Public signing key of the denomination. */ - @Checkable.String() denom_pub: string; /** * Fee for withdrawing. */ - @Checkable.String(Amounts.check) fee_withdraw: string; /** * Fee for depositing. */ - @Checkable.String(Amounts.check) fee_deposit: string; /** * Fee for refreshing. */ - @Checkable.String(Amounts.check) fee_refresh: string; /** * Fee for refunding. */ - @Checkable.String(Amounts.check) fee_refund: string; /** * Start date from which withdraw is allowed. */ - @Checkable.String(timestampCheck) - stamp_start: string; + stamp_start: Timestamp; /** * End date for withdrawing. */ - @Checkable.String(timestampCheck) - stamp_expire_withdraw: string; + stamp_expire_withdraw: Timestamp; /** * Expiration date after which the exchange can forget about * the currency. */ - @Checkable.String(timestampCheck) - stamp_expire_legal: string; + stamp_expire_legal: Timestamp; /** * Date after which the coins of this denomination can't be * deposited anymore. */ - @Checkable.String(timestampCheck) - stamp_expire_deposit: string; + stamp_expire_deposit: Timestamp; /** * Signature over the denomination information by the exchange's master * signing key. */ - @Checkable.String() master_sig: string; - - /** - * Verify that a value matches the schema of this class and convert it into a - * member. - */ - static checked: (obj: any) => Denomination; } /** * Signature by the auditor that a particular denomination key is audited. */ -@Checkable.Class() export class AuditorDenomSig { /** * Denomination public key's hash. */ - @Checkable.String() denom_pub_h: string; /** * The signature. */ - @Checkable.String() auditor_sig: string; } /** * Auditor information as given by the exchange in /keys. */ -@Checkable.Class() export class Auditor { /** * Auditor's public key. */ - @Checkable.String() auditor_pub: string; /** * Base URL of the auditor. */ - @Checkable.String() auditor_url: string; /** * List of signatures for denominations by the auditor. */ - @Checkable.List(Checkable.Value(() => AuditorDenomSig)) denomination_keys: AuditorDenomSig[]; } @@ -190,26 +173,22 @@ export interface PaybackRequest { /** * Response that we get from the exchange for a payback request. */ -@Checkable.Class() -export class PaybackConfirmation { +export class RecoupConfirmation { /** * public key of the reserve that will receive the payback. */ - @Checkable.String() reserve_pub: string; /** * How much will the exchange pay back (needed by wallet in * case coin was partially spent and wallet got restored from backup) */ - @Checkable.String() amount: string; /** * Time by which the exchange received the /payback request. */ - @Checkable.String() - timestamp: string; + timestamp: Timestamp; /** * the EdDSA signature of TALER_PaybackConfirmationPS using a current @@ -218,7 +197,6 @@ export class PaybackConfirmation { * by the date specified (this allows the exchange delaying the transfer * a bit to aggregate additional payback requests into a larger one). */ - @Checkable.String() exchange_sig: string; /** @@ -227,14 +205,7 @@ export class PaybackConfirmation { * explicitly as the client might otherwise be confused by clock skew as to * which signing key was used. */ - @Checkable.String() exchange_pub: string; - - /** - * Verify that a value matches the schema of this class and convert it into a - * member. - */ - static checked: (obj: any) => PaybackConfirmation; } /** @@ -272,183 +243,155 @@ export interface CoinPaySig { * Information about an exchange as stored inside a * merchant's contract terms. */ -@Checkable.Class() export class ExchangeHandle { /** * Master public signing key of the exchange. */ - @Checkable.String() master_pub: string; /** * Base URL of the exchange. */ - @Checkable.String() url: string; +} +export class AuditorHandle { /** - * Verify that a value matches the schema of this class and convert it into a - * member. + * Official name of the auditor. */ - static checked: (obj: any) => ExchangeHandle; + name: string; + + /** + * Master public signing key of the auditor. + */ + master_pub: string; + + /** + * Base URL of the auditor. + */ + url: string; } /** * Contract terms from a merchant. */ -@Checkable.Class({ validate: true }) export class ContractTerms { - static validate(x: ContractTerms) { - if (x.exchanges.length === 0) { - throw Error("no exchanges in contract terms"); - } - } - /** * Hash of the merchant's wire details. */ - @Checkable.String() H_wire: string; /** * Hash of the merchant's wire details. */ - @Checkable.Optional(Checkable.String()) - auto_refund?: string; + auto_refund?: Duration; /** * Wire method the merchant wants to use. */ - @Checkable.String() wire_method: string; /** * Human-readable short summary of the contract. */ - @Checkable.Optional(Checkable.String()) - summary?: string; + summary: string; /** * Nonce used to ensure freshness. */ - @Checkable.Optional(Checkable.String()) - nonce?: string; + nonce: string; /** * Total amount payable. */ - @Checkable.String(Amounts.check) amount: string; /** * Auditors accepted by the merchant. */ - @Checkable.List(Checkable.AnyObject()) - auditors: any[]; + auditors: AuditorHandle[]; /** * Deadline to pay for the contract. */ - @Checkable.Optional(Checkable.String()) - pay_deadline: string; + pay_deadline: Timestamp; /** * Delivery locations. */ - @Checkable.Any() locations: any; /** * Maximum deposit fee covered by the merchant. */ - @Checkable.String(Amounts.check) max_fee: string; /** * Information about the merchant. */ - @Checkable.Any() merchant: any; /** * Public key of the merchant. */ - @Checkable.String() merchant_pub: string; /** * List of accepted exchanges. */ - @Checkable.List(Checkable.Value(() => ExchangeHandle)) exchanges: ExchangeHandle[]; /** * Products that are sold in this contract. */ - @Checkable.List(Checkable.AnyObject()) - products: any[]; + products?: any[]; /** * Deadline for refunds. */ - @Checkable.String(timestampCheck) - refund_deadline: string; + refund_deadline: Timestamp; /** * Deadline for the wire transfer. */ - @Checkable.String() - wire_transfer_deadline: string; + wire_transfer_deadline: Timestamp; /** * Time when the contract was generated by the merchant. */ - @Checkable.String(timestampCheck) - timestamp: string; + timestamp: Timestamp; /** * Order id to uniquely identify the purchase within * one merchant instance. */ - @Checkable.String() order_id: string; /** * Base URL of the merchant's backend. */ - @Checkable.String() merchant_base_url: string; /** * Fulfillment URL to view the product or * delivery status. */ - @Checkable.String() fulfillment_url: string; /** * Share of the wire fee that must be settled with one payment. */ - @Checkable.Optional(Checkable.Number()) wire_fee_amortization?: number; /** * Maximum wire fee that the merchant agrees to pay for. */ - @Checkable.Optional(Checkable.String()) max_wire_fee?: string; /** * Extra data, interpreted by the mechant only. */ - @Checkable.Any() extra: any; - - /** - * Verify that a value matches the schema of this class and convert it into a - * member. - */ - static checked: (obj: any) => ContractTerms; } /** @@ -480,42 +423,31 @@ export interface PayReq { /** * Refund permission in the format that the merchant gives it to us. */ -@Checkable.Class() export class MerchantRefundPermission { /** * Amount to be refunded. */ - @Checkable.String(Amounts.check) refund_amount: string; /** * Fee for the refund. */ - @Checkable.String(Amounts.check) refund_fee: string; /** * Public key of the coin being refunded. */ - @Checkable.String() coin_pub: string; /** * Refund transaction ID between merchant and exchange. */ - @Checkable.Number() rtransaction_id: number; /** * Signature made by the merchant over the refund permission. */ - @Checkable.String() merchant_sig: string; - - /** - * Create a MerchantRefundPermission from untyped JSON. - */ - static checked: (obj: any) => MerchantRefundPermission; } /** @@ -564,31 +496,22 @@ export interface RefundRequest { /** * Response for a refund pickup or a /pay in abort mode. */ -@Checkable.Class() export class MerchantRefundResponse { /** * Public key of the merchant */ - @Checkable.String() merchant_pub: string; /** * Contract terms hash of the contract that * is being refunded. */ - @Checkable.String() h_contract_terms: string; /** * The signed refund permissions, to be sent to the exchange. */ - @Checkable.List(Checkable.Value(() => MerchantRefundPermission)) refund_permissions: MerchantRefundPermission[]; - - /** - * Create a MerchantRefundReponse from untyped JSON. - */ - static checked: (obj: any) => MerchantRefundResponse; } /** @@ -625,306 +548,411 @@ export interface TipPickupRequest { * Reserve signature, defined as separate class to facilitate * schema validation with "@Checkable". */ -@Checkable.Class() export class ReserveSigSingleton { /** * Reserve signature. */ - @Checkable.String() reserve_sig: string; - - /** - * Create a ReserveSigSingleton from untyped JSON. - */ - static checked: (obj: any) => ReserveSigSingleton; } - /** * Response of the merchant * to the TipPickupRequest. */ -@Checkable.Class() export class TipResponse { /** * Public key of the reserve */ - @Checkable.String() reserve_pub: string; /** * The order of the signatures matches the planchets list. */ - @Checkable.List(Checkable.Value(() => ReserveSigSingleton)) reserve_sigs: ReserveSigSingleton[]; - - /** - * Create a TipResponse from untyped JSON. - */ - static checked: (obj: any) => TipResponse; } /** * Element of the payback list that the * exchange gives us in /keys. */ -@Checkable.Class() export class Payback { /** * The hash of the denomination public key for which the payback is offered. */ - @Checkable.String() h_denom_pub: string; } /** * Structure that the exchange gives us in /keys. */ -@Checkable.Class({ extra: true }) -export class KeysJson { +export class ExchangeKeysJson { /** * List of offered denominations. */ - @Checkable.List(Checkable.Value(() => Denomination)) denoms: Denomination[]; /** * The exchange's master public key. */ - @Checkable.String() master_public_key: string; /** * The list of auditors (partially) auditing the exchange. */ - @Checkable.List(Checkable.Value(() => Auditor)) auditors: Auditor[]; /** * Timestamp when this response was issued. */ - @Checkable.String(timestampCheck) - list_issue_date: string; + list_issue_date: Timestamp; /** * List of paybacks for compromised denominations. */ - @Checkable.Optional(Checkable.List(Checkable.Value(() => Payback))) payback?: Payback[]; /** * Short-lived signing keys used to sign online * responses. */ - @Checkable.Any() signkeys: any; /** * Protocol version. */ - @Checkable.Optional(Checkable.String()) - version?: string; - - /** - * Verify that a value matches the schema of this class and convert it into a - * member. - */ - static checked: (obj: any) => KeysJson; + version: string; } /** * Wire fees as anounced by the exchange. */ -@Checkable.Class() export class WireFeesJson { /** * Cost of a wire transfer. */ - @Checkable.String(Amounts.check) wire_fee: string; /** * Cost of clising a reserve. */ - @Checkable.String(Amounts.check) closing_fee: string; /** * Signature made with the exchange's master key. */ - @Checkable.String() sig: string; /** * Date from which the fee applies. */ - @Checkable.String(timestampCheck) - start_date: string; + start_date: Timestamp; /** * Data after which the fee doesn't apply anymore. */ - @Checkable.String(timestampCheck) - end_date: string; - - /** - * Verify that a value matches the schema of this class and convert it into a - * member. - */ - static checked: (obj: any) => WireFeesJson; + end_date: Timestamp; } -@Checkable.Class({ extra: true }) export class AccountInfo { - @Checkable.String() url: string; - - @Checkable.String() master_sig: string; } -@Checkable.Class({ extra: true }) export class ExchangeWireJson { - @Checkable.Map( - Checkable.String(), - Checkable.List(Checkable.Value(() => WireFeesJson)), - ) - fees: { [methodName: string]: WireFeesJson[] }; - - @Checkable.List(Checkable.Value(() => AccountInfo)) accounts: AccountInfo[]; - - static checked: (obj: any) => ExchangeWireJson; + fees: { [methodName: string]: WireFeesJson[] }; } /** - * Wire detail, arbitrary object that must at least - * contain a "type" key. - */ -export type WireDetail = object & { type: string }; - -/** * Proposal returned from the contract URL. */ -@Checkable.Class({ extra: true }) export class Proposal { /** * Contract terms for the propoal. + * Raw, un-decoded JSON object. */ - @Checkable.Value(() => ContractTerms) - contract_terms: ContractTerms; + contract_terms: any; /** * Signature over contract, made by the merchant. The public key used for signing * must be contract_terms.merchant_pub. */ - @Checkable.String() sig: string; - - /** - * Verify that a value matches the schema of this class and convert it into a - * member. - */ - static checked: (obj: any) => Proposal; } /** * Response from the internal merchant API. */ -@Checkable.Class({ extra: true }) export class CheckPaymentResponse { - @Checkable.Boolean() paid: boolean; - - @Checkable.Optional(Checkable.Boolean()) refunded: boolean | undefined; - - @Checkable.Optional(Checkable.String()) refunded_amount: string | undefined; - - @Checkable.Optional(Checkable.Value(() => ContractTerms)) - contract_terms: ContractTerms | undefined; - - @Checkable.Optional(Checkable.String()) + contract_terms: any | undefined; taler_pay_uri: string | undefined; - - @Checkable.Optional(Checkable.String()) contract_url: string | undefined; - - /** - * Verify that a value matches the schema of this class and convert it into a - * member. - */ - static checked: (obj: any) => CheckPaymentResponse; } /** * Response from the bank. */ -@Checkable.Class({ extra: true }) export class WithdrawOperationStatusResponse { - @Checkable.Boolean() selection_done: boolean; - @Checkable.Boolean() transfer_done: boolean; - @Checkable.String() amount: string; - @Checkable.Optional(Checkable.String()) sender_wire?: string; - @Checkable.Optional(Checkable.String()) suggested_exchange?: string; - @Checkable.Optional(Checkable.String()) confirm_transfer_url?: string; - @Checkable.List(Checkable.String()) wire_types: string[]; - - /** - * Verify that a value matches the schema of this class and convert it into a - * member. - */ - static checked: (obj: any) => WithdrawOperationStatusResponse; } /** * Response from the merchant. */ -@Checkable.Class({ extra: true }) export class TipPickupGetResponse { - @Checkable.AnyObject() extra: any; - @Checkable.String() amount: string; - @Checkable.String() amount_left: string; - @Checkable.String() exchange_url: string; - @Checkable.String() - stamp_expire: string; - - @Checkable.String() - stamp_created: string; + stamp_expire: Timestamp; - /** - * Verify that a value matches the schema of this class and convert it into a - * member. - */ - static checked: (obj: any) => TipPickupGetResponse; + stamp_created: Timestamp; } - export type AmountString = string; export type Base32String = string; export type EddsaSignatureString = string; export type EddsaPublicKeyString = string; export type CoinPublicKeyString = string; -export type TimestampString = string;
\ No newline at end of file + +export const codecForDenomination = () => + typecheckedCodec<Denomination>( + makeCodecForObject<Denomination>() + .property("value", codecForString) + .property("denom_pub", codecForString) + .property("fee_withdraw", codecForString) + .property("fee_deposit", codecForString) + .property("fee_refresh", codecForString) + .property("fee_refund", codecForString) + .property("stamp_start", codecForTimestamp) + .property("stamp_expire_withdraw", codecForTimestamp) + .property("stamp_expire_legal", codecForTimestamp) + .property("stamp_expire_deposit", codecForTimestamp) + .property("master_sig", codecForString) + .build("Denomination"), + ); + +export const codecForAuditorDenomSig = () => + typecheckedCodec<AuditorDenomSig>( + makeCodecForObject<AuditorDenomSig>() + .property("denom_pub_h", codecForString) + .property("auditor_sig", codecForString) + .build("AuditorDenomSig"), + ); + +export const codecForAuditor = () => + typecheckedCodec<Auditor>( + makeCodecForObject<Auditor>() + .property("auditor_pub", codecForString) + .property("auditor_url", codecForString) + .property("denomination_keys", makeCodecForList(codecForAuditorDenomSig())) + .build("Auditor"), + ); + +export const codecForExchangeHandle = () => + typecheckedCodec<ExchangeHandle>( + makeCodecForObject<ExchangeHandle>() + .property("master_pub", codecForString) + .property("url", codecForString) + .build("ExchangeHandle"), + ); + +export const codecForAuditorHandle = () => + typecheckedCodec<AuditorHandle>( + makeCodecForObject<AuditorHandle>() + .property("name", codecForString) + .property("master_pub", codecForString) + .property("url", codecForString) + .build("AuditorHandle"), + ); + +export const codecForContractTerms = () => + typecheckedCodec<ContractTerms>( + makeCodecForObject<ContractTerms>() + .property("order_id", codecForString) + .property("fulfillment_url", codecForString) + .property("merchant_base_url", codecForString) + .property("H_wire", codecForString) + .property("auto_refund", makeCodecOptional(codecForDuration)) + .property("wire_method", codecForString) + .property("summary", codecForString) + .property("nonce", codecForString) + .property("amount", codecForString) + .property("auditors", makeCodecForList(codecForAuditorHandle())) + .property("pay_deadline", codecForTimestamp) + .property("refund_deadline", codecForTimestamp) + .property("wire_transfer_deadline", codecForTimestamp) + .property("timestamp", codecForTimestamp) + .property("locations", codecForAny) + .property("max_fee", codecForString) + .property("max_wire_fee", makeCodecOptional(codecForString)) + .property("merchant", codecForAny) + .property("merchant_pub", codecForString) + .property("exchanges", makeCodecForList(codecForExchangeHandle())) + .property("products", makeCodecOptional(makeCodecForList(codecForAny))) + .property("extra", codecForAny) + .build("ContractTerms"), + ); + +export const codecForMerchantRefundPermission = () => + typecheckedCodec<MerchantRefundPermission>( + makeCodecForObject<MerchantRefundPermission>() + .property("refund_amount", codecForString) + .property("refund_fee", codecForString) + .property("coin_pub", codecForString) + .property("rtransaction_id", codecForNumber) + .property("merchant_sig", codecForString) + .build("MerchantRefundPermission"), + ); + +export const codecForMerchantRefundResponse = () => + typecheckedCodec<MerchantRefundResponse>( + makeCodecForObject<MerchantRefundResponse>() + .property("merchant_pub", codecForString) + .property("h_contract_terms", codecForString) + .property( + "refund_permissions", + makeCodecForList(codecForMerchantRefundPermission()), + ) + .build("MerchantRefundResponse"), + ); + +export const codecForReserveSigSingleton = () => + typecheckedCodec<ReserveSigSingleton>( + makeCodecForObject<ReserveSigSingleton>() + .property("reserve_sig", codecForString) + .build("ReserveSigSingleton"), + ); + +export const codecForTipResponse = () => + typecheckedCodec<TipResponse>( + makeCodecForObject<TipResponse>() + .property("reserve_pub", codecForString) + .property("reserve_sigs", makeCodecForList(codecForReserveSigSingleton())) + .build("TipResponse"), + ); + +export const codecForPayback = () => + typecheckedCodec<Payback>( + makeCodecForObject<Payback>() + .property("h_denom_pub", codecForString) + .build("Payback"), + ); + +export const codecForExchangeKeysJson = () => + typecheckedCodec<ExchangeKeysJson>( + makeCodecForObject<ExchangeKeysJson>() + .property("denoms", makeCodecForList(codecForDenomination())) + .property("master_public_key", codecForString) + .property("auditors", makeCodecForList(codecForAuditor())) + .property("list_issue_date", codecForTimestamp) + .property("payback", makeCodecOptional(makeCodecForList(codecForPayback()))) + .property("signkeys", codecForAny) + .property("version", codecForString) + .build("KeysJson"), + ); + + +export const codecForWireFeesJson = () => + typecheckedCodec<WireFeesJson>( + makeCodecForObject<WireFeesJson>() + .property("wire_fee", codecForString) + .property("closing_fee", codecForString) + .property("sig", codecForString) + .property("start_date", codecForTimestamp) + .property("end_date", codecForTimestamp) + .build("WireFeesJson"), + ); + +export const codecForAccountInfo = () => + typecheckedCodec<AccountInfo>( + makeCodecForObject<AccountInfo>() + .property("url", codecForString) + .property("master_sig", codecForString) + .build("AccountInfo"), + ); + +export const codecForExchangeWireJson = () => + typecheckedCodec<ExchangeWireJson>( + makeCodecForObject<ExchangeWireJson>() + .property("accounts", makeCodecForList(codecForAccountInfo())) + .property("fees", makeCodecForMap(makeCodecForList(codecForWireFeesJson()))) + .build("ExchangeWireJson"), + ); + +export const codecForProposal = () => + typecheckedCodec<Proposal>( + makeCodecForObject<Proposal>() + .property("contract_terms", codecForAny) + .property("sig", codecForString) + .build("Proposal"), + ); + +export const codecForCheckPaymentResponse = () => + typecheckedCodec<CheckPaymentResponse>( + makeCodecForObject<CheckPaymentResponse>() + .property("paid", codecForBoolean) + .property("refunded", makeCodecOptional(codecForBoolean)) + .property("refunded_amount", makeCodecOptional(codecForString)) + .property("contract_terms", makeCodecOptional(codecForAny)) + .property("taler_pay_uri", makeCodecOptional(codecForString)) + .property("contract_url", makeCodecOptional(codecForString)) + .build("CheckPaymentResponse"), + ); + + +export const codecForWithdrawOperationStatusResponse = () => + typecheckedCodec<WithdrawOperationStatusResponse>( + makeCodecForObject<WithdrawOperationStatusResponse>() + .property("selection_done", codecForBoolean) + .property("transfer_done", codecForBoolean) + .property("amount",codecForString) + .property("sender_wire", makeCodecOptional(codecForString)) + .property("suggested_exchange", makeCodecOptional(codecForString)) + .property("confirm_transfer_url", makeCodecOptional(codecForString)) + .property("wire_types", makeCodecForList(codecForString)) + .build("WithdrawOperationStatusResponse"), + ); + +export const codecForTipPickupGetResponse = () => + typecheckedCodec<TipPickupGetResponse>( + makeCodecForObject<TipPickupGetResponse>() + .property("extra", codecForAny) + .property("amount", codecForString) + .property("amount_left", codecForString) + .property("exchange_url", codecForString) + .property("stamp_expire", codecForTimestamp) + .property("stamp_created", codecForTimestamp) + .build("TipPickupGetResponse"), + ); + + +export const codecForRecoupConfirmation = () => + typecheckedCodec<RecoupConfirmation>( + makeCodecForObject<RecoupConfirmation>() + .property("reserve_pub", codecForString) + .property("amount", codecForString) + .property("timestamp", codecForTimestamp) + .property("exchange_sig", codecForString) + .property("exchange_pub", codecForString) + .build("RecoupConfirmation"), + ); diff --git a/src/types/types-test.ts b/src/types/types-test.ts index a686fbe38..77ab2c4e4 100644 --- a/src/types/types-test.ts +++ b/src/types/types-test.ts @@ -16,7 +16,7 @@ import test from "ava"; import * as Amounts from "../util/amounts"; -import { ContractTerms } from "./talerTypes"; +import { ContractTerms, codecForContractTerms } from "./talerTypes"; const amt = ( value: number, @@ -130,6 +130,7 @@ test("amount stringification", t => { test("contract terms validation", t => { const c = { + nonce: "123123123", H_wire: "123", amount: "EUR:1.5", auditors: [], @@ -138,23 +139,23 @@ test("contract terms validation", t => { max_fee: "EUR:1.5", merchant_pub: "12345", order_id: "test_order", - pay_deadline: "Date(12346)", - wire_transfer_deadline: "Date(12346)", + pay_deadline: { t_ms: 42 }, + wire_transfer_deadline: { t_ms: 42 }, merchant_base_url: "https://example.com/pay", products: [], - refund_deadline: "Date(12345)", + refund_deadline: { t_ms: 42 }, summary: "hello", - timestamp: "Date(12345)", + timestamp: { t_ms: 42 }, wire_method: "test", }; - ContractTerms.checked(c); + codecForContractTerms().decode(c); const c1 = JSON.parse(JSON.stringify(c)); - c1.exchanges = []; + c1.pay_deadline = "foo"; try { - ContractTerms.checked(c1); + codecForContractTerms().decode(c1); } catch (e) { t.pass(); return; diff --git a/src/types/walletTypes.ts b/src/types/walletTypes.ts index df19d8dc2..223ca4329 100644 --- a/src/types/walletTypes.ts +++ b/src/types/walletTypes.ts @@ -25,8 +25,7 @@ /** * Imports. */ -import { AmountJson } from "../util/amounts"; -import { Checkable } from "../util/checkable"; +import { AmountJson, codecForAmountJson } from "../util/amounts"; import * as LibtoolVersion from "../util/libtoolVersion"; import { CoinRecord, @@ -35,30 +34,23 @@ import { ExchangeWireInfo, } from "./dbTypes"; import { CoinPaySig, ContractTerms } from "./talerTypes"; +import { Timestamp } from "../util/time"; +import { typecheckedCodec, makeCodecForObject, codecForString, makeCodecOptional } from "../util/codec"; /** * Response for the create reserve request to the wallet. */ -@Checkable.Class() export class CreateReserveResponse { /** * Exchange URL where the bank should create the reserve. * The URL is canonicalized in the response. */ - @Checkable.String() exchange: string; /** * Reserve public key of the newly created reserve. */ - @Checkable.String() reservePub: string; - - /** - * Verify that a value matches the schema of this class and convert it into a - * member. - */ - static checked: (obj: any) => CreateReserveResponse; } /** @@ -259,88 +251,83 @@ export interface SenderWireInfos { /** * Request to mark a reserve as confirmed. */ -@Checkable.Class() -export class CreateReserveRequest { +export interface CreateReserveRequest { /** * The initial amount for the reserve. */ - @Checkable.Value(() => AmountJson) amount: AmountJson; /** * Exchange URL where the bank should create the reserve. */ - @Checkable.String() exchange: string; /** * Payto URI that identifies the exchange's account that the funds * for this reserve go into. */ - @Checkable.String() exchangeWire: string; /** * Wire details (as a payto URI) for the bank account that sent the funds to * the exchange. */ - @Checkable.Optional(Checkable.String()) senderWire?: string; /** * URL to fetch the withdraw status from the bank. */ - @Checkable.Optional(Checkable.String()) bankWithdrawStatusUrl?: string; - - /** - * Verify that a value matches the schema of this class and convert it into a - * member. - */ - static checked: (obj: any) => CreateReserveRequest; } +export const codecForCreateReserveRequest = () => + typecheckedCodec<CreateReserveRequest>( + makeCodecForObject<CreateReserveRequest>() + .property("amount", codecForAmountJson()) + .property("exchange", codecForString) + .property("exchangeWire", codecForString) + .property("senderWire", makeCodecOptional(codecForString)) + .property("bankWithdrawStatusUrl", makeCodecOptional(codecForString)) + .build("CreateReserveRequest"), + ); + /** * Request to mark a reserve as confirmed. */ -@Checkable.Class() -export class ConfirmReserveRequest { +export interface ConfirmReserveRequest { /** * Public key of then reserve that should be marked * as confirmed. */ - @Checkable.String() reservePub: string; - - /** - * Verify that a value matches the schema of this class and convert it into a - * member. - */ - static checked: (obj: any) => ConfirmReserveRequest; } + +export const codecForConfirmReserveRequest = () => + typecheckedCodec<ConfirmReserveRequest>( + makeCodecForObject<ConfirmReserveRequest>() + .property("reservePub", codecForString) + .build("ConfirmReserveRequest"), + ); + /** * Wire coins to the user's own bank account. */ -@Checkable.Class() export class ReturnCoinsRequest { /** * The amount to wire. */ - @Checkable.Value(() => AmountJson) amount: AmountJson; /** * The exchange to take the coins from. */ - @Checkable.String() exchange: string; /** * Wire details for the bank account of the customer that will * receive the funds. */ - @Checkable.Any() senderWire?: object; /** @@ -391,8 +378,8 @@ export interface TipStatus { tipId: string; merchantTipId: string; merchantOrigin: string; - expirationTimestamp: number; - timestamp: number; + expirationTimestamp: Timestamp; + timestamp: Timestamp; totalFees: AmountJson; } @@ -418,14 +405,14 @@ export type PreparePayResult = export interface PreparePayResultPaymentPossible { status: "payment-possible"; proposalId: string; - contractTerms: ContractTerms; + contractTermsRaw: string; totalFees: AmountJson; } export interface PreparePayResultInsufficientBalance { status: "insufficient-balance"; proposalId: string; - contractTerms: ContractTerms; + contractTermsRaw: any; } export interface PreparePayResultError { @@ -435,7 +422,7 @@ export interface PreparePayResultError { export interface PreparePayResultPaid { status: "paid"; - contractTerms: ContractTerms; + contractTermsRaw: any; nextUrl: string; } @@ -459,7 +446,7 @@ export interface AcceptWithdrawalResponse { * Details about a purchase, including refund status. */ export interface PurchaseDetails { - contractTerms: ContractTerms; + contractTerms: any; hasRefund: boolean; totalRefundAmount: AmountJson; totalRefundAndRefreshFees: AmountJson; @@ -479,30 +466,6 @@ export interface OperationError { details: any; } -@Checkable.Class() -export class Timestamp { - /** - * Timestamp in milliseconds. - */ - @Checkable.Number() - readonly t_ms: number; - - static checked: (obj: any) => Timestamp; -} - -export interface Duration { - /** - * Duration in milliseconds. - */ - readonly d_ms: number; -} - -export function getTimestampNow(): Timestamp { - return { - t_ms: new Date().getTime(), - }; -} - export interface PlanchetCreationResult { coinPub: string; coinPriv: string; |