aboutsummaryrefslogtreecommitdiff
path: root/src/types.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/types.ts')
-rw-r--r--src/types.ts554
1 files changed, 554 insertions, 0 deletions
diff --git a/src/types.ts b/src/types.ts
new file mode 100644
index 000000000..39d374069
--- /dev/null
+++ b/src/types.ts
@@ -0,0 +1,554 @@
+/*
+ This file is part of TALER
+ (C) 2015 GNUnet e.V.
+
+ 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.
+
+ 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
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ * Common types that are used by Taler.
+ *
+ * Note most types are defined in wallet.ts, types that
+ * are defined in types.ts are intended to be used by components
+ * that do not depend on the whole wallet implementation (which depends on
+ * emscripten).
+ *
+ * @author Florian Dold
+ */
+
+import { Checkable } from "./checkable";
+
+@Checkable.Class
+export class AmountJson {
+ @Checkable.Number
+ value: number;
+
+ @Checkable.Number
+ fraction: number;
+
+ @Checkable.String
+ currency: string;
+
+ static checked: (obj: any) => AmountJson;
+}
+
+
+export interface SignedAmountJson {
+ amount: AmountJson;
+ isNegative: boolean;
+}
+
+
+export interface ReserveRecord {
+ reserve_pub: string;
+ reserve_priv: string,
+ exchange_base_url: string,
+ created: number,
+ last_query: number | null,
+ /**
+ * Current amount left in the reserve
+ */
+ current_amount: AmountJson | null,
+ /**
+ * Amount requested when the reserve was created.
+ * When a reserve is re-used (rare!) the current_amount can
+ * be higher than the requested_amount
+ */
+ requested_amount: AmountJson,
+
+
+ /**
+ * What's the current amount that sits
+ * in precoins?
+ */
+ precoin_amount: AmountJson;
+
+
+ confirmed: boolean,
+}
+
+
+@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;
+
+ @Checkable.String
+ reservePub: string;
+
+ static checked: (obj: any) => CreateReserveResponse;
+}
+
+
+@Checkable.Class
+export class Denomination {
+ @Checkable.Value(AmountJson)
+ value: AmountJson;
+
+ @Checkable.String
+ denom_pub: string;
+
+ @Checkable.Value(AmountJson)
+ fee_withdraw: AmountJson;
+
+ @Checkable.Value(AmountJson)
+ fee_deposit: AmountJson;
+
+ @Checkable.Value(AmountJson)
+ fee_refresh: AmountJson;
+
+ @Checkable.Value(AmountJson)
+ fee_refund: AmountJson;
+
+ @Checkable.String
+ stamp_start: string;
+
+ @Checkable.String
+ stamp_expire_withdraw: string;
+
+ @Checkable.String
+ stamp_expire_legal: string;
+
+ @Checkable.String
+ stamp_expire_deposit: string;
+
+ @Checkable.String
+ master_sig: string;
+
+ static checked: (obj: any) => Denomination;
+}
+
+
+export interface IExchangeInfo {
+ baseUrl: string;
+ masterPublicKey: string;
+
+ /**
+ * All denominations we ever received from the exchange.
+ * Expired denominations may be garbage collected.
+ */
+ all_denoms: Denomination[];
+
+ /**
+ * Denominations we received with the last update.
+ * Subset of "denoms".
+ */
+ active_denoms: Denomination[];
+
+ /**
+ * Timestamp for last update.
+ */
+ last_update_time: number;
+}
+
+export interface WireInfo {
+ [type: string]: any;
+}
+
+export interface ReserveCreationInfo {
+ exchangeInfo: IExchangeInfo;
+ wireInfo: WireInfo;
+ selectedDenoms: Denomination[];
+ withdrawFee: AmountJson;
+ overhead: AmountJson;
+}
+
+
+/**
+ * A coin that isn't yet signed by an exchange.
+ */
+export interface PreCoin {
+ coinPub: string;
+ coinPriv: string;
+ reservePub: string;
+ denomPub: string;
+ blindingKey: string;
+ withdrawSig: string;
+ coinEv: string;
+ exchangeBaseUrl: string;
+ coinValue: AmountJson;
+}
+
+export interface RefreshPreCoin {
+ publicKey: string;
+ privateKey: string;
+ coinEv: string;
+ blindingKey: string
+}
+
+
+/**
+ * Ongoing refresh
+ */
+export interface RefreshSession {
+ /**
+ * Public key that's being melted in this session.
+ */
+ meltCoinPub: string;
+
+ /**
+ * How much of the coin's value is melted away
+ * with this refresh session?
+ */
+ valueWithFee: AmountJson
+
+ /**
+ * Sum of the value of denominations we want
+ * to withdraw in this session, without fees.
+ */
+ valueOutput: AmountJson;
+
+ /**
+ * Signature to confirm the melting.
+ */
+ confirmSig: string;
+
+ /**
+ * Denominations of the newly requested coins
+ */
+ newDenoms: string[];
+
+
+ preCoinsForGammas: RefreshPreCoin[][];
+
+
+ /**
+ * The transfer keys, kappa of them.
+ */
+ transferPubs: string[];
+
+ transferPrivs: string[];
+
+ /**
+ * The no-reveal-index after we've done the melting.
+ */
+ norevealIndex?: number;
+
+ /**
+ * Hash of the session.
+ */
+ hash: string;
+
+ exchangeBaseUrl: string;
+
+ finished: boolean;
+}
+
+
+export interface CoinPaySig {
+ coin_sig: string;
+ coin_pub: string;
+ ub_sig: string;
+ denom_pub: string;
+ f: AmountJson;
+}
+
+/**
+ * Coin as stored in the "coins" data store
+ * of the wallet database.
+ */
+export interface Coin {
+ /**
+ * Public key of the coin.
+ */
+ coinPub: string;
+
+ /**
+ * Private key to authorize operations on the coin.
+ */
+ coinPriv: string;
+
+ /**
+ * Key used by the exchange used to sign the coin.
+ */
+ denomPub: string;
+
+ /**
+ * Unblinded signature by the exchange.
+ */
+ denomSig: string;
+
+ /**
+ * Amount that's left on the coin.
+ */
+ currentAmount: AmountJson;
+
+ /**
+ * Base URL that identifies the exchange from which we got the
+ * coin.
+ */
+ exchangeBaseUrl: string;
+
+ /**
+ * We have withdrawn the coin, but it's not accepted by the exchange anymore.
+ * We have to tell an auditor and wait for compensation or for the exchange
+ * to fix it.
+ */
+ suspended?: boolean;
+
+ /**
+ * Was the coin revealed in a transaction?
+ */
+ dirty: boolean;
+
+ /**
+ * Is the coin currently involved in a transaction?
+ *
+ * This delays refreshing until the transaction is finished or
+ * aborted.
+ */
+ transactionPending: boolean;
+}
+
+
+@Checkable.Class
+export class ExchangeHandle {
+ @Checkable.String
+ master_pub: string;
+
+ @Checkable.String
+ url: string;
+
+ static checked: (obj: any) => ExchangeHandle;
+}
+
+export interface WalletBalance {
+ [currency: string]: WalletBalanceEntry;
+}
+
+export interface WalletBalanceEntry {
+ available: AmountJson;
+ pendingIncoming: AmountJson;
+ pendingPayment: AmountJson;
+}
+
+
+interface Merchant {
+ /**
+ * label for a location with the business address of the merchant
+ */
+ address: string;
+
+ /**
+ * the merchant's legal name of business
+ */
+ name: string;
+
+ /**
+ * 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: string;
+
+ /**
+ * Instance of the merchant, in case one merchant
+ * represents multiple receivers.
+ */
+ instance?: string;
+}
+
+@Checkable.Class
+export class Contract {
+ @Checkable.String
+ H_wire: string;
+
+ @Checkable.String
+ summary: string;
+
+ @Checkable.Value(AmountJson)
+ amount: AmountJson;
+
+ @Checkable.List(Checkable.AnyObject)
+ auditors: any[];
+
+ /**
+ * DEPRECATED alias for pay_deadline.
+ */
+ @Checkable.Optional(Checkable.String)
+ expiry: string;
+
+ @Checkable.Optional(Checkable.String)
+ pay_deadline: string;
+
+ @Checkable.Any
+ locations: any;
+
+ @Checkable.Value(AmountJson)
+ max_fee: AmountJson;
+
+ @Checkable.Any
+ merchant: any;
+
+ @Checkable.String
+ merchant_pub: string;
+
+ @Checkable.List(Checkable.Value(ExchangeHandle))
+ exchanges: ExchangeHandle[];
+
+ @Checkable.List(Checkable.AnyObject)
+ products: any[];
+
+ @Checkable.String
+ refund_deadline: string;
+
+ @Checkable.String
+ timestamp: string;
+
+ @Checkable.Number
+ transaction_id: number;
+
+ @Checkable.String
+ fulfillment_url: string;
+
+ @Checkable.Optional(Checkable.String)
+ repurchase_correlation_id: string;
+
+ /**
+ * DEPRECATED alias for instance
+ */
+ @Checkable.Optional(Checkable.String)
+ receiver: string;
+
+ @Checkable.Optional(Checkable.String)
+ instance: string;
+
+ static checked: (obj: any) => Contract;
+}
+
+
+export type PayCoinInfo = Array<{ updatedCoin: Coin, sig: CoinPaySig }>;
+
+
+export namespace Amounts {
+ export interface Result {
+ amount: AmountJson;
+ // Was there an over-/underflow?
+ saturated: boolean;
+ }
+
+ export function getMaxAmount(currency: string): AmountJson {
+ return {
+ currency,
+ value: Number.MAX_SAFE_INTEGER,
+ fraction: 2 ** 32,
+ }
+ }
+
+ export function getZero(currency: string): AmountJson {
+ return {
+ currency,
+ value: 0,
+ fraction: 0,
+ }
+ }
+
+ export function add(first: AmountJson, ...rest: AmountJson[]): Result {
+ let currency = first.currency;
+ let value = first.value + Math.floor(first.fraction / 1e6);
+ if (value > Number.MAX_SAFE_INTEGER) {
+ return { amount: getMaxAmount(currency), saturated: true };
+ }
+ let fraction = first.fraction % 1e6;
+ for (let x of rest) {
+ if (x.currency !== currency) {
+ throw Error(`Mismatched currency: ${x.currency} and ${currency}`);
+ }
+
+ value = value + x.value + Math.floor((fraction + x.fraction) / 1e6);
+ fraction = (fraction + x.fraction) % 1e6;
+ if (value > Number.MAX_SAFE_INTEGER) {
+ return { amount: getMaxAmount(currency), saturated: true };
+ }
+ }
+ return { amount: { currency, value, fraction }, saturated: false };
+ }
+
+
+ export function sub(a: AmountJson, ...rest: AmountJson[]): Result {
+ let currency = a.currency;
+ let value = a.value;
+ let fraction = a.fraction;
+
+ for (let b of rest) {
+ if (b.currency !== currency) {
+ throw Error(`Mismatched currency: ${b.currency} and ${currency}`);
+ }
+ if (fraction < b.fraction) {
+ if (value < 1) {
+ return { amount: { currency, value: 0, fraction: 0 }, saturated: true };
+ }
+ value--;
+ fraction += 1e6;
+ }
+ console.assert(fraction >= b.fraction);
+ fraction -= b.fraction;
+ if (value < b.value) {
+ return { amount: { currency, value: 0, fraction: 0 }, saturated: true };
+ }
+ value -= b.value;
+ }
+
+ return { amount: { currency, value, fraction }, saturated: false };
+ }
+
+ export function cmp(a: AmountJson, b: AmountJson): number {
+ if (a.currency !== b.currency) {
+ throw Error(`Mismatched currency: ${a.currency} and ${b.currency}`);
+ }
+ let av = a.value + Math.floor(a.fraction / 1e6);
+ let af = a.fraction % 1e6;
+ let bv = b.value + Math.floor(b.fraction / 1e6);
+ let bf = b.fraction % 1e6;
+ switch (true) {
+ case av < bv:
+ return -1;
+ case av > bv:
+ return 1;
+ case af < bf:
+ return -1;
+ case af > bf:
+ return 1;
+ case af == bf:
+ return 0;
+ default:
+ throw Error("assertion failed");
+ }
+ }
+
+ export function copy(a: AmountJson): AmountJson {
+ return {
+ value: a.value,
+ fraction: a.fraction,
+ currency: a.currency,
+ }
+ }
+
+ export function isNonZero(a: AmountJson) {
+ return a.value > 0 || a.fraction > 0;
+ }
+}
+
+
+export interface CheckRepurchaseResult {
+ isRepurchase: boolean;
+ existingContractHash?: string;
+ existingFulfillmentUrl?: string;
+}
+
+
+export interface Notifier {
+ notify(): void;
+}