summaryrefslogtreecommitdiff
path: root/packages/taler-util/src/taler-types.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-util/src/taler-types.ts')
-rw-r--r--packages/taler-util/src/taler-types.ts2417
1 files changed, 2417 insertions, 0 deletions
diff --git a/packages/taler-util/src/taler-types.ts b/packages/taler-util/src/taler-types.ts
new file mode 100644
index 000000000..392e7149c
--- /dev/null
+++ b/packages/taler-util/src/taler-types.ts
@@ -0,0 +1,2417 @@
+/*
+ This file is part of GNU Taler
+ (C) 2019 GNUnet e.V.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ * Type and schema definitions and helpers for the core GNU Taler protocol.
+ *
+ * Even though the rest of the wallet uses camelCase for fields, use snake_case
+ * here, since that's the convention for the Taler JSON+HTTP API.
+ */
+
+/**
+ * Imports.
+ */
+
+import { Amounts, codecForAmountString } from "./amounts.js";
+import {
+ Codec,
+ buildCodecForObject,
+ buildCodecForUnion,
+ codecForAny,
+ codecForBoolean,
+ codecForConstString,
+ codecForList,
+ codecForMap,
+ codecForNumber,
+ codecForString,
+ codecForStringURL,
+ codecOptional,
+} from "./codec.js";
+import { strcmp } from "./helpers.js";
+import {
+ CurrencySpecification,
+ codecForCurrencySpecificiation,
+ codecForEither,
+ codecForProduct,
+} from "./index.js";
+import { Edx25519PublicKeyEnc } from "./taler-crypto.js";
+import {
+ TalerProtocolDuration,
+ TalerProtocolTimestamp,
+ codecForDuration,
+ codecForTimestamp,
+} from "./time.js";
+
+/**
+ * Denomination as found in the /keys response from the exchange.
+ */
+export class ExchangeDenomination {
+ /**
+ * Value of one coin of the denomination.
+ */
+ value: string;
+
+ /**
+ * Public signing key of the denomination.
+ */
+ denom_pub: DenominationPubKey;
+
+ /**
+ * Fee for withdrawing.
+ */
+ fee_withdraw: string;
+
+ /**
+ * Fee for depositing.
+ */
+ fee_deposit: string;
+
+ /**
+ * Fee for refreshing.
+ */
+ fee_refresh: string;
+
+ /**
+ * Fee for refunding.
+ */
+ fee_refund: string;
+
+ /**
+ * Start date from which withdraw is allowed.
+ */
+ stamp_start: TalerProtocolTimestamp;
+
+ /**
+ * End date for withdrawing.
+ */
+ stamp_expire_withdraw: TalerProtocolTimestamp;
+
+ /**
+ * Expiration date after which the exchange can forget about
+ * the currency.
+ */
+ stamp_expire_legal: TalerProtocolTimestamp;
+
+ /**
+ * Date after which the coins of this denomination can't be
+ * deposited anymore.
+ */
+ stamp_expire_deposit: TalerProtocolTimestamp;
+
+ /**
+ * Signature over the denomination information by the exchange's master
+ * signing key.
+ */
+ master_sig: string;
+}
+
+/**
+ * Signature by the auditor that a particular denomination key is audited.
+ */
+export class AuditorDenomSig {
+ /**
+ * Denomination public key's hash.
+ */
+ denom_pub_h: string;
+
+ /**
+ * The signature.
+ */
+ auditor_sig: string;
+}
+
+/**
+ * Auditor information as given by the exchange in /keys.
+ */
+export class ExchangeAuditor {
+ /**
+ * Auditor's public key.
+ */
+ auditor_pub: string;
+
+ /**
+ * Base URL of the auditor.
+ */
+ auditor_url: string;
+
+ /**
+ * List of signatures for denominations by the auditor.
+ */
+ denomination_keys: AuditorDenomSig[];
+}
+
+export type ExchangeWithdrawValue =
+ | ExchangeRsaWithdrawValue
+ | ExchangeCsWithdrawValue;
+
+export interface ExchangeRsaWithdrawValue {
+ cipher: "RSA";
+}
+
+export interface ExchangeCsWithdrawValue {
+ cipher: "CS";
+
+ /**
+ * CSR R0 value
+ */
+ r_pub_0: string;
+
+ /**
+ * CSR R1 value
+ */
+ r_pub_1: string;
+}
+
+export interface RecoupRequest {
+ /**
+ * Hashed denomination public key of the coin we want to get
+ * paid back.
+ */
+ denom_pub_hash: string;
+
+ /**
+ * Signature over the coin public key by the denomination.
+ *
+ * The string variant is for the legacy exchange protocol.
+ */
+ denom_sig: UnblindedSignature;
+
+ /**
+ * Blinding key that was used during withdraw,
+ * used to prove that we were actually withdrawing the coin.
+ */
+ coin_blind_key_secret: string;
+
+ /**
+ * Signature of TALER_RecoupRequestPS created with the coin's private key.
+ */
+ coin_sig: string;
+
+ ewv: ExchangeWithdrawValue;
+}
+
+export interface RecoupRefreshRequest {
+ /**
+ * Hashed enomination public key of the coin we want to get
+ * paid back.
+ */
+ denom_pub_hash: string;
+
+ /**
+ * Signature over the coin public key by the denomination.
+ *
+ * The string variant is for the legacy exchange protocol.
+ */
+ denom_sig: UnblindedSignature;
+
+ /**
+ * Coin's blinding factor.
+ */
+ coin_blind_key_secret: string;
+
+ /**
+ * Signature of TALER_RecoupRefreshRequestPS created with
+ * the coin's private key.
+ */
+ coin_sig: string;
+
+ ewv: ExchangeWithdrawValue;
+}
+
+/**
+ * Response that we get from the exchange for a payback request.
+ */
+export interface RecoupConfirmation {
+ /**
+ * Public key of the reserve that will receive the payback.
+ */
+ reserve_pub?: string;
+
+ /**
+ * Public key of the old coin that will receive the recoup,
+ * provided if refreshed was true.
+ */
+ old_coin_pub?: string;
+}
+
+export type UnblindedSignature = RsaUnblindedSignature;
+
+export interface RsaUnblindedSignature {
+ cipher: DenomKeyType.Rsa;
+ rsa_signature: string;
+}
+
+/**
+ * Deposit permission for a single coin.
+ */
+export interface CoinDepositPermission {
+ /**
+ * Signature by the coin.
+ */
+ coin_sig: string;
+
+ /**
+ * Public key of the coin being spend.
+ */
+ coin_pub: string;
+
+ /**
+ * Signature made by the denomination public key.
+ *
+ * The string variant is for legacy protocol support.
+ */
+
+ ub_sig: UnblindedSignature;
+
+ /**
+ * The denomination public key associated with this coin.
+ */
+ h_denom: string;
+
+ /**
+ * The amount that is subtracted from this coin with this payment.
+ */
+ contribution: string;
+
+ /**
+ * URL of the exchange this coin was withdrawn from.
+ */
+ exchange_url: string;
+
+ minimum_age_sig?: EddsaSignatureString;
+
+ age_commitment?: Edx25519PublicKeyEnc[];
+
+ h_age_commitment?: string;
+}
+
+/**
+ * Information about an exchange as stored inside a
+ * merchant's contract terms.
+ */
+export interface ExchangeHandle {
+ // The exchange's base URL.
+ url: string;
+
+ // Master public key of the exchange.
+ master_pub: EddsaPublicKeyString;
+}
+
+export interface AuditorHandle {
+ /**
+ * Official name of the auditor.
+ */
+ name: string;
+
+ /**
+ * Master public signing key of the auditor.
+ */
+ auditor_pub: EddsaPublicKeyString;
+
+ /**
+ * Base URL of the auditor.
+ */
+ url: string;
+}
+
+// Delivery location, loosely modeled as a subset of
+// ISO20022's PostalAddress25.
+export interface Location {
+ // Nation with its own government.
+ country?: string;
+
+ // Identifies a subdivision of a country such as state, region, county.
+ country_subdivision?: string;
+
+ // Identifies a subdivision within a country sub-division.
+ district?: string;
+
+ // Name of a built-up area, with defined boundaries, and a local government.
+ town?: string;
+
+ // Specific location name within the town.
+ town_location?: string;
+
+ // Identifier consisting of a group of letters and/or numbers that
+ // is added to a postal address to assist the sorting of mail.
+ post_code?: string;
+
+ // Name of a street or thoroughfare.
+ street?: string;
+
+ // Name of the building or house.
+ building_name?: string;
+
+ // Number that identifies the position of a building on a street.
+ building_number?: string;
+
+ // Free-form address lines, should not exceed 7 elements.
+ address_lines?: string[];
+}
+
+export interface MerchantInfo {
+ // The merchant's legal name of business.
+ name: string;
+
+ // Label for a location with the business address of the merchant.
+ email?: string;
+
+ // Label for a location with the business address of the merchant.
+ website?: string;
+
+ // An optional base64-encoded product image.
+ logo?: ImageDataUrl;
+
+ // Label for a location with the business address of the merchant.
+ address?: Location;
+
+ // Label for a location that denotes the jurisdiction for disputes.
+ // Some of the typical fields for a location (such as a street address) may be absent.
+ jurisdiction?: Location;
+}
+
+export interface Tax {
+ // the name of the tax
+ name: string;
+
+ // amount paid in tax
+ tax: AmountString;
+}
+
+export interface Product {
+ // merchant-internal identifier for the product.
+ product_id?: string;
+
+ // Human-readable product description.
+ description: string;
+
+ // Map from IETF BCP 47 language tags to localized descriptions
+ description_i18n?: InternationalizedString;
+
+ // The number of units of the product to deliver to the customer.
+ quantity?: Integer;
+
+ // The unit in which the product is measured (liters, kilograms, packages, etc.)
+ unit?: string;
+
+ // The price of the product; this is the total price for quantity times unit of this product.
+ price?: AmountString;
+
+ // An optional base64-encoded product image
+ image?: ImageDataUrl;
+
+ // a list of taxes paid by the merchant for this product. Can be empty.
+ taxes?: Tax[];
+
+ // time indicating when this product should be delivered
+ delivery_date?: TalerProtocolTimestamp;
+}
+
+export interface InternationalizedString {
+ [lang_tag: string]: string;
+}
+
+/**
+ * Contract terms from a merchant.
+ * FIXME: Add type field!
+ */
+export interface MerchantContractTerms {
+ // The hash of the merchant instance's wire details.
+ h_wire: string;
+
+ // Specifies for how long the wallet should try to get an
+ // automatic refund for the purchase. If this field is
+ // present, the wallet should wait for a few seconds after
+ // the purchase and then automatically attempt to obtain
+ // a refund. The wallet should probe until "delay"
+ // after the payment was successful (i.e. via long polling
+ // or via explicit requests with exponential back-off).
+ //
+ // In particular, if the wallet is offline
+ // at that time, it MUST repeat the request until it gets
+ // one response from the merchant after the delay has expired.
+ // If the refund is granted, the wallet MUST automatically
+ // recover the payment. This is used in case a merchant
+ // knows that it might be unable to satisfy the contract and
+ // desires for the wallet to attempt to get the refund without any
+ // customer interaction. Note that it is NOT an error if the
+ // merchant does not grant a refund.
+ auto_refund?: TalerProtocolDuration;
+
+ // Wire transfer method identifier for the wire method associated with h_wire.
+ // The wallet may only select exchanges via a matching auditor if the
+ // exchange also supports this wire method.
+ // The wire transfer fees must be added based on this wire transfer method.
+ wire_method: string;
+
+ // Human-readable description of the whole purchase.
+ summary: string;
+
+ // Map from IETF BCP 47 language tags to localized summaries.
+ summary_i18n?: InternationalizedString;
+
+ // Unique, free-form identifier for the proposal.
+ // Must be unique within a merchant instance.
+ // For merchants that do not store proposals in their DB
+ // before the customer paid for them, the order_id can be used
+ // by the frontend to restore a proposal from the information
+ // encoded in it (such as a short product identifier and timestamp).
+ order_id: string;
+
+ // Total price for the transaction.
+ // The exchange will subtract deposit fees from that amount
+ // before transferring it to the merchant.
+ amount: string;
+
+ // Nonce generated by the wallet and echoed by the merchant
+ // in this field when the proposal is generated.
+ nonce: string;
+
+ // After this deadline, the merchant won't accept payments for the contract.
+ pay_deadline: TalerProtocolTimestamp;
+
+ // More info about the merchant, see below.
+ merchant: MerchantInfo;
+
+ // Merchant's public key used to sign this proposal; this information
+ // is typically added by the backend. Note that this can be an ephemeral key.
+ merchant_pub: string;
+
+ // Time indicating when the order should be delivered.
+ // May be overwritten by individual products.
+ delivery_date?: TalerProtocolTimestamp;
+
+ // Delivery location for (all!) products.
+ delivery_location?: Location;
+
+ // Exchanges that the merchant accepts even if it does not accept any auditors that audit them.
+ exchanges: ExchangeHandle[];
+
+ // List of products that are part of the purchase (see Product).
+ products?: Product[];
+
+ // After this deadline has passed, no refunds will be accepted.
+ refund_deadline: TalerProtocolTimestamp;
+
+ // Transfer deadline for the exchange. Must be in the
+ // deposit permissions of coins used to pay for this order.
+ wire_transfer_deadline: TalerProtocolTimestamp;
+
+ // Time when this contract was generated.
+ timestamp: TalerProtocolTimestamp;
+
+ // Base URL of the (public!) merchant backend API.
+ // Must be an absolute URL that ends with a slash.
+ merchant_base_url: string;
+
+ // URL that will show that the order was successful after
+ // it has been paid for. Optional, but either fulfillment_url
+ // or fulfillment_message must be specified in every
+ // contract terms.
+ //
+ // If a non-unique fulfillment URL is used, a customer can only
+ // buy the order once and will be redirected to a previous purchase
+ // when trying to buy an order with the same fulfillment URL a second
+ // time. This is useful for digital goods that a customer only needs
+ // to buy once but should be able to repeatedly download.
+ //
+ // For orders where the customer is expected to be able to make
+ // repeated purchases (for equivalent goods), the fulfillment URL
+ // should be made unique for every order. The easiest way to do
+ // this is to include a unique order ID in the fulfillment URL.
+ //
+ // When POSTing to the merchant, the placeholder text "${ORDER_ID}"
+ // is be replaced with the actual order ID (useful if the
+ // order ID is generated server-side and needs to be
+ // in the URL). Note that this placeholder can only be used once.
+ // Front-ends may use other means to generate a unique fulfillment URL.
+ fulfillment_url?: string;
+
+ // URL where the same contract could be ordered again (if
+ // available). Returned also at the public order endpoint
+ // for people other than the actual buyer (hence public,
+ // in case order IDs are guessable).
+ public_reorder_url?: string;
+
+ // Message shown to the customer after paying for the order.
+ // Either fulfillment_url or fulfillment_message must be specified.
+ fulfillment_message?: string;
+
+ // Map from IETF BCP 47 language tags to localized fulfillment
+ // messages.
+ fulfillment_message_i18n?: InternationalizedString;
+
+ // Maximum total deposit fee accepted by the merchant for this contract.
+ // Overrides defaults of the merchant instance.
+ max_fee: string;
+
+ // Extra data that is only interpreted by the merchant frontend.
+ // Useful when the merchant needs to store extra information on a
+ // contract without storing it separately in their database.
+ // Must really be an Object (not a string, integer, float or array).
+ extra?: any;
+
+ // Minimum age the buyer must have (in years). Default is 0.
+ // This value is at least as large as the maximum over all
+ // minimum age requirements of the products in this contract.
+ // It might also be set independent of any product, due to
+ // legal requirements.
+ minimum_age?: Integer;
+}
+
+/**
+ * Refund permission in the format that the merchant gives it to us.
+ */
+export interface MerchantAbortPayRefundDetails {
+ /**
+ * Amount to be refunded.
+ */
+ refund_amount: string;
+
+ /**
+ * Fee for the refund.
+ */
+ refund_fee: string;
+
+ /**
+ * Public key of the coin being refunded.
+ */
+ coin_pub: string;
+
+ /**
+ * Refund transaction ID between merchant and exchange.
+ */
+ rtransaction_id: number;
+
+ /**
+ * Exchange's key used for the signature.
+ */
+ exchange_pub?: string;
+
+ /**
+ * Exchange's signature to confirm the refund.
+ */
+ exchange_sig?: string;
+
+ /**
+ * Error replay from the exchange (if any).
+ */
+ exchange_reply?: any;
+
+ /**
+ * Error code from the exchange (if any).
+ */
+ exchange_code?: number;
+
+ /**
+ * HTTP status code of the exchange's response
+ * to the merchant's refund request.
+ */
+ exchange_http_status: number;
+}
+
+/**
+ * Planchet detail sent to the merchant.
+ */
+export interface TipPlanchetDetail {
+ /**
+ * Hashed denomination public key.
+ */
+ denom_pub_hash: string;
+
+ /**
+ * Coin's blinded public key.
+ */
+ coin_ev: CoinEnvelope;
+}
+
+/**
+ * Request sent to the merchant to pick up a tip.
+ */
+export interface TipPickupRequest {
+ /**
+ * Identifier of the tip.
+ */
+ tip_id: string;
+
+ /**
+ * List of planchets the wallet wants to use for the tip.
+ */
+ planchets: TipPlanchetDetail[];
+}
+
+/**
+ * Reserve signature, defined as separate class to facilitate
+ * schema validation.
+ */
+export interface MerchantBlindSigWrapperV1 {
+ /**
+ * Reserve signature.
+ */
+ blind_sig: string;
+}
+
+/**
+ * Response of the merchant
+ * to the TipPickupRequest.
+ */
+export interface MerchantTipResponseV1 {
+ /**
+ * The order of the signatures matches the planchets list.
+ */
+ blind_sigs: MerchantBlindSigWrapperV1[];
+}
+
+export interface MerchantBlindSigWrapperV2 {
+ blind_sig: BlindedDenominationSignature;
+}
+
+/**
+ * Response of the merchant
+ * to the TipPickupRequest.
+ */
+export interface MerchantTipResponseV2 {
+ /**
+ * The order of the signatures matches the planchets list.
+ */
+ blind_sigs: MerchantBlindSigWrapperV2[];
+}
+
+/**
+ * Element of the payback list that the
+ * exchange gives us in /keys.
+ */
+export class Recoup {
+ /**
+ * The hash of the denomination public key for which the payback is offered.
+ */
+ h_denom_pub: string;
+}
+
+/**
+ * Structure of one exchange signing key in the /keys response.
+ */
+export class ExchangeSignKeyJson {
+ stamp_start: TalerProtocolTimestamp;
+ stamp_expire: TalerProtocolTimestamp;
+ stamp_end: TalerProtocolTimestamp;
+ key: EddsaPublicKeyString;
+ master_sig: EddsaSignatureString;
+}
+
+/**
+ * Structure that the exchange gives us in /keys.
+ */
+export class ExchangeKeysJson {
+ /**
+ * Canonical, public base URL of the exchange.
+ */
+ base_url: string;
+
+ currency: string;
+
+ /**
+ * The exchange's master public key.
+ */
+ master_public_key: string;
+
+ /**
+ * The list of auditors (partially) auditing the exchange.
+ */
+ auditors: ExchangeAuditor[];
+
+ /**
+ * Timestamp when this response was issued.
+ */
+ list_issue_date: TalerProtocolTimestamp;
+
+ /**
+ * List of revoked denominations.
+ */
+ recoup?: Recoup[];
+
+ /**
+ * Short-lived signing keys used to sign online
+ * responses.
+ */
+ signkeys: ExchangeSignKeyJson[];
+
+ /**
+ * Protocol version.
+ */
+ version: string;
+
+ reserve_closing_delay: TalerProtocolDuration;
+
+ global_fees: GlobalFees[];
+
+ accounts: ExchangeWireAccount[];
+
+ wire_fees: { [methodName: string]: WireFeesJson[] };
+
+ denominations: DenomGroup[];
+}
+
+export type DenomGroup =
+ | DenomGroupRsa
+ | DenomGroupCs
+ | DenomGroupRsaAgeRestricted
+ | DenomGroupCsAgeRestricted;
+
+export interface DenomGroupCommon {
+ // How much are coins of this denomination worth?
+ value: AmountString;
+
+ // Fee charged by the exchange for withdrawing a coin of this denomination.
+ fee_withdraw: AmountString;
+
+ // Fee charged by the exchange for depositing a coin of this denomination.
+ fee_deposit: AmountString;
+
+ // Fee charged by the exchange for refreshing a coin of this denomination.
+ fee_refresh: AmountString;
+
+ // Fee charged by the exchange for refunding a coin of this denomination.
+ fee_refund: AmountString;
+
+ // XOR of all the SHA-512 hash values of the denominations' public keys
+ // in this group. Note that for hashing, the binary format of the
+ // public keys is used, and not their base32 encoding.
+ hash: HashCodeString;
+}
+
+export interface DenomCommon {
+ // Signature of TALER_DenominationKeyValidityPS.
+ master_sig: EddsaSignatureString;
+
+ // When does the denomination key become valid?
+ stamp_start: TalerProtocolTimestamp;
+
+ // When is it no longer possible to deposit coins
+ // of this denomination?
+ stamp_expire_withdraw: TalerProtocolTimestamp;
+
+ // Timestamp indicating by when legal disputes relating to these coins must
+ // be settled, as the exchange will afterwards destroy its evidence relating to
+ // transactions involving this coin.
+ stamp_expire_legal: TalerProtocolTimestamp;
+
+ stamp_expire_deposit: TalerProtocolTimestamp;
+
+ // Set to 'true' if the exchange somehow "lost"
+ // the private key. The denomination was not
+ // necessarily revoked, but still cannot be used
+ // to withdraw coins at this time (theoretically,
+ // the private key could be recovered in the
+ // future; coins signed with the private key
+ // remain valid).
+ lost?: boolean;
+}
+
+export type RsaPublicKeySring = string;
+export type AgeMask = number;
+export type ImageDataUrl = string;
+
+/**
+ * 32-byte value representing a point on Curve25519.
+ */
+export type Cs25519Point = string;
+
+export interface DenomGroupRsa extends DenomGroupCommon {
+ cipher: "RSA";
+
+ denoms: ({
+ rsa_pub: RsaPublicKeySring;
+ } & DenomCommon)[];
+}
+
+export interface DenomGroupRsaAgeRestricted extends DenomGroupCommon {
+ cipher: "RSA+age_restricted";
+ age_mask: AgeMask;
+
+ denoms: ({
+ rsa_pub: RsaPublicKeySring;
+ } & DenomCommon)[];
+}
+
+export interface DenomGroupCs extends DenomGroupCommon {
+ cipher: "CS";
+ age_mask: AgeMask;
+
+ denoms: ({
+ cs_pub: Cs25519Point;
+ } & DenomCommon)[];
+}
+
+export interface DenomGroupCsAgeRestricted extends DenomGroupCommon {
+ cipher: "CS+age_restricted";
+ age_mask: AgeMask;
+
+ denoms: ({
+ cs_pub: Cs25519Point;
+ } & DenomCommon)[];
+}
+
+export interface GlobalFees {
+ // What date (inclusive) does these fees go into effect?
+ start_date: TalerProtocolTimestamp;
+
+ // What date (exclusive) does this fees stop going into effect?
+ end_date: TalerProtocolTimestamp;
+
+ // Account history fee, charged when a user wants to
+ // obtain a reserve/account history.
+ history_fee: AmountString;
+
+ // Annual fee charged for having an open account at the
+ // exchange. Charged to the account. If the account
+ // balance is insufficient to cover this fee, the account
+ // is automatically deleted/closed. (Note that the exchange
+ // will keep the account history around for longer for
+ // regulatory reasons.)
+ account_fee: AmountString;
+
+ // Purse fee, charged only if a purse is abandoned
+ // and was not covered by the account limit.
+ purse_fee: AmountString;
+
+ // How long will the exchange preserve the account history?
+ // After an account was deleted/closed, the exchange will
+ // retain the account history for legal reasons until this time.
+ history_expiration: TalerProtocolDuration;
+
+ // Non-negative number of concurrent purses that any
+ // account holder is allowed to create without having
+ // to pay the purse_fee.
+ purse_account_limit: number;
+
+ // How long does an exchange keep a purse around after a purse
+ // has expired (or been successfully merged)? A 'GET' request
+ // for a purse will succeed until the purse expiration time
+ // plus this value.
+ purse_timeout: TalerProtocolDuration;
+
+ // Signature of TALER_GlobalFeesPS.
+ master_sig: string;
+}
+/**
+ * Wire fees as announced by the exchange.
+ */
+export class WireFeesJson {
+ /**
+ * Cost of a wire transfer.
+ */
+ wire_fee: string;
+
+ /**
+ * Cost of clising a reserve.
+ */
+ closing_fee: string;
+
+ /**
+ * Signature made with the exchange's master key.
+ */
+ sig: string;
+
+ /**
+ * Date from which the fee applies.
+ */
+ start_date: TalerProtocolTimestamp;
+
+ /**
+ * Data after which the fee doesn't apply anymore.
+ */
+ end_date: TalerProtocolTimestamp;
+}
+
+/**
+ * Proposal returned from the contract URL.
+ */
+export class Proposal {
+ /**
+ * Contract terms for the propoal.
+ * Raw, un-decoded JSON object.
+ */
+ contract_terms: any;
+
+ /**
+ * Signature over contract, made by the merchant. The public key used for signing
+ * must be contract_terms.merchant_pub.
+ */
+ sig: string;
+}
+
+/**
+ * Response from the internal merchant API.
+ */
+export class CheckPaymentResponse {
+ order_status: string;
+ refunded: boolean | undefined;
+ refunded_amount: string | undefined;
+ contract_terms: any | undefined;
+ taler_pay_uri: string | undefined;
+ contract_url: string | undefined;
+}
+
+/**
+ * Response from the bank.
+ */
+export class WithdrawOperationStatusResponse {
+ status: "selected" | "aborted" | "confirmed" | "pending";
+
+ selection_done: boolean;
+
+ transfer_done: boolean;
+
+ aborted: boolean;
+
+ amount: string;
+
+ sender_wire?: string;
+
+ suggested_exchange?: string;
+
+ confirm_transfer_url?: string;
+
+ wire_types: string[];
+}
+
+/**
+ * Response from the merchant.
+ */
+export class RewardPickupGetResponse {
+ reward_amount: string;
+
+ exchange_url: string;
+
+ next_url?: string;
+
+ expiration: TalerProtocolTimestamp;
+}
+
+export enum DenomKeyType {
+ Rsa = "RSA",
+ ClauseSchnorr = "CS",
+}
+
+export namespace DenomKeyType {
+ export function toIntTag(t: DenomKeyType): number {
+ switch (t) {
+ case DenomKeyType.Rsa:
+ return 1;
+ case DenomKeyType.ClauseSchnorr:
+ return 2;
+ }
+ }
+}
+
+export interface RsaBlindedDenominationSignature {
+ cipher: DenomKeyType.Rsa;
+ blinded_rsa_signature: string;
+}
+
+export interface CSBlindedDenominationSignature {
+ cipher: DenomKeyType.ClauseSchnorr;
+}
+
+export type BlindedDenominationSignature =
+ | RsaBlindedDenominationSignature
+ | CSBlindedDenominationSignature;
+
+export const codecForRsaBlindedDenominationSignature = () =>
+ buildCodecForObject<RsaBlindedDenominationSignature>()
+ .property("cipher", codecForConstString(DenomKeyType.Rsa))
+ .property("blinded_rsa_signature", codecForString())
+ .build("RsaBlindedDenominationSignature");
+
+export const codecForBlindedDenominationSignature = () =>
+ buildCodecForUnion<BlindedDenominationSignature>()
+ .discriminateOn("cipher")
+ .alternative(DenomKeyType.Rsa, codecForRsaBlindedDenominationSignature())
+ .build("BlindedDenominationSignature");
+
+export class ExchangeWithdrawResponse {
+ ev_sig: BlindedDenominationSignature;
+}
+
+export class ExchangeWithdrawBatchResponse {
+ ev_sigs: ExchangeWithdrawResponse[];
+}
+
+export interface MerchantPayResponse {
+ sig: string;
+ pos_confirmation?: string;
+}
+
+export interface ExchangeMeltRequest {
+ coin_pub: CoinPublicKeyString;
+ confirm_sig: EddsaSignatureString;
+ denom_pub_hash: HashCodeString;
+ denom_sig: UnblindedSignature;
+ rc: string;
+ value_with_fee: AmountString;
+ age_commitment_hash?: HashCodeString;
+}
+
+export interface ExchangeMeltResponse {
+ /**
+ * Which of the kappa indices does the client not have to reveal.
+ */
+ noreveal_index: number;
+
+ /**
+ * Signature of TALER_RefreshMeltConfirmationPS whereby the exchange
+ * affirms the successful melt and confirming the noreveal_index
+ */
+ exchange_sig: EddsaSignatureString;
+
+ /*
+ * public EdDSA key of the exchange that was used to generate the signature.
+ * Should match one of the exchange's signing keys from /keys. Again given
+ * explicitly as the client might otherwise be confused by clock skew as to
+ * which signing key was used.
+ */
+ exchange_pub: EddsaPublicKeyString;
+
+ /*
+ * Base URL to use for operations on the refresh context
+ * (so the reveal operation). If not given,
+ * the base URL is the same as the one used for this request.
+ * Can be used if the base URL for /refreshes/ differs from that
+ * for /coins/, i.e. for load balancing. Clients SHOULD
+ * respect the refresh_base_url if provided. Any HTTP server
+ * belonging to an exchange MUST generate a 307 or 308 redirection
+ * to the correct base URL should a client uses the wrong base
+ * URL, or if the base URL has changed since the melt.
+ *
+ * When melting the same coin twice (technically allowed
+ * as the response might have been lost on the network),
+ * the exchange may return different values for the refresh_base_url.
+ */
+ refresh_base_url?: string;
+}
+
+export interface ExchangeRevealItem {
+ ev_sig: BlindedDenominationSignature;
+}
+
+export interface ExchangeRevealResponse {
+ // List of the exchange's blinded RSA signatures on the new coins.
+ ev_sigs: ExchangeRevealItem[];
+}
+
+interface MerchantOrderStatusPaid {
+ // Was the payment refunded (even partially, via refund or abort)?
+ refunded: boolean;
+
+ // Is any amount of the refund still waiting to be picked up (even partially)?
+ refund_pending: boolean;
+
+ // Amount that was refunded in total.
+ refund_amount: AmountString;
+
+ // Amount that already taken by the wallet.
+ refund_taken: AmountString;
+}
+
+interface MerchantOrderRefundResponse {
+ /**
+ * Amount that was refunded in total.
+ */
+ refund_amount: AmountString;
+
+ /**
+ * Successful refunds for this payment, empty array for none.
+ */
+ refunds: MerchantCoinRefundStatus[];
+
+ /**
+ * Public key of the merchant.
+ */
+ merchant_pub: EddsaPublicKeyString;
+}
+
+export type MerchantCoinRefundStatus =
+ | MerchantCoinRefundSuccessStatus
+ | MerchantCoinRefundFailureStatus;
+
+export interface MerchantCoinRefundSuccessStatus {
+ type: "success";
+
+ // HTTP status of the exchange request, 200 (integer) required for refund confirmations.
+ exchange_status: 200;
+
+ // the EdDSA :ref:signature (binary-only) with purpose
+ // TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND using a current signing key of the
+ // exchange affirming the successful refund
+ exchange_sig: EddsaSignatureString;
+
+ // public EdDSA key of the exchange that was used to generate the signature.
+ // Should match one of the exchange's signing keys from /keys. It is given
+ // explicitly as the client might otherwise be confused by clock skew as to
+ // which signing key was used.
+ exchange_pub: EddsaPublicKeyString;
+
+ // Refund transaction ID.
+ rtransaction_id: number;
+
+ // public key of a coin that was refunded
+ coin_pub: EddsaPublicKeyString;
+
+ // Amount that was refunded, including refund fee charged by the exchange
+ // to the customer.
+ refund_amount: AmountString;
+
+ execution_time: TalerProtocolTimestamp;
+}
+
+export interface MerchantCoinRefundFailureStatus {
+ type: "failure";
+
+ // HTTP status of the exchange request, must NOT be 200.
+ exchange_status: number;
+
+ // Taler error code from the exchange reply, if available.
+ exchange_code?: number;
+
+ // If available, HTTP reply from the exchange.
+ exchange_reply?: any;
+
+ // Refund transaction ID.
+ rtransaction_id: number;
+
+ // public key of a coin that was refunded
+ coin_pub: EddsaPublicKeyString;
+
+ // Amount that was refunded, including refund fee charged by the exchange
+ // to the customer.
+ refund_amount: AmountString;
+
+ execution_time: TalerProtocolTimestamp;
+}
+
+export interface MerchantOrderStatusUnpaid {
+ /**
+ * URI that the wallet must process to complete the payment.
+ */
+ taler_pay_uri: string;
+
+ /**
+ * Alternative order ID which was paid for already in the same session.
+ *
+ * Only given if the same product was purchased before in the same session.
+ */
+ already_paid_order_id?: string;
+}
+
+/**
+ * Response body for the following endpoint:
+ *
+ * POST {talerBankIntegrationApi}/withdrawal-operation/{wopid}
+ */
+export interface BankWithdrawalOperationPostResponse {
+ // Current status of the operation
+ // pending: the operation is pending parameters selection (exchange and reserve public key)
+ // selected: the operations has been selected and is pending confirmation
+ // aborted: the operation has been aborted
+ // confirmed: the transfer has been confirmed and registered by the bank
+ status: "selected" | "aborted" | "confirmed" | "pending";
+
+ // URL that the user needs to navigate to in order to
+ // complete some final confirmation (e.g. 2FA).
+ //
+ // Only applicable when status is selected or pending.
+ // It may contain withdrawal operation id
+ confirm_transfer_url?: string;
+
+ // Deprecated field use status instead
+ // The transfer has been confirmed and registered by the bank.
+ // Does not guarantee that the funds have arrived at the exchange already.
+ transfer_done: boolean;
+}
+
+export const codeForBankWithdrawalOperationPostResponse =
+ (): Codec<BankWithdrawalOperationPostResponse> =>
+ buildCodecForObject<BankWithdrawalOperationPostResponse>()
+ .property(
+ "status",
+ codecForEither(
+ codecForConstString("selected"),
+ codecForConstString("confirmed"),
+ codecForConstString("aborted"),
+ codecForConstString("pending"),
+ ),
+ )
+ .property("confirm_transfer_url", codecOptional(codecForString()))
+ .property("transfer_done", codecForBoolean())
+ .build("BankWithdrawalOperationPostResponse");
+
+export type DenominationPubKey = RsaDenominationPubKey | CsDenominationPubKey;
+
+export interface RsaDenominationPubKey {
+ readonly cipher: DenomKeyType.Rsa;
+ readonly rsa_public_key: string;
+ readonly age_mask: number;
+}
+
+export interface CsDenominationPubKey {
+ readonly cipher: DenomKeyType.ClauseSchnorr;
+ readonly age_mask: number;
+ readonly cs_public_key: string;
+}
+
+export namespace DenominationPubKey {
+ export function cmp(
+ p1: DenominationPubKey,
+ p2: DenominationPubKey,
+ ): -1 | 0 | 1 {
+ if (p1.cipher < p2.cipher) {
+ return -1;
+ } else if (p1.cipher > p2.cipher) {
+ return +1;
+ } else if (
+ p1.cipher === DenomKeyType.Rsa &&
+ p2.cipher === DenomKeyType.Rsa
+ ) {
+ if ((p1.age_mask ?? 0) < (p2.age_mask ?? 0)) {
+ return -1;
+ } else if ((p1.age_mask ?? 0) > (p2.age_mask ?? 0)) {
+ return 1;
+ }
+ return strcmp(p1.rsa_public_key, p2.rsa_public_key);
+ } else if (
+ p1.cipher === DenomKeyType.ClauseSchnorr &&
+ p2.cipher === DenomKeyType.ClauseSchnorr
+ ) {
+ if ((p1.age_mask ?? 0) < (p2.age_mask ?? 0)) {
+ return -1;
+ } else if ((p1.age_mask ?? 0) > (p2.age_mask ?? 0)) {
+ return 1;
+ }
+ return strcmp(p1.cs_public_key, p2.cs_public_key);
+ } else {
+ throw Error("unsupported cipher");
+ }
+ }
+}
+
+export const codecForRsaDenominationPubKey = () =>
+ buildCodecForObject<RsaDenominationPubKey>()
+ .property("cipher", codecForConstString(DenomKeyType.Rsa))
+ .property("rsa_public_key", codecForString())
+ .property("age_mask", codecForNumber())
+ .build("DenominationPubKey");
+
+export const codecForCsDenominationPubKey = () =>
+ buildCodecForObject<CsDenominationPubKey>()
+ .property("cipher", codecForConstString(DenomKeyType.ClauseSchnorr))
+ .property("cs_public_key", codecForString())
+ .property("age_mask", codecForNumber())
+ .build("CsDenominationPubKey");
+
+export const codecForDenominationPubKey = () =>
+ buildCodecForUnion<DenominationPubKey>()
+ .discriminateOn("cipher")
+ .alternative(DenomKeyType.Rsa, codecForRsaDenominationPubKey())
+ .alternative(DenomKeyType.ClauseSchnorr, codecForCsDenominationPubKey())
+ .build("DenominationPubKey");
+
+declare const __amount_str: unique symbol;
+export type AmountString = string & { [__amount_str]: true };
+// export type AmountString = string;
+export type Base32String = string;
+export type EddsaSignatureString = string;
+export type EddsaPublicKeyString = string;
+export type EddsaPrivateKeyString = string;
+export type CoinPublicKeyString = string;
+
+export const codecForDenomination = (): Codec<ExchangeDenomination> =>
+ buildCodecForObject<ExchangeDenomination>()
+ .property("value", codecForString())
+ .property("denom_pub", codecForDenominationPubKey())
+ .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 = (): Codec<AuditorDenomSig> =>
+ buildCodecForObject<AuditorDenomSig>()
+ .property("denom_pub_h", codecForString())
+ .property("auditor_sig", codecForString())
+ .build("AuditorDenomSig");
+
+export const codecForAuditor = (): Codec<ExchangeAuditor> =>
+ buildCodecForObject<ExchangeAuditor>()
+ .property("auditor_pub", codecForString())
+ .property("auditor_url", codecForString())
+ .property("denomination_keys", codecForList(codecForAuditorDenomSig()))
+ .build("Auditor");
+
+export const codecForExchangeHandle = (): Codec<ExchangeHandle> =>
+ buildCodecForObject<ExchangeHandle>()
+ .property("master_pub", codecForString())
+ .property("url", codecForString())
+ .build("ExchangeHandle");
+
+export const codecForAuditorHandle = (): Codec<AuditorHandle> =>
+ buildCodecForObject<AuditorHandle>()
+ .property("name", codecForString())
+ .property("auditor_pub", codecForString())
+ .property("url", codecForString())
+ .build("AuditorHandle");
+
+export const codecForLocation = (): Codec<Location> =>
+ buildCodecForObject<Location>()
+ .property("country", codecOptional(codecForString()))
+ .property("country_subdivision", codecOptional(codecForString()))
+ .property("building_name", codecOptional(codecForString()))
+ .property("building_number", codecOptional(codecForString()))
+ .property("district", codecOptional(codecForString()))
+ .property("street", codecOptional(codecForString()))
+ .property("post_code", codecOptional(codecForString()))
+ .property("town", codecOptional(codecForString()))
+ .property("town_location", codecOptional(codecForString()))
+ .property("address_lines", codecOptional(codecForList(codecForString())))
+ .build("Location");
+
+export const codecForMerchantInfo = (): Codec<MerchantInfo> =>
+ buildCodecForObject<MerchantInfo>()
+ .property("name", codecForString())
+ .property("address", codecOptional(codecForLocation()))
+ .property("jurisdiction", codecOptional(codecForLocation()))
+ .build("MerchantInfo");
+
+export const codecForInternationalizedString =
+ (): Codec<InternationalizedString> => codecForMap(codecForString());
+
+export const codecForMerchantContractTerms = (): Codec<MerchantContractTerms> =>
+ buildCodecForObject<MerchantContractTerms>()
+ .property("order_id", codecForString())
+ .property("fulfillment_url", codecOptional(codecForString()))
+ .property("fulfillment_message", codecOptional(codecForString()))
+ .property(
+ "fulfillment_message_i18n",
+ codecOptional(codecForInternationalizedString()),
+ )
+ .property("merchant_base_url", codecForString())
+ .property("h_wire", codecForString())
+ .property("auto_refund", codecOptional(codecForDuration))
+ .property("wire_method", codecForString())
+ .property("summary", codecForString())
+ .property("summary_i18n", codecOptional(codecForInternationalizedString()))
+ .property("nonce", codecForString())
+ .property("amount", codecForAmountString())
+ .property("pay_deadline", codecForTimestamp)
+ .property("refund_deadline", codecForTimestamp)
+ .property("wire_transfer_deadline", codecForTimestamp)
+ .property("timestamp", codecForTimestamp)
+ .property("delivery_location", codecOptional(codecForLocation()))
+ .property("delivery_date", codecOptional(codecForTimestamp))
+ .property("max_fee", codecForAmountString())
+ .property("merchant", codecForMerchantInfo())
+ .property("merchant_pub", codecForString())
+ .property("exchanges", codecForList(codecForExchangeHandle()))
+ .property("products", codecOptional(codecForList(codecForProduct())))
+ .property("extra", codecForAny())
+ .property("minimum_age", codecOptional(codecForNumber()))
+ .build("MerchantContractTerms");
+
+export const codecForPeerContractTerms = (): Codec<PeerContractTerms> =>
+ buildCodecForObject<PeerContractTerms>()
+ .property("summary", codecForString())
+ .property("amount", codecForAmountString())
+ .property("purse_expiration", codecForTimestamp)
+ .build("PeerContractTerms");
+
+export const codecForMerchantRefundPermission =
+ (): Codec<MerchantAbortPayRefundDetails> =>
+ buildCodecForObject<MerchantAbortPayRefundDetails>()
+ .property("refund_amount", codecForAmountString())
+ .property("refund_fee", codecForAmountString())
+ .property("coin_pub", codecForString())
+ .property("rtransaction_id", codecForNumber())
+ .property("exchange_http_status", codecForNumber())
+ .property("exchange_code", codecOptional(codecForNumber()))
+ .property("exchange_reply", codecOptional(codecForAny()))
+ .property("exchange_sig", codecOptional(codecForString()))
+ .property("exchange_pub", codecOptional(codecForString()))
+ .build("MerchantRefundPermission");
+
+export const codecForBlindSigWrapperV2 = (): Codec<MerchantBlindSigWrapperV2> =>
+ buildCodecForObject<MerchantBlindSigWrapperV2>()
+ .property("blind_sig", codecForBlindedDenominationSignature())
+ .build("MerchantBlindSigWrapperV2");
+
+export const codecForMerchantTipResponseV2 = (): Codec<MerchantTipResponseV2> =>
+ buildCodecForObject<MerchantTipResponseV2>()
+ .property("blind_sigs", codecForList(codecForBlindSigWrapperV2()))
+ .build("MerchantTipResponseV2");
+
+export const codecForRecoup = (): Codec<Recoup> =>
+ buildCodecForObject<Recoup>()
+ .property("h_denom_pub", codecForString())
+ .build("Recoup");
+
+export const codecForExchangeSigningKey = (): Codec<ExchangeSignKeyJson> =>
+ buildCodecForObject<ExchangeSignKeyJson>()
+ .property("key", codecForString())
+ .property("master_sig", codecForString())
+ .property("stamp_end", codecForTimestamp)
+ .property("stamp_start", codecForTimestamp)
+ .property("stamp_expire", codecForTimestamp)
+ .build("ExchangeSignKeyJson");
+
+export const codecForGlobalFees = (): Codec<GlobalFees> =>
+ buildCodecForObject<GlobalFees>()
+ .property("start_date", codecForTimestamp)
+ .property("end_date", codecForTimestamp)
+ .property("history_fee", codecForAmountString())
+ .property("account_fee", codecForAmountString())
+ .property("purse_fee", codecForAmountString())
+ .property("history_expiration", codecForDuration)
+ .property("purse_account_limit", codecForNumber())
+ .property("purse_timeout", codecForDuration)
+ .property("master_sig", codecForString())
+ .build("GlobalFees");
+
+// FIXME: Validate properly!
+export const codecForNgDenominations: Codec<DenomGroup> = codecForAny();
+
+export const codecForExchangeKeysJson = (): Codec<ExchangeKeysJson> =>
+ buildCodecForObject<ExchangeKeysJson>()
+ .property("base_url", codecForString())
+ .property("currency", codecForString())
+ .property("master_public_key", codecForString())
+ .property("auditors", codecForList(codecForAuditor()))
+ .property("list_issue_date", codecForTimestamp)
+ .property("recoup", codecOptional(codecForList(codecForRecoup())))
+ .property("signkeys", codecForList(codecForExchangeSigningKey()))
+ .property("version", codecForString())
+ .property("reserve_closing_delay", codecForDuration)
+ .property("global_fees", codecForList(codecForGlobalFees()))
+ .property("accounts", codecForList(codecForExchangeWireAccount()))
+ .property("wire_fees", codecForMap(codecForList(codecForWireFeesJson())))
+ .property("denominations", codecForList(codecForNgDenominations))
+ .build("ExchangeKeysJson");
+
+export const codecForWireFeesJson = (): Codec<WireFeesJson> =>
+ buildCodecForObject<WireFeesJson>()
+ .property("wire_fee", codecForString())
+ .property("closing_fee", codecForString())
+ .property("sig", codecForString())
+ .property("start_date", codecForTimestamp)
+ .property("end_date", codecForTimestamp)
+ .build("WireFeesJson");
+
+export const codecForProposal = (): Codec<Proposal> =>
+ buildCodecForObject<Proposal>()
+ .property("contract_terms", codecForAny())
+ .property("sig", codecForString())
+ .build("Proposal");
+
+export const codecForCheckPaymentResponse = (): Codec<CheckPaymentResponse> =>
+ buildCodecForObject<CheckPaymentResponse>()
+ .property("order_status", codecForString())
+ .property("refunded", codecOptional(codecForBoolean()))
+ .property("refunded_amount", codecOptional(codecForString()))
+ .property("contract_terms", codecOptional(codecForAny()))
+ .property("taler_pay_uri", codecOptional(codecForString()))
+ .property("contract_url", codecOptional(codecForString()))
+ .build("CheckPaymentResponse");
+
+export const codecForWithdrawOperationStatusResponse =
+ (): Codec<WithdrawOperationStatusResponse> =>
+ buildCodecForObject<WithdrawOperationStatusResponse>()
+ .property(
+ "status",
+ codecForEither(
+ codecForConstString("selected"),
+ codecForConstString("confirmed"),
+ codecForConstString("aborted"),
+ codecForConstString("pending"),
+ ),
+ )
+ .property("selection_done", codecForBoolean())
+ .property("transfer_done", codecForBoolean())
+ .property("aborted", codecForBoolean())
+ .property("amount", codecForString())
+ .property("sender_wire", codecOptional(codecForString()))
+ .property("suggested_exchange", codecOptional(codecForString()))
+ .property("confirm_transfer_url", codecOptional(codecForString()))
+ .property("wire_types", codecForList(codecForString()))
+ .build("WithdrawOperationStatusResponse");
+
+export const codecForRewardPickupGetResponse =
+ (): Codec<RewardPickupGetResponse> =>
+ buildCodecForObject<RewardPickupGetResponse>()
+ .property("reward_amount", codecForString())
+ .property("exchange_url", codecForString())
+ .property("next_url", codecOptional(codecForString()))
+ .property("expiration", codecForTimestamp)
+ .build("TipPickupGetResponse");
+
+export const codecForRecoupConfirmation = (): Codec<RecoupConfirmation> =>
+ buildCodecForObject<RecoupConfirmation>()
+ .property("reserve_pub", codecOptional(codecForString()))
+ .property("old_coin_pub", codecOptional(codecForString()))
+ .build("RecoupConfirmation");
+
+export const codecForWithdrawResponse = (): Codec<ExchangeWithdrawResponse> =>
+ buildCodecForObject<ExchangeWithdrawResponse>()
+ .property("ev_sig", codecForBlindedDenominationSignature())
+ .build("WithdrawResponse");
+
+export const codecForExchangeWithdrawBatchResponse =
+ (): Codec<ExchangeWithdrawBatchResponse> =>
+ buildCodecForObject<ExchangeWithdrawBatchResponse>()
+ .property("ev_sigs", codecForList(codecForWithdrawResponse()))
+ .build("WithdrawBatchResponse");
+
+export const codecForMerchantPayResponse = (): Codec<MerchantPayResponse> =>
+ buildCodecForObject<MerchantPayResponse>()
+ .property("sig", codecForString())
+ .property("pos_confirmation", codecOptional(codecForString()))
+ .build("MerchantPayResponse");
+
+export const codecForExchangeMeltResponse = (): Codec<ExchangeMeltResponse> =>
+ buildCodecForObject<ExchangeMeltResponse>()
+ .property("exchange_pub", codecForString())
+ .property("exchange_sig", codecForString())
+ .property("noreveal_index", codecForNumber())
+ .property("refresh_base_url", codecOptional(codecForString()))
+ .build("ExchangeMeltResponse");
+
+export const codecForExchangeRevealItem = (): Codec<ExchangeRevealItem> =>
+ buildCodecForObject<ExchangeRevealItem>()
+ .property("ev_sig", codecForBlindedDenominationSignature())
+ .build("ExchangeRevealItem");
+
+export const codecForExchangeRevealResponse =
+ (): Codec<ExchangeRevealResponse> =>
+ buildCodecForObject<ExchangeRevealResponse>()
+ .property("ev_sigs", codecForList(codecForExchangeRevealItem()))
+ .build("ExchangeRevealResponse");
+
+export const codecForMerchantOrderStatusPaid =
+ (): Codec<MerchantOrderStatusPaid> =>
+ buildCodecForObject<MerchantOrderStatusPaid>()
+ .property("refund_amount", codecForAmountString())
+ .property("refund_taken", codecForAmountString())
+ .property("refund_pending", codecForBoolean())
+ .property("refunded", codecForBoolean())
+ .build("MerchantOrderStatusPaid");
+
+export const codecForMerchantOrderStatusUnpaid =
+ (): Codec<MerchantOrderStatusUnpaid> =>
+ buildCodecForObject<MerchantOrderStatusUnpaid>()
+ .property("taler_pay_uri", codecForString())
+ .property("already_paid_order_id", codecOptional(codecForString()))
+ .build("MerchantOrderStatusUnpaid");
+
+export interface AbortRequest {
+ // hash of the order's contract terms (this is used to authenticate the
+ // wallet/customer in case $ORDER_ID is guessable).
+ h_contract: string;
+
+ // List of coins the wallet would like to see refunds for.
+ // (Should be limited to the coins for which the original
+ // payment succeeded, as far as the wallet knows.)
+ coins: AbortingCoin[];
+}
+
+export interface AbortingCoin {
+ // Public key of a coin for which the wallet is requesting an abort-related refund.
+ coin_pub: EddsaPublicKeyString;
+
+ // The amount to be refunded (matches the original contribution)
+ contribution: AmountString;
+
+ // URL of the exchange this coin was withdrawn from.
+ exchange_url: string;
+}
+
+export interface AbortResponse {
+ // List of refund responses about the coins that the wallet
+ // requested an abort for. In the same order as the 'coins'
+ // from the original request.
+ // The rtransaction_id is implied to be 0.
+ refunds: MerchantAbortPayRefundStatus[];
+}
+
+export type MerchantAbortPayRefundStatus =
+ | MerchantAbortPayRefundSuccessStatus
+ | MerchantAbortPayRefundFailureStatus;
+
+// Details about why a refund failed.
+export interface MerchantAbortPayRefundFailureStatus {
+ // Used as tag for the sum type RefundStatus sum type.
+ type: "failure";
+
+ // HTTP status of the exchange request, must NOT be 200.
+ exchange_status: number;
+
+ // Taler error code from the exchange reply, if available.
+ exchange_code?: number;
+
+ // If available, HTTP reply from the exchange.
+ exchange_reply?: unknown;
+}
+
+// Additional details needed to verify the refund confirmation signature
+// (h_contract_terms and merchant_pub) are already known
+// to the wallet and thus not included.
+export interface MerchantAbortPayRefundSuccessStatus {
+ // Used as tag for the sum type MerchantCoinRefundStatus sum type.
+ type: "success";
+
+ // HTTP status of the exchange request, 200 (integer) required for refund confirmations.
+ exchange_status: 200;
+
+ // the EdDSA :ref:signature (binary-only) with purpose
+ // TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND using a current signing key of the
+ // exchange affirming the successful refund
+ exchange_sig: string;
+
+ // public EdDSA key of the exchange that was used to generate the signature.
+ // Should match one of the exchange's signing keys from /keys. It is given
+ // explicitly as the client might otherwise be confused by clock skew as to
+ // which signing key was used.
+ exchange_pub: string;
+}
+
+export interface FutureKeysResponse {
+ future_denoms: any[];
+
+ future_signkeys: any[];
+
+ master_pub: string;
+
+ denom_secmod_public_key: string;
+
+ // Public key of the signkey security module.
+ signkey_secmod_public_key: string;
+}
+
+export const codecForKeysManagementResponse = (): Codec<FutureKeysResponse> =>
+ buildCodecForObject<FutureKeysResponse>()
+ .property("master_pub", codecForString())
+ .property("future_signkeys", codecForList(codecForAny()))
+ .property("future_denoms", codecForList(codecForAny()))
+ .property("denom_secmod_public_key", codecForAny())
+ .property("signkey_secmod_public_key", codecForAny())
+ .build("FutureKeysResponse");
+
+export interface MerchantConfigResponse {
+ currency: string;
+ name: string;
+ version: string;
+}
+
+export const codecForMerchantConfigResponse =
+ (): Codec<MerchantConfigResponse> =>
+ buildCodecForObject<MerchantConfigResponse>()
+ .property("currency", codecForString())
+ .property("name", codecForString())
+ .property("version", codecForString())
+ .build("MerchantConfigResponse");
+
+export enum ExchangeProtocolVersion {
+ /**
+ * Current version supported by the wallet.
+ */
+ V12 = 12,
+}
+
+export enum MerchantProtocolVersion {
+ /**
+ * Current version supported by the wallet.
+ */
+ V3 = 3,
+}
+
+export type CoinEnvelope = CoinEnvelopeRsa | CoinEnvelopeCs;
+
+export interface CoinEnvelopeRsa {
+ cipher: DenomKeyType.Rsa;
+ rsa_blinded_planchet: string;
+}
+
+export interface CoinEnvelopeCs {
+ cipher: DenomKeyType.ClauseSchnorr;
+ // FIXME: add remaining fields
+}
+
+export type HashCodeString = string;
+
+export interface ExchangeWithdrawRequest {
+ denom_pub_hash: HashCodeString;
+ reserve_sig: EddsaSignatureString;
+ coin_ev: CoinEnvelope;
+}
+
+export interface ExchangeBatchWithdrawRequest {
+ planchets: ExchangeWithdrawRequest[];
+}
+
+export interface ExchangeRefreshRevealRequest {
+ new_denoms_h: HashCodeString[];
+ coin_evs: CoinEnvelope[];
+ /**
+ * kappa - 1 transfer private keys (ephemeral ECDHE keys).
+ */
+ transfer_privs: string[];
+
+ transfer_pub: EddsaPublicKeyString;
+
+ link_sigs: EddsaSignatureString[];
+
+ /**
+ * Iff the corresponding denomination has support for age restriction,
+ * the client MUST provide the original age commitment, i.e. the vector
+ * of public keys.
+ */
+ old_age_commitment?: Edx25519PublicKeyEnc[];
+}
+
+interface DepositConfirmationSignature {
+ // The EdDSA signature of `TALER_DepositConfirmationPS` using a current
+ // `signing key of the exchange <sign-key-priv>` affirming the successful
+ // deposit and that the exchange will transfer the funds after the refund
+ // deadline, or as soon as possible if the refund deadline is zero.
+ exchange_sig: EddsaSignatureString;
+}
+
+export interface BatchDepositSuccess {
+ // Optional base URL of the exchange for looking up wire transfers
+ // associated with this transaction. If not given,
+ // the base URL is the same as the one used for this request.
+ // Can be used if the base URL for ``/transactions/`` differs from that
+ // for ``/coins/``, i.e. for load balancing. Clients SHOULD
+ // respect the ``transaction_base_url`` if provided. Any HTTP server
+ // belonging to an exchange MUST generate a 307 or 308 redirection
+ // to the correct base URL should a client uses the wrong base
+ // URL, or if the base URL has changed since the deposit.
+ transaction_base_url?: string;
+
+ // Timestamp when the deposit was received by the exchange.
+ exchange_timestamp: TalerProtocolTimestamp;
+
+ // `Public EdDSA key of the exchange <sign-key-pub>` that was used to
+ // generate the signature.
+ // Should match one of the exchange's signing keys from ``/keys``. It is given
+ // explicitly as the client might otherwise be confused by clock skew as to
+ // which signing key was used.
+ exchange_pub: EddsaPublicKeyString;
+
+ // Array of deposit confirmation signatures from the exchange
+ // Entries must be in the same order the coins were given
+ // in the batch deposit request.
+ exchange_sig: EddsaSignatureString;
+}
+
+export const codecForBatchDepositSuccess = (): Codec<BatchDepositSuccess> =>
+ buildCodecForObject<BatchDepositSuccess>()
+ .property("exchange_pub", codecForString())
+ .property("exchange_sig", codecForString())
+ .property("exchange_timestamp", codecForTimestamp)
+ .property("transaction_base_url", codecOptional(codecForString()))
+ .build("BatchDepositSuccess");
+
+export interface TrackTransactionWired {
+ // Raw wire transfer identifier of the deposit.
+ wtid: Base32String;
+
+ // When was the wire transfer given to the bank.
+ execution_time: TalerProtocolTimestamp;
+
+ // The contribution of this coin to the total (without fees)
+ coin_contribution: AmountString;
+
+ // Binary-only Signature_ with purpose TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE
+ // over a TALER_ConfirmWirePS
+ // whereby the exchange affirms the successful wire transfer.
+ exchange_sig: EddsaSignatureString;
+
+ // Public EdDSA key of the exchange that was used to generate the signature.
+ // Should match one of the exchange's signing keys from /keys. Again given
+ // explicitly as the client might otherwise be confused by clock skew as to
+ // which signing key was used.
+ exchange_pub: EddsaPublicKeyString;
+}
+
+export const codecForTackTransactionWired = (): Codec<TrackTransactionWired> =>
+ buildCodecForObject<TrackTransactionWired>()
+ .property("wtid", codecForString())
+ .property("execution_time", codecForTimestamp)
+ .property("coin_contribution", codecForAmountString())
+ .property("exchange_sig", codecForString())
+ .property("exchange_pub", codecForString())
+ .build("TackTransactionWired");
+
+interface TrackTransactionAccepted {
+ // Legitimization target that the merchant should
+ // use to check for its KYC status using
+ // the /kyc-check/$REQUIREMENT_ROW/... endpoint.
+ // Optional, not present if the deposit has not
+ // yet been aggregated to the point that a KYC
+ // need has been evaluated.
+ requirement_row?: number;
+
+ // True if the KYC check for the merchant has been
+ // satisfied. False does not mean that KYC
+ // is strictly needed, unless also a
+ // legitimization_uuid is provided.
+ kyc_ok: boolean;
+
+ // Time by which the exchange currently thinks the deposit will be executed.
+ // Actual execution may be later if the KYC check is not satisfied by then.
+ execution_time: TalerProtocolTimestamp;
+}
+
+export const codecForTackTransactionAccepted =
+ (): Codec<TrackTransactionAccepted> =>
+ buildCodecForObject<TrackTransactionAccepted>()
+ .property("requirement_row", codecOptional(codecForNumber()))
+ .property("kyc_ok", codecForBoolean())
+ .property("execution_time", codecForTimestamp)
+ .build("TackTransactionAccepted");
+
+export type TrackTransaction =
+ | ({ type: "accepted" } & TrackTransactionAccepted)
+ | ({ type: "wired" } & TrackTransactionWired);
+
+export interface PurseDeposit {
+ /**
+ * Amount to be deposited, can be a fraction of the
+ * coin's total value.
+ */
+ amount: AmountString;
+
+ /**
+ * Hash of denomination RSA key with which the coin is signed.
+ */
+ denom_pub_hash: HashCodeString;
+
+ /**
+ * Exchange's unblinded RSA signature of the coin.
+ */
+ ub_sig: UnblindedSignature;
+
+ /**
+ * Age commitment for the coin, if the denomination is age-restricted.
+ */
+ age_commitment?: string[];
+
+ /**
+ * Attestation for the minimum age, if the denomination is age-restricted.
+ */
+ attest?: string;
+
+ /**
+ * Signature over TALER_PurseDepositSignaturePS
+ * of purpose TALER_SIGNATURE_WALLET_PURSE_DEPOSIT
+ * made by the customer with the
+ * coin's private key.
+ */
+ coin_sig: EddsaSignatureString;
+
+ /**
+ * Public key of the coin being deposited into the purse.
+ */
+ coin_pub: EddsaPublicKeyString;
+}
+
+export interface ExchangePurseMergeRequest {
+ // payto://-URI of the account the purse is to be merged into.
+ // Must be of the form: 'payto://taler/$EXCHANGE_URL/$RESERVE_PUB'.
+ payto_uri: string;
+
+ // EdDSA signature of the account/reserve affirming the merge
+ // over a TALER_AccountMergeSignaturePS.
+ // Must be of purpose TALER_SIGNATURE_ACCOUNT_MERGE
+ reserve_sig: EddsaSignatureString;
+
+ // EdDSA signature of the purse private key affirming the merge
+ // over a TALER_PurseMergeSignaturePS.
+ // Must be of purpose TALER_SIGNATURE_PURSE_MERGE.
+ merge_sig: EddsaSignatureString;
+
+ // Client-side timestamp of when the merge request was made.
+ merge_timestamp: TalerProtocolTimestamp;
+}
+
+export interface ExchangeGetContractResponse {
+ purse_pub: string;
+ econtract_sig: string;
+ econtract: string;
+}
+
+export const codecForExchangeGetContractResponse =
+ (): Codec<ExchangeGetContractResponse> =>
+ buildCodecForObject<ExchangeGetContractResponse>()
+ .property("purse_pub", codecForString())
+ .property("econtract_sig", codecForString())
+ .property("econtract", codecForString())
+ .build("ExchangeGetContractResponse");
+
+/**
+ * Contract terms between two wallets (as opposed to a merchant and wallet).
+ */
+export interface PeerContractTerms {
+ amount: AmountString;
+ summary: string;
+ purse_expiration: TalerProtocolTimestamp;
+}
+
+export interface EncryptedContract {
+ // Encrypted contract.
+ econtract: string;
+
+ // Signature over the (encrypted) contract.
+ econtract_sig: string;
+
+ // Ephemeral public key for the DH operation to decrypt the encrypted contract.
+ contract_pub: string;
+}
+
+/**
+ * Payload for /reserves/{reserve_pub}/purse
+ * endpoint of the exchange.
+ */
+export interface ExchangeReservePurseRequest {
+ /**
+ * Minimum amount that must be credited to the reserve, that is
+ * the total value of the purse minus the deposit fees.
+ * If the deposit fees are lower, the contribution to the
+ * reserve can be higher!
+ */
+ purse_value: AmountString;
+
+ // Minimum age required for all coins deposited into the purse.
+ min_age: number;
+
+ // Purse fee the reserve owner is willing to pay
+ // for the purse creation. Optional, if not present
+ // the purse is to be created from the purse quota
+ // of the reserve.
+ purse_fee: AmountString;
+
+ // Optional encrypted contract, in case the buyer is
+ // proposing the contract and thus establishing the
+ // purse with the payment.
+ econtract?: EncryptedContract;
+
+ // EdDSA public key used to approve merges of this purse.
+ merge_pub: EddsaPublicKeyString;
+
+ // EdDSA signature of the purse private key affirming the merge
+ // over a TALER_PurseMergeSignaturePS.
+ // Must be of purpose TALER_SIGNATURE_PURSE_MERGE.
+ merge_sig: EddsaSignatureString;
+
+ // EdDSA signature of the account/reserve affirming the merge.
+ // Must be of purpose TALER_SIGNATURE_WALLET_ACCOUNT_MERGE
+ reserve_sig: EddsaSignatureString;
+
+ // Purse public key.
+ purse_pub: EddsaPublicKeyString;
+
+ // EdDSA signature of the purse over
+ // TALER_PurseRequestSignaturePS of
+ // purpose TALER_SIGNATURE_PURSE_REQUEST
+ // confirming that the
+ // above details hold for this purse.
+ purse_sig: EddsaSignatureString;
+
+ // SHA-512 hash of the contact of the purse.
+ h_contract_terms: HashCodeString;
+
+ // Client-side timestamp of when the merge request was made.
+ merge_timestamp: TalerProtocolTimestamp;
+
+ // Indicative time by which the purse should expire
+ // if it has not been paid.
+ purse_expiration: TalerProtocolTimestamp;
+}
+
+export interface ExchangePurseDeposits {
+ // Array of coins to deposit into the purse.
+ deposits: PurseDeposit[];
+}
+
+/**
+ * @deprecated batch deposit should be used.
+ */
+export interface ExchangeDepositRequest {
+ // Amount to be deposited, can be a fraction of the
+ // coin's total value.
+ contribution: AmountString;
+
+ // The merchant's account details.
+ // In case of an auction policy, it refers to the seller.
+ merchant_payto_uri: string;
+
+ // The salt is used to hide the payto_uri from customers
+ // when computing the h_wire of the merchant.
+ wire_salt: string;
+
+ // SHA-512 hash of the contract of the merchant with the customer. Further
+ // details are never disclosed to the exchange.
+ h_contract_terms: HashCodeString;
+
+ // Hash of denomination RSA key with which the coin is signed.
+ denom_pub_hash: HashCodeString;
+
+ // Exchange's unblinded RSA signature of the coin.
+ ub_sig: UnblindedSignature;
+
+ // Timestamp when the contract was finalized.
+ timestamp: TalerProtocolTimestamp;
+
+ // Indicative time by which the exchange undertakes to transfer the funds to
+ // the merchant, in case of successful payment. A wire transfer deadline of 'never'
+ // is not allowed.
+ wire_transfer_deadline: TalerProtocolTimestamp;
+
+ // EdDSA public key of the merchant, so that the client can identify the
+ // merchant for refund requests.
+ //
+ // THIS FIELD WILL BE DEPRECATED, once the refund mechanism becomes a
+ // policy via extension.
+ merchant_pub: EddsaPublicKeyString;
+
+ // Date until which the merchant can issue a refund to the customer via the
+ // exchange, to be omitted if refunds are not allowed.
+ //
+ // THIS FIELD WILL BE DEPRECATED, once the refund mechanism becomes a
+ // policy via extension.
+ refund_deadline?: TalerProtocolTimestamp;
+
+ // CAVEAT: THIS IS WORK IN PROGRESS
+ // (Optional) policy for the deposit.
+ // This might be a refund, auction or escrow policy.
+ //
+ // Note that support for policies is an optional feature of the exchange.
+ // Optional features are so called "extensions" in Taler. The exchange
+ // provides the list of supported extensions, including policies, in the
+ // ExtensionsManifestsResponse response to the /keys endpoint.
+ policy?: any;
+
+ // Signature over TALER_DepositRequestPS, made by the customer with the
+ // coin's private key.
+ coin_sig: EddsaSignatureString;
+
+ h_age_commitment?: string;
+}
+
+export type WireSalt = string;
+
+export interface ExchangeBatchDepositRequest {
+ // The merchant's account details.
+ merchant_payto_uri: string;
+
+ // The salt is used to hide the ``payto_uri`` from customers
+ // when computing the ``h_wire`` of the merchant.
+ wire_salt: WireSalt;
+
+ // SHA-512 hash of the contract of the merchant with the customer. Further
+ // details are never disclosed to the exchange.
+ h_contract_terms: HashCodeString;
+
+ // The list of coins that are going to be deposited with this Request.
+ coins: BatchDepositRequestCoin[];
+
+ // Timestamp when the contract was finalized.
+ timestamp: TalerProtocolTimestamp;
+
+ // Indicative time by which the exchange undertakes to transfer the funds to
+ // the merchant, in case of successful payment. A wire transfer deadline of 'never'
+ // is not allowed.
+ wire_transfer_deadline: TalerProtocolTimestamp;
+
+ // EdDSA `public key of the merchant <merchant-pub>`, so that the client can identify the
+ // merchant for refund requests.
+ merchant_pub: EddsaPublicKeyString;
+
+ // Date until which the merchant can issue a refund to the customer via the
+ // exchange, to be omitted if refunds are not allowed.
+ //
+ // THIS FIELD WILL BE DEPRECATED, once the refund mechanism becomes a
+ // policy via extension.
+ refund_deadline?: TalerProtocolTimestamp;
+
+ // CAVEAT: THIS IS WORK IN PROGRESS
+ // (Optional) policy for the batch-deposit.
+ // This might be a refund, auction or escrow policy.
+ policy?: any;
+}
+
+export interface BatchDepositRequestCoin {
+ // EdDSA public key of the coin being deposited.
+ coin_pub: EddsaPublicKeyString;
+
+ // Hash of denomination RSA key with which the coin is signed.
+ denom_pub_hash: HashCodeString;
+
+ // Exchange's unblinded RSA signature of the coin.
+ ub_sig: UnblindedSignature;
+
+ // Amount to be deposited, can be a fraction of the
+ // coin's total value.
+ contribution: Amounts;
+
+ // Signature over `TALER_DepositRequestPS`, made by the customer with the
+ // `coin's private key <coin-priv>`.
+ coin_sig: EddsaSignatureString;
+
+ h_age_commitment?: string;
+}
+
+export interface WalletKycUuid {
+ // UUID that the wallet should use when initiating
+ // the KYC check.
+ requirement_row: number;
+
+ // Hash of the payto:// account URI for the wallet.
+ h_payto: string;
+}
+
+export const codecForWalletKycUuid = (): Codec<WalletKycUuid> =>
+ buildCodecForObject<WalletKycUuid>()
+ .property("requirement_row", codecForNumber())
+ .property("h_payto", codecForString())
+ .build("WalletKycUuid");
+
+export interface MerchantUsingTemplateDetails {
+ summary?: string;
+ amount?: AmountString;
+}
+
+export interface ExchangeRefundRequest {
+ // Amount to be refunded, can be a fraction of the
+ // coin's total deposit value (including deposit fee);
+ // must be larger than the refund fee.
+ refund_amount: AmountString;
+
+ // SHA-512 hash of the contact of the merchant with the customer.
+ h_contract_terms: HashCodeString;
+
+ // 64-bit transaction id of the refund transaction between merchant and customer.
+ rtransaction_id: number;
+
+ // EdDSA public key of the merchant.
+ merchant_pub: EddsaPublicKeyString;
+
+ // EdDSA signature of the merchant over a
+ // TALER_RefundRequestPS with purpose
+ // TALER_SIGNATURE_MERCHANT_REFUND
+ // affirming the refund.
+ merchant_sig: EddsaPublicKeyString;
+}
+
+export interface ExchangeRefundSuccessResponse {
+ // The EdDSA :ref:signature (binary-only) with purpose
+ // TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND over
+ // a TALER_RecoupRefreshConfirmationPS
+ // using a current signing key of the
+ // exchange affirming the successful refund.
+ exchange_sig: EddsaSignatureString;
+
+ // Public EdDSA key of the exchange that was used to generate the signature.
+ // Should match one of the exchange's signing keys from /keys. It is given
+ // explicitly as the client might otherwise be confused by clock skew as to
+ // which signing key was used.
+ exchange_pub: EddsaPublicKeyString;
+}
+
+export const codecForExchangeRefundSuccessResponse =
+ (): Codec<ExchangeRefundSuccessResponse> =>
+ buildCodecForObject<ExchangeRefundSuccessResponse>()
+ .property("exchange_pub", codecForString())
+ .property("exchange_sig", codecForString())
+ .build("ExchangeRefundSuccessResponse");
+
+export type AccountRestriction =
+ | RegexAccountRestriction
+ | DenyAllAccountRestriction;
+
+export interface DenyAllAccountRestriction {
+ type: "deny";
+}
+
+// Accounts interacting with this type of account
+// restriction must have a payto://-URI matching
+// the given regex.
+export interface RegexAccountRestriction {
+ type: "regex";
+
+ // Regular expression that the payto://-URI of the
+ // partner account must follow. The regular expression
+ // should follow posix-egrep, but without support for character
+ // classes, GNU extensions, back-references or intervals. See
+ // https://www.gnu.org/software/findutils/manual/html_node/find_html/posix_002degrep-regular-expression-syntax.html
+ // for a description of the posix-egrep syntax. Applications
+ // may support regexes with additional features, but exchanges
+ // must not use such regexes.
+ payto_regex: string;
+
+ // Hint for a human to understand the restriction
+ // (that is hopefully easier to comprehend than the regex itself).
+ human_hint: string;
+
+ // Map from IETF BCP 47 language tags to localized
+ // human hints.
+ human_hint_i18n?: InternationalizedString;
+}
+
+export interface ExchangeWireAccount {
+ // payto:// URI identifying the account and wire method
+ payto_uri: string;
+
+ // URI to convert amounts from or to the currency used by
+ // this wire account of the exchange. Missing if no
+ // conversion is applicable.
+ conversion_url?: string;
+
+ // Restrictions that apply to bank accounts that would send
+ // funds to the exchange (crediting this exchange bank account).
+ // Optional, empty array for unrestricted.
+ credit_restrictions: AccountRestriction[];
+
+ // Restrictions that apply to bank accounts that would receive
+ // funds from the exchange (debiting this exchange bank account).
+ // Optional, empty array for unrestricted.
+ debit_restrictions: AccountRestriction[];
+
+ // Signature using the exchange's offline key over
+ // a TALER_MasterWireDetailsPS
+ // with purpose TALER_SIGNATURE_MASTER_WIRE_DETAILS.
+ master_sig: EddsaSignatureString;
+
+ // Display label wallets should use to show this
+ // bank account.
+ // Since protocol **v19**.
+ bank_label?: string;
+ priority?: number;
+}
+
+export const codecForExchangeWireAccount = (): Codec<ExchangeWireAccount> =>
+ buildCodecForObject<ExchangeWireAccount>()
+ .property("conversion_url", codecOptional(codecForStringURL()))
+ .property("credit_restrictions", codecForList(codecForAny()))
+ .property("debit_restrictions", codecForList(codecForAny()))
+ .property("master_sig", codecForString())
+ .property("payto_uri", codecForString())
+ .property("bank_label", codecOptional(codecForString()))
+ .property("priority", codecOptional(codecForNumber()))
+ .build("WireAccount");
+
+export type Integer = number;
+
+export interface BankConversionInfoConfig {
+ // libtool-style representation of the Bank protocol version, see
+ // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
+ // The format is "current:revision:age".
+ version: string;
+
+ // Name of the API.
+ name: "taler-conversion-info";
+
+ regional_currency: string;
+
+ fiat_currency: string;
+
+ // Currency used by this bank.
+ regional_currency_specification: CurrencySpecification;
+
+ // External currency used during conversion.
+ fiat_currency_specification: CurrencySpecification;
+}
+
+export const codecForBankConversionInfoConfig =
+ (): Codec<BankConversionInfoConfig> =>
+ buildCodecForObject<BankConversionInfoConfig>()
+ .property("name", codecForConstString("taler-conversion-info"))
+ .property("version", codecForString())
+ .property("fiat_currency", codecForString())
+ .property("regional_currency", codecForString())
+ .property("fiat_currency_specification", codecForCurrencySpecificiation())
+ .property(
+ "regional_currency_specification",
+ codecForCurrencySpecificiation(),
+ )
+ .build("BankConversionInfoConfig");
+
+export interface DenominationExpiredMessage {
+ // Taler error code. Note that beyond
+ // expiration this message format is also
+ // used if the key is not yet valid, or
+ // has been revoked.
+ code: number;
+
+ // Signature by the exchange over a
+ // TALER_DenominationExpiredAffirmationPS.
+ // Must have purpose TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_EXPIRED.
+ exchange_sig: EddsaSignatureString;
+
+ // Public key of the exchange used to create
+ // the 'exchange_sig.
+ exchange_pub: EddsaPublicKeyString;
+
+ // Hash of the denomination public key that is unknown.
+ h_denom_pub: HashCodeString;
+
+ // When was the signature created.
+ timestamp: TalerProtocolTimestamp;
+
+ // What kind of operation was requested that now
+ // failed?
+ oper: string;
+}
+
+export const codecForDenominationExpiredMessage = () =>
+ buildCodecForObject<DenominationExpiredMessage>()
+ .property("code", codecForNumber())
+ .property("exchange_sig", codecForString())
+ .property("exchange_pub", codecForString())
+ .property("h_denom_pub", codecForString())
+ .property("timestamp", codecForTimestamp)
+ .property("oper", codecForString())
+ .build("DenominationExpiredMessage");
+
+export interface CoinHistoryResponse {
+ // Current balance of the coin.
+ balance: AmountString;
+
+ // Hash of the coin's denomination.
+ h_denom_pub: HashCodeString;
+
+ // Transaction history for the coin.
+ history: any[];
+}
+
+export const codecForCoinHistoryResponse = () =>
+ buildCodecForObject<CoinHistoryResponse>()
+ .property("balance", codecForAmountString())
+ .property("h_denom_pub", codecForString())
+ .property("history", codecForAny())
+ .build("CoinHistoryResponse");