gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [taler-wallet-webex] 02/02: fix lint issues and separate me


From: gnunet
Subject: [GNUnet-SVN] [taler-wallet-webex] 02/02: fix lint issues and separate message types into multiple files
Date: Wed, 03 Jan 2018 14:42:50 +0100

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository wallet-webex.

commit fd2cd9c383b07cd681c18137396deae025d98047
Author: Florian Dold <address@hidden>
AuthorDate: Wed Jan 3 14:42:06 2018 +0100

    fix lint issues and separate message types into multiple files
---
 .vscode/settings.json                      |    3 +-
 .vscode/tasks.json                         |   44 +
 gulpfile.js                                |    3 +-
 src/amounts.ts                             |  257 ++++
 src/crypto/cryptoApi-test.ts               |    6 +-
 src/crypto/cryptoApi.ts                    |   19 +-
 src/crypto/cryptoWorker.ts                 |   37 +-
 src/crypto/emscInterface.ts                |    4 +-
 src/dbTypes.ts                             |  811 +++++++++++
 src/helpers.ts                             |    3 +-
 src/query.ts                               |    2 +-
 src/talerTypes.ts                          |  632 +++++++++
 src/types-test.ts                          |   16 +-
 src/types.ts                               | 2048 ----------------------------
 src/wallet-test.ts                         |   18 +-
 src/wallet.ts                              |  130 +-
 src/walletTypes.ts                         |  572 ++++++++
 src/webex/messages.ts                      |   51 +-
 src/webex/notify.ts                        |   14 +-
 src/webex/pages/add-auditor.tsx            |    2 +-
 src/webex/pages/auditors.tsx               |    2 +-
 src/webex/pages/confirm-contract.tsx       |    9 +-
 src/webex/pages/confirm-create-reserve.tsx |   27 +-
 src/webex/pages/payback.tsx                |    2 +-
 src/webex/pages/popup.tsx                  |   11 +-
 src/webex/pages/refund.tsx                 |   21 +-
 src/webex/pages/return-coins.tsx           |    7 +-
 src/webex/pages/tip.tsx                    |   27 +-
 src/webex/pages/tree.tsx                   |    3 +-
 src/webex/renderHtml.tsx                   |   17 +-
 src/webex/wxApi.ts                         |   40 +-
 src/webex/wxBackend.ts                     |   19 +-
 tooling/pogen/dumpTree.ts                  |    6 +-
 tsconfig.json                              |   16 +-
 tslint.json                                |    1 +
 35 files changed, 2628 insertions(+), 2252 deletions(-)

diff --git a/.vscode/settings.json b/.vscode/settings.json
index e17e44c9..565900b9 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,7 +1,7 @@
 // Place your settings in this file to overwrite default and user settings.
 {
     // Use latest language servicesu
-    "typescript.tsdk": "node_modules/typescript/lib",
+    "typescript.tsdk": "./node_modules/typescript/lib",
     // Defines space handling after a comma delimiter
     "typescript.format.insertSpaceAfterCommaDelimiter": true,
     //  Defines space handling after a semicolon in a for statement
@@ -34,5 +34,6 @@
         },
         "**/*.js.map": true
     },
+    "tslint.enable": true,
     "editor.wrappingIndent": "same"
 }
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 00000000..a1415994
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,44 @@
+{
+    // See https://go.microsoft.com/fwlink/?LinkId=733558
+    // for the documentation about the tasks.json format
+    "version": "2.0.0",
+    "tasks": [
+        {
+            "type": "typescript",
+            "tsconfig": "tsconfig.json",
+            "option": "watch",
+            "problemMatcher": [
+                "$tsc-watch"
+            ],
+            "group": "build",
+            "isBackground": true,
+            "promptOnClose": false
+        },
+        {
+            "type": "typescript",
+            "tsconfig": "tsconfig.json",
+            "problemMatcher": [
+                "$tsc"
+            ],
+            "group": "build"
+        },
+        {
+            "label": "tslint",
+            "type": "shell",
+            "command": "make lint",
+            "problemMatcher": {
+                "owner": "tslint",
+                "applyTo": "allDocuments",
+                "fileLocation": "absolute",
+                "severity": "warning",
+                "pattern": "$tslint5"
+            },
+            "group": "build"
+        },
+        {
+            "label": "My Task",
+            "type": "shell",
+            "command": "echo Hello"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/gulpfile.js b/gulpfile.js
index cb385f04..f8e0c90f 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -107,7 +107,7 @@ const tsBaseArgs = {
   experimentalDecorators: true,
   module: "commonjs",
   sourceMap: true,
-  lib: ["ES6", "DOM"],
+  lib: ["es6", "dom"],
   noImplicitReturns: true,
   noFallthroughCasesInSwitch: true,
   strict: true,
@@ -266,6 +266,7 @@ gulp.task("pogen", function (cb) {
  */
 function tsconfig(confBase) {
   let conf = {
+    compileOnSave: true,
     compilerOptions: {},
     files: []
   };
diff --git a/src/amounts.ts b/src/amounts.ts
new file mode 100644
index 00000000..a31bec3d
--- /dev/null
+++ b/src/amounts.ts
@@ -0,0 +1,257 @@
+/*
+ This file is part of TALER
+ (C) 2018 GNUnet e.V. and INRIA
+
+ 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/>
+ */
+
+
+/**
+ * Types and helper functions for dealing with Taler amounts.
+ */
+
+/**
+ * Imports.
+ */
+import { Checkable } from "./checkable";
+
+/**
+ * Number of fractional units that one value unit represents.
+ */
+export const fractionalBase = 1e8;
+
+/**
+ * Non-negative financial amount.  Fractional values are expressed as multiples
+ * of 1e-8.
+ */
address@hidden()
+export class AmountJson {
+  /**
+   * Value, must be an integer.
+   */
+  @Checkable.Number
+  readonly value: number;
+
+  /**
+   * Fraction, must be an integer.  Represent 1/1e8 of a unit.
+   */
+  @Checkable.Number
+  readonly fraction: number;
+
+  /**
+   * Currency of the amount.
+   */
+  @Checkable.String
+  readonly currency: string;
+
+  /**
+   * Verify that a value matches the schema of this class and convert it into a
+   * member.
+   */
+  static checked: (obj: any) => AmountJson;
+}
+
+/**
+ * Result of a possibly overflowing operation.
+ */
+export interface Result {
+  /**
+   * Resulting, possibly saturated amount.
+   */
+  amount: AmountJson;
+  /**
+   * Was there an over-/underflow?
+   */
+  saturated: boolean;
+}
+
+/**
+ * Get the largest amount that is safely representable.
+ */
+export function getMaxAmount(currency: string): AmountJson {
+  return {
+    currency,
+    fraction: 2 ** 32,
+    value: Number.MAX_SAFE_INTEGER,
+  };
+}
+
+/**
+ * Get an amount that represents zero units of a currency.
+ */
+export function getZero(currency: string): AmountJson {
+  return {
+    currency,
+    fraction: 0,
+    value: 0,
+  };
+}
+
+/**
+ * Add two amounts.  Return the result and whether
+ * the addition overflowed.  The overflow is always handled
+ * by saturating and never by wrapping.
+ *
+ * Throws when currencies don't match.
+ */
+export function add(first: AmountJson, ...rest: AmountJson[]): Result {
+  const currency = first.currency;
+  let value = first.value + Math.floor(first.fraction / fractionalBase);
+  if (value > Number.MAX_SAFE_INTEGER) {
+    return { amount: getMaxAmount(currency), saturated: true };
+  }
+  let fraction = first.fraction % fractionalBase;
+  for (const x of rest) {
+    if (x.currency !== currency) {
+      throw Error(`Mismatched currency: ${x.currency} and ${currency}`);
+    }
+
+    value = value + x.value + Math.floor((fraction + x.fraction) / 
fractionalBase);
+    fraction = Math.floor((fraction + x.fraction) % fractionalBase);
+    if (value > Number.MAX_SAFE_INTEGER) {
+      return { amount: getMaxAmount(currency), saturated: true };
+    }
+  }
+  return { amount: { currency, value, fraction }, saturated: false };
+}
+
+/**
+ * Subtract two amounts.  Return the result and whether
+ * the subtraction overflowed.  The overflow is always handled
+ * by saturating and never by wrapping.
+ *
+ * Throws when currencies don't match.
+ */
+export function sub(a: AmountJson, ...rest: AmountJson[]): Result {
+  const currency = a.currency;
+  let value = a.value;
+  let fraction = a.fraction;
+
+  for (const 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 += fractionalBase;
+    }
+    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 };
+}
+
+/**
+ * Compare two amounts.  Returns 0 when equal, -1 when a < b
+ * and +1 when a > b.  Throws when currencies don't match.
+ */
+export function cmp(a: AmountJson, b: AmountJson): number {
+  if (a.currency !== b.currency) {
+    throw Error(`Mismatched currency: ${a.currency} and ${b.currency}`);
+  }
+  const av = a.value + Math.floor(a.fraction / fractionalBase);
+  const af = a.fraction % fractionalBase;
+  const bv = b.value + Math.floor(b.fraction / fractionalBase);
+  const bf = b.fraction % fractionalBase;
+  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");
+  }
+}
+
+/**
+ * Create a copy of an amount.
+ */
+export function copy(a: AmountJson): AmountJson {
+  return {
+    currency: a.currency,
+    fraction: a.fraction,
+    value: a.value,
+  };
+}
+
+/**
+ * Divide an amount.  Throws on division by zero.
+ */
+export function divide(a: AmountJson, n: number): AmountJson {
+  if (n === 0) {
+    throw Error(`Division by 0`);
+  }
+  if (n === 1) {
+    return {value: a.value, fraction: a.fraction, currency: a.currency};
+  }
+  const r = a.value % n;
+  return {
+    currency: a.currency,
+    fraction: Math.floor(((r * fractionalBase) + a.fraction) / n),
+    value: Math.floor(a.value / n),
+  };
+}
+
+/**
+ * Check if an amount is non-zero.
+ */
+export function isNonZero(a: AmountJson): boolean {
+  return a.value > 0 || a.fraction > 0;
+}
+
+/**
+ * Parse an amount like 'EUR:20.5' for 20 Euros and 50 ct.
+ */
+export function parse(s: string): AmountJson|undefined {
+  const res = s.match(/([a-zA-Z0-9_*-]+):([0-9])+([.][0-9]+)?/);
+  if (!res) {
+    return undefined;
+  }
+  return {
+    currency: res[1],
+    fraction: Math.round(fractionalBase * Number.parseFloat(res[3] || "0")),
+    value: Number.parseInt(res[2]),
+  };
+}
+
+/**
+ * Convert the amount to a float.
+ */
+export function toFloat(a: AmountJson): number {
+  return a.value + (a.fraction / fractionalBase);
+}
+
+/**
+ * Convert a float to a Taler amount.
+ * Loss of precision possible.
+ */
+export function fromFloat(floatVal: number, currency: string) {
+  return {
+    currency,
+    fraction: Math.floor((floatVal - Math.floor(floatVal)) * fractionalBase),
+    value: Math.floor(floatVal),
+  };
+}
diff --git a/src/crypto/cryptoApi-test.ts b/src/crypto/cryptoApi-test.ts
index d96d69e4..88099e3e 100644
--- a/src/crypto/cryptoApi-test.ts
+++ b/src/crypto/cryptoApi-test.ts
@@ -16,15 +16,15 @@
 
 // tslint:disable:max-line-length
 
-import {test} from "ava";
+import { test } from "ava";
 
 import {
   DenominationRecord,
   DenominationStatus,
   ReserveRecord,
-} from "../types";
+} from "../dbTypes";
 
-import {CryptoApi} from "./cryptoApi";
+import { CryptoApi } from "./cryptoApi";
 
 const masterPub1: string = 
"CQQZ9DY3MZ1ARMN5K1VKDETS04Y2QCKMMCFHZSWJWWVN82BTTH00";
 
diff --git a/src/crypto/cryptoApi.ts b/src/crypto/cryptoApi.ts
index 12b1c970..1f45ba8e 100644
--- a/src/crypto/cryptoApi.ts
+++ b/src/crypto/cryptoApi.ts
@@ -23,20 +23,27 @@
 /**
  * Imports.
  */
+import { AmountJson } from "../amounts";
+
 import {
-  AmountJson,
   CoinRecord,
-  CoinWithDenom,
-  ContractTerms,
   DenominationRecord,
-  PayCoinInfo,
-  PaybackRequest,
   PreCoinRecord,
   RefreshSessionRecord,
   ReserveRecord,
   TipPlanchet,
   WireFee,
-} from "../types";
+} from "../dbTypes";
+
+import {
+  ContractTerms,
+  PaybackRequest,
+} from "../talerTypes";
+
+import {
+  CoinWithDenom,
+  PayCoinInfo,
+} from "../walletTypes";
 
 import * as timer from "../timer";
 
diff --git a/src/crypto/cryptoWorker.ts b/src/crypto/cryptoWorker.ts
index 3b954811..1e5f10c2 100644
--- a/src/crypto/cryptoWorker.ts
+++ b/src/crypto/cryptoWorker.ts
@@ -22,27 +22,33 @@
 /**
  * Imports.
  */
+import * as Amounts from "../amounts";
+import { AmountJson } from "../amounts";
+
 import {
-  canonicalJson,
-} from "../helpers";
-import {
-  AmountJson,
-  Amounts,
-  CoinPaySig,
   CoinRecord,
   CoinStatus,
-  CoinWithDenom,
-  ContractTerms,
   DenominationRecord,
-  PayCoinInfo,
-  PaybackRequest,
   PreCoinRecord,
   RefreshPreCoinRecord,
   RefreshSessionRecord,
   ReserveRecord,
   TipPlanchet,
   WireFee,
-} from "../types";
+} from "../dbTypes";
+
+import {
+  CoinPaySig,
+  ContractTerms,
+  PaybackRequest,
+} from "../talerTypes";
+
+import {
+  CoinWithDenom,
+  PayCoinInfo,
+} from "../walletTypes";
+
+import { canonicalJson } from "../helpers";
 
 import {
   Amount,
@@ -112,6 +118,9 @@ namespace RpcFunctions {
   }
 
 
+  /**
+   * Create a planchet used for tipping, including the private keys.
+   */
   export function createTipPlanchet(denom: DenominationRecord): TipPlanchet {
     const denomPub = native.RsaPublicKey.fromCrock(denom.denomPub);
     const coinPriv = native.EddsaPrivateKey.create();
@@ -134,8 +143,8 @@ namespace RpcFunctions {
       coinPriv: coinPriv.toCrock(),
       coinPub: coinPub.toCrock(),
       coinValue: denom.value,
-      denomPubHash: denomPub.encode().hash().toCrock(),
       denomPub: denomPub.encode().toCrock(),
+      denomPubHash: denomPub.encode().hash().toCrock(),
     };
     return tipPlanchet;
   }
@@ -263,8 +272,8 @@ namespace RpcFunctions {
                               cds: CoinWithDenom[]): PayCoinInfo {
     const ret: PayCoinInfo = {
       originalCoins: [],
-      updatedCoins: [],
       sigs: [],
+      updatedCoins: [],
     };
 
     const contractTermsHash = hashString(canonicalJson(contractTerms));
@@ -325,8 +334,8 @@ namespace RpcFunctions {
       const s: CoinPaySig = {
         coin_pub: cd.coin.coinPub,
         coin_sig: coinSig,
-        denom_pub: cd.coin.denomPub,
         contribution: coinSpend.toJson(),
+        denom_pub: cd.coin.denomPub,
         ub_sig: cd.coin.denomSig,
       };
       ret.sigs.push(s);
diff --git a/src/crypto/emscInterface.ts b/src/crypto/emscInterface.ts
index 8c9a3413..ce52c88b 100644
--- a/src/crypto/emscInterface.ts
+++ b/src/crypto/emscInterface.ts
@@ -26,9 +26,9 @@
 /**
  * Imports.
  */
-import {AmountJson} from "../types";
+import { AmountJson } from "../amounts";
 
-import {EmscFunGen, getLib} from "./emscLoader";
+import { EmscFunGen, getLib } from "./emscLoader";
 
 const emscLib = getLib();
 
diff --git a/src/dbTypes.ts b/src/dbTypes.ts
new file mode 100644
index 00000000..e0adb6fc
--- /dev/null
+++ b/src/dbTypes.ts
@@ -0,0 +1,811 @@
+/*
+ This file is part of TALER
+ (C) 2018 GNUnet e.V. and INRIA
+
+ 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/>
+ */
+
+
+/**
+ * Types for records stored in the wallet's database.
+ *
+ * Types for the objects in the database should end in "-Record".
+ */
+
+/**
+ * Imports.
+ */
+import { AmountJson } from "./amounts";
+import { Checkable } from "./checkable";
+import {
+  Auditor,
+  CoinPaySig,
+  ContractTerms,
+  Denomination,
+  PayReq,
+  RefundPermission,
+  TipResponse,
+} from "./talerTypes";
+
+
+/**
+ * A reserve record as stored in the wallet's database.
+ */
+export interface ReserveRecord {
+  /**
+   * The reserve public key.
+   */
+  reserve_pub: string;
+
+  /**
+   * The reserve private key.
+   */
+  reserve_priv: string;
+
+  /**
+   * The exchange base URL.
+   */
+  exchange_base_url: string;
+
+  /**
+   * Time when the reserve was created.
+   */
+  created: number;
+
+  /**
+   * Time when the reserve was depleted.
+   * Set to 0 if not depleted yet.
+   */
+  timestamp_depleted: number;
+
+  /**
+   * Time when the reserve was confirmed.
+   *
+   * Set to 0 if not confirmed yet.
+   */
+  timestamp_confirmed: number;
+
+  /**
+   * 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;
+
+  /**
+   * We got some payback to this reserve.  We'll cease to automatically
+   * withdraw money from it.
+   */
+  hasPayback: boolean;
+
+  /**
+   * Wire information for the bank account that
+   * transfered funds for this reserve.
+   */
+  senderWire?: object;
+}
+
+
+/**
+ * Auditor record as stored with currencies in the exchange database.
+ */
+export interface AuditorRecord {
+  /**
+   * Base url of the auditor.
+   */
+  baseUrl: string;
+  /**
+   * Public signing key of the auditor.
+   */
+  auditorPub: string;
+  /**
+   * Time when the auditing expires.
+   */
+  expirationStamp: number;
+}
+
+
+/**
+ * Exchange for currencies as stored in the wallet's currency
+ * information database.
+ */
+export interface ExchangeForCurrencyRecord {
+  /**
+   * FIXME: unused?
+   */
+  exchangePub: string;
+  /**
+   * Base URL of the exchange.
+   */
+  baseUrl: string;
+}
+
+
+/**
+ * Information about a currency as displayed in the wallet's database.
+ */
+export interface CurrencyRecord {
+  /**
+   * Name of the currency.
+   */
+  name: string;
+  /**
+   * Number of fractional digits to show when rendering the currency.
+   */
+  fractionalDigits: number;
+  /**
+   * Auditors that the wallet trusts for this currency.
+   */
+  auditors: AuditorRecord[];
+  /**
+   * Exchanges that the wallet trusts for this currency.
+   */
+  exchanges: ExchangeForCurrencyRecord[];
+}
+
+
+/**
+ * Status of a denomination.
+ */
+export enum DenominationStatus {
+  /**
+   * Verification was delayed.
+   */
+  Unverified,
+  /**
+   * Verified as valid.
+   */
+  VerifiedGood,
+  /**
+   * Verified as invalid.
+   */
+  VerifiedBad,
+}
+
+
+/**
+ * Denomination record as stored in the wallet's database.
+ */
address@hidden()
+export class 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.String
+  stampStart: string;
+
+  /**
+   * Date after which the currency can't be withdrawn anymore.
+   */
+  @Checkable.String
+  stampExpireWithdraw: string;
+
+  /**
+   * Date after the denomination officially doesn't exist anymore.
+   */
+  @Checkable.String
+  stampExpireLegal: string;
+
+  /**
+   * Data after which coins of this denomination can't be deposited anymore.
+   */
+  @Checkable.String
+  stampExpireDeposit: string;
+
+  /**
+   * 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;
+
+  /**
+   * Was this denomination still offered by the exchange the last time
+   * 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;
+}
+
+
+/**
+ * Exchange record as stored in the wallet's database.
+ */
+export interface ExchangeRecord {
+  /**
+   * Base url of the exchange.
+   */
+  baseUrl: string;
+  /**
+   * Master public key of the exchange.
+   */
+  masterPublicKey: string;
+  /**
+   * Auditors (partially) auditing the exchange.
+   */
+  auditors: Auditor[];
+
+  /**
+   * Currency that the exchange offers.
+   */
+  currency: string;
+
+  /**
+   * Timestamp for last update.
+   */
+  lastUpdateTime: number;
+
+  /**
+   * When did we actually use this exchange last (in milliseconds).  If we
+   * never used the exchange for anything but just updated its info, this is
+   * set to 0.  (Currently only updated when reserves are created.)
+   */
+  lastUsedTime: number;
+
+  /**
+   * Last observed protocol version.
+   */
+  protocolVersion?: string;
+}
+
+
+/**
+ * A coin that isn't yet signed by an exchange.
+ */
+export interface PreCoinRecord {
+  coinPub: string;
+  coinPriv: string;
+  reservePub: string;
+  denomPub: string;
+  blindingKey: string;
+  withdrawSig: string;
+  coinEv: string;
+  exchangeBaseUrl: string;
+  coinValue: AmountJson;
+  /**
+   * Set to true if this pre-coin came from a tip.
+   * Until the tip is marked as "accepted", the resulting
+   * coin will not be used for payments.
+   */
+  isFromTip: boolean;
+}
+
+
+/**
+ * Planchet for a coin during refrehs.
+ */
+export interface RefreshPreCoinRecord {
+  /**
+   * Public key for the coin.
+   */
+  publicKey: string;
+  /**
+   * Private key for the coin.
+   */
+  privateKey: string;
+  /**
+   * Blinded public key.
+   */
+  coinEv: string;
+  /**
+   * Blinding key used.
+   */
+  blindingKey: string;
+}
+
+
+/**
+ * State of returning a list of coins
+ * to the customer's bank account.
+ */
+export interface CoinsReturnRecord {
+  /**
+   * Coins that we're returning.
+   */
+  coins: CoinPaySig[];
+
+  /**
+   * Responses to the deposit requests.
+   */
+  responses: any;
+
+  /**
+   * Ephemeral dummy merchant key for
+   * the coins returns operation.
+   */
+  dummyMerchantPub: string;
+
+  /**
+   * Ephemeral dummy merchant key for
+   * the coins returns operation.
+   */
+  dummyMerchantPriv: string;
+
+  /**
+   * Contract terms.
+   */
+  contractTerms: string;
+
+  /**
+   * Hash of contract terms.
+   */
+  contractTermsHash: string;
+
+  /**
+   * Wire info to send the money for the coins to.
+   */
+  wire: object;
+
+  /**
+   * Hash of the wire object.
+   */
+  wireHash: string;
+
+  /**
+   * All coins were deposited.
+   */
+  finished: boolean;
+}
+
+
+/**
+ * Status of a coin.
+ */
+export enum CoinStatus {
+  /**
+   * Withdrawn and never shown to anybody.
+   */
+  Fresh,
+  /**
+   * Currently planned to be sent to a merchant for a purchase.
+   */
+  PurchasePending,
+  /**
+   * Used for a completed transaction and now dirty.
+   */
+  Dirty,
+  /**
+   * A coin that was refreshed.
+   */
+  Refreshed,
+  /**
+   * Coin marked to be paid back, but payback not finished.
+   */
+  PaybackPending,
+  /**
+   * Coin fully paid back.
+   */
+  PaybackDone,
+  /**
+   * Coin was dirty but can't be refreshed.
+   */
+  Useless,
+  /**
+   * The coin was withdrawn for a tip that the user hasn't accepted yet.
+   */
+  TainedByTip,
+}
+
+
+/**
+ * CoinRecord as stored in the "coins" data store
+ * of the wallet database.
+ */
+export interface CoinRecord {
+  /**
+   * 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;
+
+  /**
+   * Blinding key used when withdrawing the coin.
+   * Potentionally sed again during payback.
+   */
+  blindingKey: string;
+
+  /**
+   * Reserve public key for the reserve we got this coin from,
+   * or zero when we got the coin from refresh.
+   */
+  reservePub: string|undefined;
+
+  /**
+   * Status of the coin.
+   */
+  status: CoinStatus;
+}
+
+/**
+ * Proposal record, stored in the wallet's database.
+ */
address@hidden()
+export class ProposalRecord {
+  /**
+   * The contract that was offered by the merchant.
+   */
+  @Checkable.Value(ContractTerms)
+  contractTerms: ContractTerms;
+
+  /**
+   * Signature by the merchant over the contract details.
+   */
+  @Checkable.String
+  merchantSig: string;
+
+  /**
+   * Hash of the contract terms.
+   */
+  @Checkable.String
+  contractTermsHash: string;
+
+  /**
+   * Serial ID when the offer is stored in the wallet DB.
+   */
+  @Checkable.Optional(Checkable.Number)
+  id?: number;
+
+  /**
+   * Timestamp (in ms) of when the record
+   * was created.
+   */
+  @Checkable.Number
+  timestamp: number;
+
+  /**
+   * Verify that a value matches the schema of this class and convert it into a
+   * member.
+   */
+  static checked: (obj: any) => ProposalRecord;
+}
+
+
+/**
+ * Wire fees for an exchange.
+ */
+export interface ExchangeWireFeesRecord {
+  /**
+   * Base URL of the exchange.
+   */
+  exchangeBaseUrl: string;
+
+  /**
+   * Mapping from wire method type to the wire fee.
+   */
+  feesForType: { [wireMethod: string]: WireFee[] };
+}
+
+
+/**
+ * Status of a tip we got from a merchant.
+ */
+export interface TipRecord {
+  /**
+   * Has the user accepted the tip?  Only after the tip has been accepted coins
+   * withdrawn from the tip may be used.
+   */
+  accepted: boolean;
+
+  /**
+   * The tipped amount.
+   */
+  amount: AmountJson;
+
+  /**
+   * Coin public keys from the planchets.
+   * This field is redundant and used for indexing the record via
+   * a multi-entry index to look up tip records by coin public key.
+   */
+  coinPubs: string[];
+
+  /**
+   * Timestamp, the tip can't be picked up anymore after this deadline.
+   */
+  deadline: number;
+
+  /**
+   * The exchange that will sign our coins, chosen by the merchant.
+   */
+  exchangeUrl: string;
+
+  /**
+   * Domain of the merchant, necessary to uniquely identify the tip since
+   * merchants can freely choose the ID and a malicious merchant might cause a
+   * collision.
+   */
+  merchantDomain: string;
+
+  /**
+   * Planchets, the members included in TipPlanchetDetail will be sent to the
+   * merchant.
+   */
+  planchets: TipPlanchet[];
+
+  /**
+   * Response if the merchant responded,
+   * undefined otherwise.
+   */
+  response?: TipResponse[];
+
+  /**
+   * Identifier for the tip, chosen by the merchant.
+   */
+  tipId: string;
+
+  /**
+   * URL to go to once the tip has been accepted.
+   */
+  nextUrl: string;
+
+  timestamp: number;
+}
+
+
+/**
+ * Ongoing refresh
+ */
+export interface RefreshSessionRecord {
+  /**
+   * 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;
+
+  /**
+   * Hased denominations of the newly requested coins.
+   */
+  newDenomHashes: string[];
+
+  /**
+   * Denominations of the newly requested coins.
+   */
+  newDenoms: string[];
+
+  /**
+   * Precoins for each cut-and-choose instance.
+   */
+  preCoinsForGammas: RefreshPreCoinRecord[][];
+
+  /**
+   * The transfer keys, kappa of them.
+   */
+  transferPubs: string[];
+
+  /**
+   * Private keys for the transfer public keys.
+   */
+  transferPrivs: string[];
+
+  /**
+   * The no-reveal-index after we've done the melting.
+   */
+  norevealIndex?: number;
+
+  /**
+   * Hash of the session.
+   */
+  hash: string;
+
+  /**
+   * Base URL for the exchange we're doing the refresh with.
+   */
+  exchangeBaseUrl: string;
+
+  /**
+   * Is this session finished?
+   */
+  finished: boolean;
+
+  /**
+   * Record ID when retrieved from the DB.
+   */
+  id?: number;
+}
+
+
+/**
+ * Tipping planchet stored in the database.
+ */
+export interface TipPlanchet {
+  blindingKey: string;
+  coinEv: string;
+  coinPriv: string;
+  coinPub: string;
+  coinValue: AmountJson;
+  denomPubHash: string;
+  denomPub: string;
+}
+
+
+/**
+ * Wire fee for one wire method as stored in the
+ * wallet's database.
+ */
+export interface WireFee {
+  /**
+   * Fee for wire transfers.
+   */
+  wireFee: AmountJson;
+
+  /**
+   * Fees to close and refund a reserve.
+   */
+  closingFee: AmountJson;
+
+  /**
+   * Start date of the fee.
+   */
+  startStamp: number;
+
+  /**
+   * End date of the fee.
+   */
+  endStamp: number;
+
+  /**
+   * Signature made by the exchange master key.
+   */
+  sig: string;
+}
+
+/**
+ * Record that stores status information about one purchase, starting from when
+ * the customer accepts a proposal.  Includes refund status if applicable.
+ */
+export interface PurchaseRecord {
+  contractTermsHash: string;
+  contractTerms: ContractTerms;
+  payReq: PayReq;
+  merchantSig: string;
+
+  /**
+   * The purchase isn't active anymore, it's either successfully paid or
+   * refunded/aborted.
+   */
+  finished: boolean;
+
+  refundsPending: { [refundSig: string]: RefundPermission };
+  refundsDone: { [refundSig: string]: RefundPermission };
+
+  /**
+   * When was the purchase made?
+   * Refers to the time that the user accepted.
+   */
+  timestamp: number;
+
+  /**
+   * When was the last refund made?
+   * Set to 0 if no refund was made on the purchase.
+   */
+  timestamp_refund: number;
+}
diff --git a/src/helpers.ts b/src/helpers.ts
index 6dc080b2..d85808ac 100644
--- a/src/helpers.ts
+++ b/src/helpers.ts
@@ -21,7 +21,8 @@
 /**
  * Imports.
  */
-import {AmountJson, Amounts} from "./types";
+import { AmountJson } from "./amounts";
+import * as Amounts from "./amounts";
 
 import URI = require("urijs");
 
diff --git a/src/query.ts b/src/query.ts
index b199e0e9..e45596c6 100644
--- a/src/query.ts
+++ b/src/query.ts
@@ -825,7 +825,7 @@ export class QueryRoot {
         const req = tx.objectStore(store.name).get(key);
         req.onsuccess = () => {
           results.push(req.result);
-          if (results.length == keys.length) {
+          if (results.length === keys.length) {
             resolve(results);
           }
         };
diff --git a/src/talerTypes.ts b/src/talerTypes.ts
new file mode 100644
index 00000000..2ac2a515
--- /dev/null
+++ b/src/talerTypes.ts
@@ -0,0 +1,632 @@
+/*
+ This file is part of TALER
+ (C) 2018 GNUnet e.V. and INRIA
+
+ 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/>
+ */
+
+/**
+ * Type and schema definitions for the base taler protocol.
+ *
+ * All types here should be "@Checkable".
+ *
+ * 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 { AmountJson } from "./amounts";
+import { Checkable } from "./checkable";
+
+
+/**
+ * Denomination as found in the /keys response from the exchange.
+ */
address@hidden()
+export class Denomination {
+  /**
+   * Value of one coin of the denomination.
+   */
+  @Checkable.Value(AmountJson)
+  value: AmountJson;
+
+  /**
+   * Public signing key of the denomination.
+   */
+  @Checkable.String
+  denom_pub: string;
+
+  /**
+   * Fee for withdrawing.
+   */
+  @Checkable.Value(AmountJson)
+  fee_withdraw: AmountJson;
+
+  /**
+   * Fee for depositing.
+   */
+  @Checkable.Value(AmountJson)
+  fee_deposit: AmountJson;
+
+  /**
+   * Fee for refreshing.
+   */
+  @Checkable.Value(AmountJson)
+  fee_refresh: AmountJson;
+
+  /**
+   * Fee for refunding.
+   */
+  @Checkable.Value(AmountJson)
+  fee_refund: AmountJson;
+
+  /**
+   * Start date from which withdraw is allowed.
+   */
+  @Checkable.String
+  stamp_start: string;
+
+  /**
+   * End date for withdrawing.
+   */
+  @Checkable.String
+  stamp_expire_withdraw: string;
+
+  /**
+   * Expiration date after which the exchange can forget about
+   * the currency.
+   */
+  @Checkable.String
+  stamp_expire_legal: string;
+
+  /**
+   * Date after which the coins of this denomination can't be
+   * deposited anymore.
+   */
+  @Checkable.String
+  stamp_expire_deposit: string;
+
+  /**
+   * 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.
+ */
address@hidden()
+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.
+ */
address@hidden()
+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[];
+}
+
+
+/**
+ * Request that we send to the exchange to get a payback.
+ */
+export interface PaybackRequest {
+  /**
+   * Denomination public key of the coin we want to get
+   * paid back.
+   */
+  denom_pub: string;
+
+  /**
+   * Signature over the coin public key by the denomination.
+   */
+  denom_sig: string;
+
+  /**
+   * Coin public key of the coin we want to refund.
+   */
+  coin_pub: string;
+
+  /**
+   * Blinding key that was used during withdraw,
+   * used to prove that we were actually withdrawing the coin.
+   */
+  coin_blind_key_secret: string;
+
+  /**
+   * Signature made by the coin, authorizing the payback.
+   */
+  coin_sig: string;
+}
+
+
+/**
+ * Response that we get from the exchange for a payback request.
+ */
address@hidden()
+export class PaybackConfirmation {
+  /**
+   * 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.Value(AmountJson)
+  amount: AmountJson;
+
+  /**
+   * Time by which the exchange received the /payback request.
+   */
+  @Checkable.String
+  timestamp: string;
+
+  /**
+   * the EdDSA signature of TALER_PaybackConfirmationPS using a current
+   * signing key of the exchange affirming the successful
+   * payback request, and that the exchange promises to transfer the funds
+   * 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;
+
+  /**
+   * 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.
+   */
+  @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;
+}
+
+
+/**
+ * Deposit permission for a single coin.
+ */
+export interface CoinPaySig {
+  /**
+   * Signature by the coin.
+   */
+  coin_sig: string;
+  /**
+   * Public key of the coin being spend.
+   */
+  coin_pub: string;
+  /**
+   * Signature made by the denomination public key.
+   */
+  ub_sig: string;
+  /**
+   * The denomination public key associated with this coin.
+   */
+  denom_pub: string;
+  /**
+   * The amount that is subtracted from this coin with this payment.
+   */
+  contribution: AmountJson;
+}
+
+
+/**
+ * Information about an exchange as stored inside a
+ * merchant's contract terms.
+ */
address@hidden()
+export class ExchangeHandle {
+  /**
+   * Master public signing key of the exchange.
+   */
+  @Checkable.String
+  master_pub: string;
+
+  /**
+   * Base URL of the exchange.
+   */
+  @Checkable.String
+  url: string;
+
+  /**
+   * Verify that a value matches the schema of this class and convert it into a
+   * member.
+   */
+  static checked: (obj: any) => ExchangeHandle;
+}
+
+
+/**
+ * Contract terms from a merchant.
+ */
address@hidden({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;
+
+  /**
+   * 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;
+
+  /**
+   * Nonce used to ensure freshness.
+   */
+  @Checkable.Optional(Checkable.String)
+  nonce?: string;
+
+  /**
+   * Total amount payable.
+   */
+  @Checkable.Value(AmountJson)
+  amount: AmountJson;
+
+  /**
+   * Auditors accepted by the merchant.
+   */
+  @Checkable.List(Checkable.AnyObject)
+  auditors: any[];
+
+  /**
+   * Deadline to pay for the contract.
+   */
+  @Checkable.Optional(Checkable.String)
+  pay_deadline: string;
+
+  /**
+   * Delivery locations.
+   */
+  @Checkable.Any
+  locations: any;
+
+  /**
+   * Maximum deposit fee covered by the merchant.
+   */
+  @Checkable.Value(AmountJson)
+  max_fee: AmountJson;
+
+  /**
+   * 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[];
+
+  /**
+   * Deadline for refunds.
+   */
+  @Checkable.String
+  refund_deadline: string;
+
+  /**
+   * Time when the contract was generated by the merchant.
+   */
+  @Checkable.String
+  timestamp: string;
+
+  /**
+   * Order id to uniquely identify the purchase within
+   * one merchant instance.
+   */
+  @Checkable.String
+  order_id: string;
+
+  /**
+   * URL to post the payment to.
+   */
+  @Checkable.String
+  pay_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.Value(AmountJson))
+  max_wire_fee?: AmountJson;
+
+  /**
+   * 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;
+}
+
+
+/**
+ * Payment body sent to the merchant's /pay.
+ */
+export interface PayReq {
+  /**
+   * Coins with signature.
+   */
+  coins: CoinPaySig[];
+
+  /**
+   * The merchant public key, used to uniquely
+   * identify the merchant instance.
+   */
+  merchant_pub: string;
+
+  /**
+   * Order ID that's being payed for.
+   */
+  order_id: string;
+
+  /**
+   * Exchange that the coins are from (base URL).
+   */
+  exchange: string;
+}
+
+
+/**
+ * Refund permission in the format that the merchant gives it to us.
+ */
+export interface RefundPermission {
+  /**
+   * Amount to be refunded.
+   */
+  refund_amount: AmountJson;
+
+  /**
+   * Fee for the refund.
+   */
+  refund_fee: AmountJson;
+
+  /**
+   * Contract terms hash to identify the contract that this
+   * refund is for.
+   */
+  h_contract_terms: string;
+
+  /**
+   * Public key of the coin being refunded.
+   */
+  coin_pub: string;
+
+  /**
+   * Refund transaction ID between merchant and exchange.
+   */
+  rtransaction_id: number;
+
+  /**
+   * Public key of the merchant.
+   */
+  merchant_pub: string;
+
+  /**
+   * Signature made by the merchant over the refund permission.
+   */
+  merchant_sig: string;
+}
+
+
+/**
+ * Planchet detail sent to the merchant.
+ */
+export interface TipPlanchetDetail {
+  /**
+   * Hashed denomination public key.
+   */
+  denom_pub_hash: string;
+
+  /**
+   * Coin's blinded public key.
+   */
+  coin_ev: string;
+}
+
+
+/**
+ * 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 with "@Checkable".
+ */
address@hidden()
+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.
+ */
address@hidden()
+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;
+}
+
+/**
+ * Token containing all the information for the wallet
+ * to process a tip.  Given by the merchant to the wallet.
+ */
address@hidden()
+export class TipToken {
+  /**
+   * Expiration for the tip.
+   */
+  @Checkable.String
+  expiration: string;
+
+  /**
+   * URL of the exchange that the tip can be withdrawn from.
+   */
+  @Checkable.String
+  exchange_url: string;
+
+  /**
+   * Merchant's URL to pick up the tip.
+   */
+  @Checkable.String
+  pickup_url: string;
+
+  /**
+   * Merchant-chosen tip identifier.
+   */
+  @Checkable.String
+  tip_id: string;
+
+  /**
+   * Amount of tip.
+   */
+  @Checkable.Value(AmountJson)
+  amount: AmountJson;
+
+  /**
+   * URL to navigate after finishing tip processing.
+   */
+  @Checkable.String
+  next_url: string;
+
+  /**
+   * Create a TipToken from untyped JSON.
+   * Validates the schema and throws on error.
+   */
+  static checked: (obj: any) => TipToken;
+}
diff --git a/src/types-test.ts b/src/types-test.ts
index 3657d6d2..097235a7 100644
--- a/src/types-test.ts
+++ b/src/types-test.ts
@@ -14,17 +14,17 @@
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import {test} from "ava";
-import {Amounts} from "./types";
-import * as types from "./types";
+import { test } from "ava";
+import * as Amounts from "./amounts";
+import { ContractTerms } from "./talerTypes";
 
-const amt = (value: number, fraction: number, currency: string): 
types.AmountJson => ({value, fraction, currency});
+const amt = (value: number, fraction: number, currency: string): 
Amounts.AmountJson => ({value, fraction, currency});
 
 test("amount addition (simple)", (t) => {
   const a1 = amt(1, 0, "EUR");
   const a2 = amt(1, 0, "EUR");
   const a3 = amt(2, 0, "EUR");
-  t.true(0 === types.Amounts.cmp(Amounts.add(a1, a2).amount, a3));
+  t.true(0 === Amounts.cmp(Amounts.add(a1, a2).amount, a3));
   t.pass();
 });
 
@@ -39,7 +39,7 @@ test("amount subtraction (simple)", (t) => {
   const a1 = amt(2, 5, "EUR");
   const a2 = amt(1, 0, "EUR");
   const a3 = amt(1, 5, "EUR");
-  t.true(0 === types.Amounts.cmp(Amounts.sub(a1, a2).amount, a3));
+  t.true(0 === Amounts.cmp(Amounts.sub(a1, a2).amount, a3));
   t.pass();
 });
 
@@ -73,13 +73,13 @@ test("contract terms validation", (t) => {
     wire_method: "test",
   };
 
-  types.ContractTerms.checked(c);
+  ContractTerms.checked(c);
 
   const c1 = JSON.parse(JSON.stringify(c));
   c1.exchanges = [];
 
   try {
-    types.ContractTerms.checked(c1);
+    ContractTerms.checked(c1);
   } catch (e) {
     t.pass();
     return;
diff --git a/src/types.ts b/src/types.ts
deleted file mode 100644
index ae4454a8..00000000
--- a/src/types.ts
+++ /dev/null
@@ -1,2048 +0,0 @@
-/*
- This file is part of TALER
- (C) 2015-2017 GNUnet e.V. and INRIA
-
- 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 and some helper functions
- * to deal with them.
- *
- * 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.
- */
-
-/**
- * Imports.
- */
-import { Checkable } from "./checkable";
-import * as LibtoolVersion from "./libtoolVersion";
-
-/**
- * Non-negative financial amount.  Fractional values are expressed as multiples
- * of 1e-8.
- */
address@hidden()
-export class AmountJson {
-  /**
-   * Value, must be an integer.
-   */
-  @Checkable.Number
-  readonly value: number;
-
-  /**
-   * Fraction, must be an integer.  Represent 1/1e8 of a unit.
-   */
-  @Checkable.Number
-  readonly fraction: number;
-
-  /**
-   * Currency of the amount.
-   */
-  @Checkable.String
-  readonly currency: string;
-
-  /**
-   * Verify that a value matches the schema of this class and convert it into a
-   * member.
-   */
-  static checked: (obj: any) => AmountJson;
-}
-
-
-/**
- * Amount with a sign.
- */
-export interface SignedAmountJson {
-  /**
-   * The absolute amount.
-   */
-  amount: AmountJson;
-  /**
-   * Sign.
-   */
-  isNegative: boolean;
-}
-
-
-/**
- * A reserve record as stored in the wallet's database.
- */
-export interface ReserveRecord {
-  /**
-   * The reserve public key.
-   */
-  reserve_pub: string;
-
-  /**
-   * The reserve private key.
-   */
-  reserve_priv: string;
-
-  /**
-   * The exchange base URL.
-   */
-  exchange_base_url: string;
-
-  /**
-   * Time when the reserve was created.
-   */
-  created: number;
-
-  /**
-   * Time when the reserve was depleted.
-   * Set to 0 if not depleted yet.
-   */
-  timestamp_depleted: number;
-
-  /**
-   * Time when the reserve was confirmed.
-   *
-   * Set to 0 if not confirmed yet.
-   */
-  timestamp_confirmed: number;
-
-  /**
-   * 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;
-
-  /**
-   * We got some payback to this reserve.  We'll cease to automatically
-   * withdraw money from it.
-   */
-  hasPayback: boolean;
-
-  /**
-   * Wire information for the bank account that
-   * transfered funds for this reserve.
-   */
-  senderWire?: object;
-}
-
-
-/**
- * Auditor record as stored with currencies in the exchange database.
- */
-export interface AuditorRecord {
-  /**
-   * Base url of the auditor.
-   */
-  baseUrl: string;
-  /**
-   * Public signing key of the auditor.
-   */
-  auditorPub: string;
-  /**
-   * Time when the auditing expires.
-   */
-  expirationStamp: number;
-}
-
-
-/**
- * Exchange for currencies as stored in the wallet's currency
- * information database.
- */
-export interface ExchangeForCurrencyRecord {
-  /**
-   * FIXME: unused?
-   */
-  exchangePub: string;
-  /**
-   * Base URL of the exchange.
-   */
-  baseUrl: string;
-}
-
-
-/**
- * Information about a currency as displayed in the wallet's database.
- */
-export interface CurrencyRecord {
-  /**
-   * Name of the currency.
-   */
-  name: string;
-  /**
-   * Number of fractional digits to show when rendering the currency.
-   */
-  fractionalDigits: number;
-  /**
-   * Auditors that the wallet trusts for this currency.
-   */
-  auditors: AuditorRecord[];
-  /**
-   * Exchanges that the wallet trusts for this currency.
-   */
-  exchanges: ExchangeForCurrencyRecord[];
-}
-
-
-/**
- * Response for the create reserve request to the wallet.
- */
address@hidden()
-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;
-}
-
-
-/**
- * Status of a denomination.
- */
-export enum DenominationStatus {
-  /**
-   * Verification was delayed.
-   */
-  Unverified,
-  /**
-   * Verified as valid.
-   */
-  VerifiedGood,
-  /**
-   * Verified as invalid.
-   */
-  VerifiedBad,
-}
-
-/**
- * Denomination record as stored in the wallet's database.
- */
address@hidden()
-export class 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.String
-  stampStart: string;
-
-  /**
-   * Date after which the currency can't be withdrawn anymore.
-   */
-  @Checkable.String
-  stampExpireWithdraw: string;
-
-  /**
-   * Date after the denomination officially doesn't exist anymore.
-   */
-  @Checkable.String
-  stampExpireLegal: string;
-
-  /**
-   * Data after which coins of this denomination can't be deposited anymore.
-   */
-  @Checkable.String
-  stampExpireDeposit: string;
-
-  /**
-   * 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;
-
-  /**
-   * Was this denomination still offered by the exchange the last time
-   * 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;
-}
-
-/**
- * Denomination as found in the /keys response from the exchange.
- */
address@hidden()
-export class Denomination {
-  /**
-   * Value of one coin of the denomination.
-   */
-  @Checkable.Value(AmountJson)
-  value: AmountJson;
-
-  /**
-   * Public signing key of the denomination.
-   */
-  @Checkable.String
-  denom_pub: string;
-
-  /**
-   * Fee for withdrawing.
-   */
-  @Checkable.Value(AmountJson)
-  fee_withdraw: AmountJson;
-
-  /**
-   * Fee for depositing.
-   */
-  @Checkable.Value(AmountJson)
-  fee_deposit: AmountJson;
-
-  /**
-   * Fee for refreshing.
-   */
-  @Checkable.Value(AmountJson)
-  fee_refresh: AmountJson;
-
-  /**
-   * Fee for refunding.
-   */
-  @Checkable.Value(AmountJson)
-  fee_refund: AmountJson;
-
-  /**
-   * Start date from which withdraw is allowed.
-   */
-  @Checkable.String
-  stamp_start: string;
-
-  /**
-   * End date for withdrawing.
-   */
-  @Checkable.String
-  stamp_expire_withdraw: string;
-
-  /**
-   * Expiration date after which the exchange can forget about
-   * the currency.
-   */
-  @Checkable.String
-  stamp_expire_legal: string;
-
-  /**
-   * Date after which the coins of this denomination can't be
-   * deposited anymore.
-   */
-  @Checkable.String
-  stamp_expire_deposit: string;
-
-  /**
-   * 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.
- */
address@hidden()
-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.
- */
address@hidden()
-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[];
-}
-
-
-/**
- * Exchange record as stored in the wallet's database.
- */
-export interface ExchangeRecord {
-  /**
-   * Base url of the exchange.
-   */
-  baseUrl: string;
-  /**
-   * Master public key of the exchange.
-   */
-  masterPublicKey: string;
-  /**
-   * Auditors (partially) auditing the exchange.
-   */
-  auditors: Auditor[];
-
-  /**
-   * Currency that the exchange offers.
-   */
-  currency: string;
-
-  /**
-   * Timestamp for last update.
-   */
-  lastUpdateTime: number;
-
-  /**
-   * When did we actually use this exchange last (in milliseconds).  If we
-   * never used the exchange for anything but just updated its info, this is
-   * set to 0.  (Currently only updated when reserves are created.)
-   */
-  lastUsedTime: number;
-
-  /**
-   * Last observed protocol version.
-   */
-  protocolVersion?: string;
-}
-
-/**
- * Wire info, sent to the bank when creating a reserve.  Fee information will
- * be filtered out.  Only methods that the bank also supports should be sent.
- */
-export interface WireInfo {
-  /**
-   * Mapping from wire method type to the exchange's wire info,
-   * excluding fees.
-   */
-  [type: string]: any;
-}
-
-
-/**
- * Information about what will happen when creating a reserve.
- *
- * Sent to the wallet frontend to be rendered and shown to the user.
- */
-export interface ReserveCreationInfo {
-  /**
-   * Exchange that the reserve will be created at.
-   */
-  exchangeInfo: ExchangeRecord;
-  /**
-   * Filtered wire info to send to the bank.
-   */
-  wireInfo: WireInfo;
-  /**
-   * Selected denominations for withdraw.
-   */
-  selectedDenoms: DenominationRecord[];
-  /**
-   * Fees for withdraw.
-   */
-  withdrawFee: AmountJson;
-  /**
-   * Remaining balance that is too small to be withdrawn.
-   */
-  overhead: AmountJson;
-  /**
-   * Wire fees from the exchange.
-   */
-  wireFees: ExchangeWireFeesRecord;
-  /**
-   * Does the wallet know about an auditor for
-   * the exchange that the reserve.
-   */
-  isAudited: boolean;
-  /**
-   * The exchange is trusted directly.
-   */
-  isTrusted: boolean;
-  /**
-   * The earliest deposit expiration of the selected coins.
-   */
-  earliestDepositExpiration: number;
-  /**
-   * Number of currently offered denominations.
-   */
-  numOfferedDenoms: number;
-  /**
-   * Public keys of trusted auditors for the currency we're withdrawing.
-   */
-  trustedAuditorPubs: string[];
-  /**
-   * Result of checking the wallet's version
-   * against the exchange's version.
-   *
-   * Older exchanges don't return version information.
-   */
-  versionMatch: LibtoolVersion.VersionMatchResult|undefined;
-
-  /**
-   * Libtool-style version string for the exchange or "unknown"
-   * for older exchanges.
-   */
-  exchangeVersion: string;
-
-  /**
-   * Libtool-style version string for the wallet.
-   */
-  walletVersion: string;
-}
-
-
-/**
- * A coin that isn't yet signed by an exchange.
- */
-export interface PreCoinRecord {
-  coinPub: string;
-  coinPriv: string;
-  reservePub: string;
-  denomPub: string;
-  blindingKey: string;
-  withdrawSig: string;
-  coinEv: string;
-  exchangeBaseUrl: string;
-  coinValue: AmountJson;
-  /**
-   * Set to true if this pre-coin came from a tip.
-   * Until the tip is marked as "accepted", the resulting
-   * coin will not be used for payments.
-   */
-  isFromTip: boolean;
-}
-
-/**
- * Planchet for a coin during refrehs.
- */
-export interface RefreshPreCoinRecord {
-  /**
-   * Public key for the coin.
-   */
-  publicKey: string;
-  /**
-   * Private key for the coin.
-   */
-  privateKey: string;
-  /**
-   * Blinded public key.
-   */
-  coinEv: string;
-  /**
-   * Blinding key used.
-   */
-  blindingKey: string;
-}
-
-/**
- * Request that we send to the exchange to get a payback.
- */
-export interface PaybackRequest {
-  /**
-   * Denomination public key of the coin we want to get
-   * paid back.
-   */
-  denom_pub: string;
-
-  /**
-   * Signature over the coin public key by the denomination.
-   */
-  denom_sig: string;
-
-  /**
-   * Coin public key of the coin we want to refund.
-   */
-  coin_pub: string;
-
-  /**
-   * Blinding key that was used during withdraw,
-   * used to prove that we were actually withdrawing the coin.
-   */
-  coin_blind_key_secret: string;
-
-  /**
-   * Signature made by the coin, authorizing the payback.
-   */
-  coin_sig: string;
-}
-
-/**
- * Response that we get from the exchange for a payback request.
- */
address@hidden()
-export class PaybackConfirmation {
-  /**
-   * 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.Value(AmountJson)
-  amount: AmountJson;
-
-  /**
-   * Time by which the exchange received the /payback request.
-   */
-  @Checkable.String
-  timestamp: string;
-
-  /**
-   * the EdDSA signature of TALER_PaybackConfirmationPS using a current
-   * signing key of the exchange affirming the successful
-   * payback request, and that the exchange promises to transfer the funds
-   * 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;
-
-  /**
-   * 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.
-   */
-  @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;
-}
-
-/**
- * Ongoing refresh
- */
-export interface RefreshSessionRecord {
-  /**
-   * 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;
-
-  /**
-   * Hased denominations of the newly requested coins.
-   */
-  newDenomHashes: string[];
-
-  /**
-   * Denominations of the newly requested coins.
-   */
-  newDenoms: string[];
-
-  /**
-   * Precoins for each cut-and-choose instance.
-   */
-  preCoinsForGammas: RefreshPreCoinRecord[][];
-
-  /**
-   * The transfer keys, kappa of them.
-   */
-  transferPubs: string[];
-
-  /**
-   * Private keys for the transfer public keys.
-   */
-  transferPrivs: string[];
-
-  /**
-   * The no-reveal-index after we've done the melting.
-   */
-  norevealIndex?: number;
-
-  /**
-   * Hash of the session.
-   */
-  hash: string;
-
-  /**
-   * Base URL for the exchange we're doing the refresh with.
-   */
-  exchangeBaseUrl: string;
-
-  /**
-   * Is this session finished?
-   */
-  finished: boolean;
-
-  /**
-   * Record ID when retrieved from the DB.
-   */
-  id?: number;
-}
-
-
-/**
- * Deposit permission for a single coin.
- */
-export interface CoinPaySig {
-  /**
-   * Signature by the coin.
-   */
-  coin_sig: string;
-  /**
-   * Public key of the coin being spend.
-   */
-  coin_pub: string;
-  /**
-   * Signature made by the denomination public key.
-   */
-  ub_sig: string;
-  /**
-   * The denomination public key associated with this coin.
-   */
-  denom_pub: string;
-  /**
-   * The amount that is subtracted from this coin with this payment.
-   */
-  contribution: AmountJson;
-}
-
-
-/**
- * Status of a coin.
- */
-export enum CoinStatus {
-  /**
-   * Withdrawn and never shown to anybody.
-   */
-  Fresh,
-  /**
-   * Currently planned to be sent to a merchant for a purchase.
-   */
-  PurchasePending,
-  /**
-   * Used for a completed transaction and now dirty.
-   */
-  Dirty,
-  /**
-   * A coin that was refreshed.
-   */
-  Refreshed,
-  /**
-   * Coin marked to be paid back, but payback not finished.
-   */
-  PaybackPending,
-  /**
-   * Coin fully paid back.
-   */
-  PaybackDone,
-  /**
-   * Coin was dirty but can't be refreshed.
-   */
-  Useless,
-  /**
-   * The coin was withdrawn for a tip that the user hasn't accepted yet.
-   */
-  TainedByTip,
-}
-
-
-/**
- * State of returning a list of coins
- * to the customer's bank account.
- */
-export interface CoinsReturnRecord {
-  /**
-   * Coins that we're returning.
-   */
-  coins: CoinPaySig[];
-
-  /**
-   * Responses to the deposit requests.
-   */
-  responses: any;
-
-  /**
-   * Ephemeral dummy merchant key for
-   * the coins returns operation.
-   */
-  dummyMerchantPub: string;
-
-  /**
-   * Ephemeral dummy merchant key for
-   * the coins returns operation.
-   */
-  dummyMerchantPriv: string;
-
-  /**
-   * Contract terms.
-   */
-  contractTerms: string;
-
-  /**
-   * Hash of contract terms.
-   */
-  contractTermsHash: string;
-
-  /**
-   * Wire info to send the money for the coins to.
-   */
-  wire: object;
-
-  /**
-   * Hash of the wire object.
-   */
-  wireHash: string;
-
-  /**
-   * All coins were deposited.
-   */
-  finished: boolean;
-}
-
-
-/**
- * CoinRecord as stored in the "coins" data store
- * of the wallet database.
- */
-export interface CoinRecord {
-  /**
-   * 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;
-
-  /**
-   * Blinding key used when withdrawing the coin.
-   * Potentionally sed again during payback.
-   */
-  blindingKey: string;
-
-  /**
-   * Reserve public key for the reserve we got this coin from,
-   * or zero when we got the coin from refresh.
-   */
-  reservePub: string|undefined;
-
-  /**
-   * Status of the coin.
-   */
-  status: CoinStatus;
-}
-
-
-/**
- * Information about an exchange as stored inside a
- * merchant's contract terms.
- */
address@hidden()
-export class ExchangeHandle {
-  /**
-   * Master public signing key of the exchange.
-   */
-  @Checkable.String
-  master_pub: string;
-
-  /**
-   * Base URL of the exchange.
-   */
-  @Checkable.String
-  url: string;
-
-  /**
-   * Verify that a value matches the schema of this class and convert it into a
-   * member.
-   */
-  static checked: (obj: any) => ExchangeHandle;
-}
-
-
-/**
- * Mapping from currency/exchange to detailed balance
- * information.
- */
-export interface WalletBalance {
-  /**
-   * Mapping from currency name to detailed balance info.
-   */
-  byExchange: { [exchangeBaseUrl: string]: WalletBalanceEntry };
-
-  /**
-   * Mapping from currency name to detailed balance info.
-   */
-  byCurrency: { [currency: string]: WalletBalanceEntry };
-}
-
-
-/**
- * Detailed wallet balance for a particular currency.
- */
-export interface WalletBalanceEntry {
-  /**
-   * Directly available amount.
-   */
-  available: AmountJson;
-  /**
-   * Amount that we're waiting for (refresh, withdrawal).
-   */
-  pendingIncoming: AmountJson;
-  /**
-   * Amount that's marked for a pending payment.
-   */
-  pendingPayment: AmountJson;
-  /**
-   * Amount that was paid back and we could withdraw again.
-   */
-  paybackAmount: AmountJson;
-}
-
-
-/**
- * Contract terms from a merchant.
- */
address@hidden({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;
-
-  /**
-   * 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;
-
-  /**
-   * Nonce used to ensure freshness.
-   */
-  @Checkable.Optional(Checkable.String)
-  nonce?: string;
-
-  /**
-   * Total amount payable.
-   */
-  @Checkable.Value(AmountJson)
-  amount: AmountJson;
-
-  /**
-   * Auditors accepted by the merchant.
-   */
-  @Checkable.List(Checkable.AnyObject)
-  auditors: any[];
-
-  /**
-   * Deadline to pay for the contract.
-   */
-  @Checkable.Optional(Checkable.String)
-  pay_deadline: string;
-
-  /**
-   * Delivery locations.
-   */
-  @Checkable.Any
-  locations: any;
-
-  /**
-   * Maximum deposit fee covered by the merchant.
-   */
-  @Checkable.Value(AmountJson)
-  max_fee: AmountJson;
-
-  /**
-   * 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[];
-
-  /**
-   * Deadline for refunds.
-   */
-  @Checkable.String
-  refund_deadline: string;
-
-  /**
-   * Time when the contract was generated by the merchant.
-   */
-  @Checkable.String
-  timestamp: string;
-
-  /**
-   * Order id to uniquely identify the purchase within
-   * one merchant instance.
-   */
-  @Checkable.String
-  order_id: string;
-
-  /**
-   * URL to post the payment to.
-   */
-  @Checkable.String
-  pay_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.Value(AmountJson))
-  max_wire_fee?: AmountJson;
-
-  /**
-   * 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;
-}
-
-
-/**
- * Proposal record, stored in the wallet's database.
- */
address@hidden()
-export class ProposalRecord {
-  /**
-   * The contract that was offered by the merchant.
-   */
-  @Checkable.Value(ContractTerms)
-  contractTerms: ContractTerms;
-
-  /**
-   * Signature by the merchant over the contract details.
-   */
-  @Checkable.String
-  merchantSig: string;
-
-  /**
-   * Hash of the contract terms.
-   */
-  @Checkable.String
-  contractTermsHash: string;
-
-  /**
-   * Serial ID when the offer is stored in the wallet DB.
-   */
-  @Checkable.Optional(Checkable.Number)
-  id?: number;
-
-  /**
-   * Timestamp (in ms) of when the record
-   * was created.
-   */
-  @Checkable.Number
-  timestamp: number;
-
-  /**
-   * Verify that a value matches the schema of this class and convert it into a
-   * member.
-   */
-  static checked: (obj: any) => ProposalRecord;
-}
-
-
-/**
- * Wire fee for one wire method as stored in the
- * wallet's database.
- */
-export interface WireFee {
-  /**
-   * Fee for wire transfers.
-   */
-  wireFee: AmountJson;
-
-  /**
-   * Fees to close and refund a reserve.
-   */
-  closingFee: AmountJson;
-
-  /**
-   * Start date of the fee.
-   */
-  startStamp: number;
-
-  /**
-   * End date of the fee.
-   */
-  endStamp: number;
-
-  /**
-   * Signature made by the exchange master key.
-   */
-  sig: string;
-}
-
-
-/**
- * Wire fees for an exchange.
- */
-export interface ExchangeWireFeesRecord {
-  /**
-   * Base URL of the exchange.
-   */
-  exchangeBaseUrl: string;
-
-  /**
-   * Mapping from wire method type to the wire fee.
-   */
-  feesForType: { [wireMethod: string]: WireFee[] };
-}
-
-
-/**
- * Coins used for a payment, with signatures authorizing the payment and the
- * coins with remaining value updated to accomodate for a payment.
- */
-export interface PayCoinInfo {
-  originalCoins: CoinRecord[];
-  updatedCoins: CoinRecord[];
-  sigs: CoinPaySig[];
-}
-
-
-/**
- * Amount helpers.
- */
-export namespace Amounts {
-  /**
-   * Number of fractional units that one value unit represents.
-   */
-  export const fractionalBase = 1e8;
-
-  /**
-   * Result of a possibly overflowing operation.
-   */
-  export interface Result {
-    /**
-     * Resulting, possibly saturated amount.
-     */
-    amount: AmountJson;
-    /**
-     * Was there an over-/underflow?
-     */
-    saturated: boolean;
-  }
-
-  /**
-   * Get the largest amount that is safely representable.
-   */
-  export function getMaxAmount(currency: string): AmountJson {
-    return {
-      currency,
-      fraction: 2 ** 32,
-      value: Number.MAX_SAFE_INTEGER,
-    };
-  }
-
-  /**
-   * Get an amount that represents zero units of a currency.
-   */
-  export function getZero(currency: string): AmountJson {
-    return {
-      currency,
-      fraction: 0,
-      value: 0,
-    };
-  }
-
-  /**
-   * Add two amounts.  Return the result and whether
-   * the addition overflowed.  The overflow is always handled
-   * by saturating and never by wrapping.
-   *
-   * Throws when currencies don't match.
-   */
-  export function add(first: AmountJson, ...rest: AmountJson[]): Result {
-    const currency = first.currency;
-    let value = first.value + Math.floor(first.fraction / fractionalBase);
-    if (value > Number.MAX_SAFE_INTEGER) {
-      return { amount: getMaxAmount(currency), saturated: true };
-    }
-    let fraction = first.fraction % fractionalBase;
-    for (const x of rest) {
-      if (x.currency !== currency) {
-        throw Error(`Mismatched currency: ${x.currency} and ${currency}`);
-      }
-
-      value = value + x.value + Math.floor((fraction + x.fraction) / 
fractionalBase);
-      fraction = Math.floor((fraction + x.fraction) % fractionalBase);
-      if (value > Number.MAX_SAFE_INTEGER) {
-        return { amount: getMaxAmount(currency), saturated: true };
-      }
-    }
-    return { amount: { currency, value, fraction }, saturated: false };
-  }
-
-  /**
-   * Subtract two amounts.  Return the result and whether
-   * the subtraction overflowed.  The overflow is always handled
-   * by saturating and never by wrapping.
-   *
-   * Throws when currencies don't match.
-   */
-  export function sub(a: AmountJson, ...rest: AmountJson[]): Result {
-    const currency = a.currency;
-    let value = a.value;
-    let fraction = a.fraction;
-
-    for (const 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 += fractionalBase;
-      }
-      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 };
-  }
-
-  /**
-   * Compare two amounts.  Returns 0 when equal, -1 when a < b
-   * and +1 when a > b.  Throws when currencies don't match.
-   */
-  export function cmp(a: AmountJson, b: AmountJson): number {
-    if (a.currency !== b.currency) {
-      throw Error(`Mismatched currency: ${a.currency} and ${b.currency}`);
-    }
-    const av = a.value + Math.floor(a.fraction / fractionalBase);
-    const af = a.fraction % fractionalBase;
-    const bv = b.value + Math.floor(b.fraction / fractionalBase);
-    const bf = b.fraction % fractionalBase;
-    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");
-    }
-  }
-
-  /**
-   * Create a copy of an amount.
-   */
-  export function copy(a: AmountJson): AmountJson {
-    return {
-      currency: a.currency,
-      fraction: a.fraction,
-      value: a.value,
-    };
-  }
-
-  /**
-   * Divide an amount.  Throws on division by zero.
-   */
-  export function divide(a: AmountJson, n: number): AmountJson {
-    if (n === 0) {
-      throw Error(`Division by 0`);
-    }
-    if (n === 1) {
-      return {value: a.value, fraction: a.fraction, currency: a.currency};
-    }
-    const r = a.value % n;
-    return {
-      currency: a.currency,
-      fraction: Math.floor(((r * fractionalBase) + a.fraction) / n),
-      value: Math.floor(a.value / n),
-    };
-  }
-
-  /**
-   * Check if an amount is non-zero.
-   */
-  export function isNonZero(a: AmountJson): boolean {
-    return a.value > 0 || a.fraction > 0;
-  }
-
-  /**
-   * Parse an amount like 'EUR:20.5' for 20 Euros and 50 ct.
-   */
-  export function parse(s: string): AmountJson|undefined {
-    const res = s.match(/([a-zA-Z0-9_*-]+):([0-9])+([.][0-9]+)?/);
-    if (!res) {
-      return undefined;
-    }
-    return {
-      currency: res[1],
-      fraction: Math.round(fractionalBase * Number.parseFloat(res[3] || "0")),
-      value: Number.parseInt(res[2]),
-    };
-  }
-
-  /**
-   * Convert the amount to a float.
-   */
-  export function toFloat(a: AmountJson): number {
-    return a.value + (a.fraction / fractionalBase);
-  }
-
-  /**
-   * Convert a float to a Taler amount.
-   * Loss of precision possible.
-   */
-  export function fromFloat(floatVal: number, currency: string) {
-    return {
-      currency,
-      fraction: Math.floor((floatVal - Math.floor(floatVal)) * fractionalBase),
-      value: Math.floor(floatVal),
-    };
-  }
-}
-
-
-/**
- * Listener for notifications from the wallet.
- */
-export interface Notifier {
-  /**
-   * Called when a new notification arrives.
-   */
-  notify(): void;
-}
-
-/**
- * For terseness.
- */
-export function mkAmount(value: number, fraction: number, currency: string): 
AmountJson {
-  return {value, fraction, currency};
-}
-
-/**
- * Possible results for checkPay.
- */
-export interface CheckPayResult {
-  status: "paid" | "payment-possible" | "insufficient-balance";
-  coinSelection?: CoinSelectionResult;
-}
-
-/**
- * Possible results for confirmPay.
- */
-export type ConfirmPayResult = "paid" | "insufficient-balance";
-
-
-/**
- * Activity history record.
- */
-export interface HistoryRecord {
-  /**
-   * Type of the history event.
-   */
-  type: string;
-
-  /**
-   * Time when the activity was recorded.
-   */
-  timestamp: number;
-
-  /**
-   * Subject of the entry.  Used to group multiple history records together.
-   * Only the latest history record with the same subjectId will be shown.
-   */
-  subjectId?: string;
-
-  /**
-   * Details used when rendering the history record.
-   */
-  detail: any;
-}
-
-
-/**
- * Payment body sent to the merchant's /pay.
- */
-export interface PayReq {
-  /**
-   * Coins with signature.
-   */
-  coins: CoinPaySig[];
-
-  /**
-   * The merchant public key, used to uniquely
-   * identify the merchant instance.
-   */
-  merchant_pub: string;
-
-  /**
-   * Order ID that's being payed for.
-   */
-  order_id: string;
-
-  /**
-   * Exchange that the coins are from (base URL).
-   */
-  exchange: string;
-}
-
-
-/**
- * Response to a query payment request.  Tagged union over the 'found' field.
- */
-export type QueryPaymentResult = QueryPaymentNotFound | QueryPaymentFound;
-
-/**
- * Query payment response when the payment was found.
- */
-export interface QueryPaymentNotFound {
-  found: false;
-}
-
-/**
- * Query payment response when the payment wasn't found.
- */
-export interface QueryPaymentFound {
-  found: true;
-  contractTermsHash: string;
-  contractTerms: ContractTerms;
-  payReq: PayReq;
-}
-
-/**
- * Information about all sender wire details known to the wallet,
- * as well as exchanges that accept these wire types.
- */
-export interface SenderWireInfos {
-  /**
-   * Mapping from exchange base url to list of accepted
-   * wire types.
-   */
-  exchangeWireTypes: { [exchangeBaseUrl: string]: string[] };
-
-  /**
-   * Sender wire types stored in the wallet.
-   */
-  senderWires: object[];
-}
-
-
-/**
- * Request to mark a reserve as confirmed.
- */
address@hidden()
-export class 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;
-
-  /**
-   * Wire details for the bank account that sent the funds to the exchange.
-   */
-  @Checkable.Optional(Checkable.Any)
-  senderWire?: object;
-
-  /**
-   * Verify that a value matches the schema of this class and convert it into a
-   * member.
-   */
-  static checked: (obj: any) => CreateReserveRequest;
-}
-
-
-/**
- * Request to mark a reserve as confirmed.
- */
address@hidden()
-export class 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;
-}
-
-
-/**
- * Wire coins to the user's own bank account.
- */
address@hidden()
-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;
-
-  /**
-   * Verify that a value matches the schema of this class and convert it into a
-   * member.
-   */
-  static checked: (obj: any) => ReturnCoinsRequest;
-}
-
-
-/**
- * Refund permission in the format that the merchant gives it to us.
- */
-export interface RefundPermission {
-  /**
-   * Amount to be refunded.
-   */
-  refund_amount: AmountJson;
-
-  /**
-   * Fee for the refund.
-   */
-  refund_fee: AmountJson;
-
-  /**
-   * Contract terms hash to identify the contract that this
-   * refund is for.
-   */
-  h_contract_terms: string;
-
-  /**
-   * Public key of the coin being refunded.
-   */
-  coin_pub: string;
-
-  /**
-   * Refund transaction ID between merchant and exchange.
-   */
-  rtransaction_id: number;
-
-  /**
-   * Public key of the merchant.
-   */
-  merchant_pub: string;
-
-  /**
-   * Signature made by the merchant over the refund permission.
-   */
-  merchant_sig: string;
-}
-
-
-/**
- * Record that stores status information about one purchase, starting from when
- * the customer accepts a proposal.  Includes refund status if applicable.
- */
-export interface PurchaseRecord {
-  contractTermsHash: string;
-  contractTerms: ContractTerms;
-  payReq: PayReq;
-  merchantSig: string;
-
-  /**
-   * The purchase isn't active anymore, it's either successfully paid or
-   * refunded/aborted.
-   */
-  finished: boolean;
-
-  refundsPending: { [refundSig: string]: RefundPermission };
-  refundsDone: { [refundSig: string]: RefundPermission };
-
-  /**
-   * When was the purchase made?
-   * Refers to the time that the user accepted.
-   */
-  timestamp: number;
-
-  /**
-   * When was the last refund made?
-   * Set to 0 if no refund was made on the purchase.
-   */
-  timestamp_refund: number;
-}
-
-
-/**
- * Result of selecting coins, contains the exchange, and selected
- * coins with their denomination.
- */
-export interface CoinSelectionResult {
-  exchangeUrl: string;
-  cds: CoinWithDenom[];
-  totalFees: AmountJson;
-}
-
-
-/**
- * Named tuple of coin and denomination.
- */
-export interface CoinWithDenom {
-  /**
-   * A coin.  Must have the same denomination public key as the associated
-   * denomination.
-   */
-  coin: CoinRecord;
-  /**
-   * An associated denomination.
-   */
-  denom: DenominationRecord;
-}
-
-
-/**
- * Planchet detail sent to the merchant.
- */
-export interface TipPlanchetDetail {
-  /**
-   * Hashed denomination public key.
-   */
-  denom_pub_hash: string;
-
-  /**
-   * Coin's blinded public key.
-   */
-  coin_ev: string;
-}
-
-
-export interface TipPickupRequest {
-  /**
-   * Identifier of the tip.
-   */
-  tip_id: string;
-
-  /**
-   * List of planchets the wallet wants to use for the tip.
-   */
-  planchets: TipPlanchetDetail[];
-}
-
address@hidden()
-export class ReserveSigSingleton {
-  @Checkable.String
-  reserve_sig: string;
-
-  static checked: (obj: any) => ReserveSigSingleton;
-}
-
-/**
- * Response of the merchant
- * to the TipPickupRequest.
- */
address@hidden()
-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[];
-
-  static checked: (obj: any) => TipResponse;
-}
-
-
-/**
- * Tipping planchet stored in the database.
- */
-export interface TipPlanchet {
-  blindingKey: string;
-  coinEv: string;
-  coinPriv: string;
-  coinPub: string;
-  coinValue: AmountJson;
-  denomPubHash: string;
-  denomPub: string;
-}
-
-/**
- * Status of a tip we got from a merchant.
- */
-export interface TipRecord {
-  /**
-   * Has the user accepted the tip?  Only after the tip has been accepted coins
-   * withdrawn from the tip may be used.
-   */
-  accepted: boolean;
-
-  /**
-   * The tipped amount.
-   */
-  amount: AmountJson;
-
-  /**
-   * Coin public keys from the planchets.
-   * This field is redundant and used for indexing the record via
-   * a multi-entry index to look up tip records by coin public key.
-   */
-  coinPubs: string[];
-
-  /**
-   * Timestamp, the tip can't be picked up anymore after this deadline.
-   */
-  deadline: number;
-
-  /**
-   * The exchange that will sign our coins, chosen by the merchant.
-   */
-  exchangeUrl: string;
-
-  /**
-   * Domain of the merchant, necessary to uniquely identify the tip since
-   * merchants can freely choose the ID and a malicious merchant might cause a
-   * collision.
-   */
-  merchantDomain: string;
-
-  /**
-   * Planchets, the members included in TipPlanchetDetail will be sent to the
-   * merchant.
-   */
-  planchets: TipPlanchet[];
-
-  /**
-   * Response if the merchant responded,
-   * undefined otherwise.
-   */
-  response?: TipResponse[];
-
-  /**
-   * Identifier for the tip, chosen by the merchant.
-   */
-  tipId: string;
-
-  /**
-   * URL to go to once the tip has been accepted.
-   */
-  nextUrl: string;
-
-  timestamp: number;
-}
-
-
-export interface TipStatus {
-  tip: TipRecord;
-  rci?: ReserveCreationInfo;
-}
-
-
address@hidden()
-export class TipStatusRequest {
-  @Checkable.String
-  tipId: string;
-
-  @Checkable.String
-  merchantDomain: string;
-
-  static checked: (obj: any) => TipStatusRequest;
-}
-
-
address@hidden()
-export class AcceptTipRequest {
-  @Checkable.String
-  tipId: string;
-
-  @Checkable.String
-  merchantDomain: string;
-
-  static checked: (obj: any) => AcceptTipRequest;
-}
-
-
address@hidden()
-export class ProcessTipResponseRequest {
-  @Checkable.String
-  tipId: string;
-
-  @Checkable.String
-  merchantDomain: string;
-
-  @Checkable.Value(TipResponse)
-  tipResponse: TipResponse;
-
-  static checked: (obj: any) => ProcessTipResponseRequest;
-}
-
address@hidden()
-export class GetTipPlanchetsRequest {
-  @Checkable.String
-  tipId: string;
-
-  @Checkable.String
-  merchantDomain: string;
-
-  @Checkable.Optional(Checkable.Value(AmountJson))
-  amount: AmountJson;
-
-  @Checkable.Number
-  deadline: number;
-
-  @Checkable.String
-  exchangeUrl: string;
-
-  @Checkable.String
-  nextUrl: string;
-
-  static checked: (obj: any) => GetTipPlanchetsRequest;
-}
-
address@hidden()
-export class TipToken {
-  @Checkable.String
-  expiration: string;
-
-  @Checkable.String
-  exchange_url: string;
-
-  @Checkable.String
-  pickup_url: string;
-
-  @Checkable.String
-  tip_id: string;
-
-  @Checkable.Value(AmountJson)
-  amount: AmountJson;
-
-  @Checkable.String
-  next_url: string;
-
-  static checked: (obj: any) => TipToken;
-}
diff --git a/src/wallet-test.ts b/src/wallet-test.ts
index 037cc759..6b06085c 100644
--- a/src/wallet-test.ts
+++ b/src/wallet-test.ts
@@ -15,13 +15,19 @@
  */
 
 
-import {test} from "ava";
-import * as types from "./types";
+import { test } from "ava";
+
+import * as dbTypes from "./dbTypes";
+import * as types from "./walletTypes";
+
 import * as wallet from "./wallet";
 
+import { AmountJson} from "./amounts";
+import * as Amounts from "./amounts";
+
 
-function a(x: string): types.AmountJson {
-  const amt = types.Amounts.parse(x);
+function a(x: string): AmountJson {
+  const amt = Amounts.parse(x);
   if (!amt) {
     throw Error("invalid amount");
   }
@@ -40,7 +46,7 @@ function fakeCwd(current: string, value: string, feeDeposit: 
string): types.Coin
       denomSig: "(mock)",
       exchangeBaseUrl: "(mock)",
       reservePub: "(mock)",
-      status: types.CoinStatus.Fresh,
+      status: dbTypes.CoinStatus.Fresh,
     },
     denom: {
       denomPub: "(mock)",
@@ -56,7 +62,7 @@ function fakeCwd(current: string, value: string, feeDeposit: 
string): types.Coin
       stampExpireLegal: "(mock)",
       stampExpireWithdraw: "(mock)",
       stampStart: "(mock)",
-      status: types.DenominationStatus.VerifiedGood,
+      status: dbTypes.DenominationStatus.VerifiedGood,
       value: a(value),
     },
   };
diff --git a/src/wallet.ts b/src/wallet.ts
index ca94e1d5..41f8e727 100644
--- a/src/wallet.ts
+++ b/src/wallet.ts
@@ -43,56 +43,64 @@ import {
   QueryRoot,
   Store,
 } from "./query";
-import {TimerGroup} from "./timer";
+import { TimerGroup } from "./timer";
+
+import { AmountJson } from "./amounts";
+import * as Amounts from "./amounts";
+
 import {
-  AmountJson,
-  Amounts,
-  Auditor,
-  CheckPayResult,
-  CoinPaySig,
   CoinRecord,
-  CoinSelectionResult,
   CoinStatus,
-  CoinWithDenom,
-  ConfirmPayResult,
-  ConfirmReserveRequest,
-  ContractTerms,
-  CreateReserveRequest,
-  CreateReserveResponse,
   CurrencyRecord,
-  Denomination,
   DenominationRecord,
   DenominationStatus,
-  ExchangeHandle,
   ExchangeRecord,
   ExchangeWireFeesRecord,
-  HistoryRecord,
-  Notifier,
-  PayCoinInfo,
-  PayReq,
-  PaybackConfirmation,
   PreCoinRecord,
   ProposalRecord,
   PurchaseRecord,
-  QueryPaymentResult,
   RefreshPreCoinRecord,
   RefreshSessionRecord,
+  ReserveRecord,
+  TipRecord,
+  WireFee,
+} from "./dbTypes";
+
+import URI = require("urijs");
+
+import {
+  Auditor,
+  CoinPaySig,
+  ContractTerms,
+  Denomination,
+  ExchangeHandle,
+  PayReq,
+  PaybackConfirmation,
   RefundPermission,
+  TipPlanchetDetail,
+  TipResponse,
+} from "./talerTypes";
+import {
+  CheckPayResult,
+  CoinSelectionResult,
+  CoinWithDenom,
+  ConfirmPayResult,
+  ConfirmReserveRequest,
+  CreateReserveRequest,
+  CreateReserveResponse,
+  HistoryRecord,
+  Notifier,
+  PayCoinInfo,
+  QueryPaymentResult,
   ReserveCreationInfo,
-  ReserveRecord,
   ReturnCoinsRequest,
   SenderWireInfos,
-  TipPlanchetDetail,
-  TipRecord,
-  TipResponse,
   TipStatus,
   WalletBalance,
   WalletBalanceEntry,
-  WireFee,
   WireInfo,
-} from "./types";
 
-import URI = require("urijs");
+} from "./walletTypes";
 
 
 /**
@@ -561,7 +569,9 @@ export namespace Stores {
       super("purchases", {keyPath: "contractTermsHash"});
     }
 
-    fulfillmentUrlIndex = new Index<string, PurchaseRecord>(this, 
"fulfillmentUrlIndex", "contractTerms.fulfillment_url");
+    fulfillmentUrlIndex = new Index<string, PurchaseRecord>(this,
+                                                            
"fulfillmentUrlIndex",
+                                                            
"contractTerms.fulfillment_url");
     orderIdIndex = new Index<string, PurchaseRecord>(this, "orderIdIndex", 
"contractTerms.order_id");
     timestampIndex = new Index<string, PurchaseRecord>(this, "timestampIndex", 
"timestamp");
   }
@@ -1077,7 +1087,7 @@ export class Wallet {
     if (!sp) {
       return;
     }
-    if (sp.proposalId != proposalId) {
+    if (sp.proposalId !== proposalId) {
       return;
     }
     const coinKeys = sp.payCoinInfo.updatedCoins.map(x => x.coinPub);
@@ -1090,8 +1100,8 @@ export class Wallet {
       if (!currentCoin) {
         return;
       }
-      if (Amounts.cmp(specCoin.currentAmount, currentCoin.currentAmount) != 0) 
{
-        return
+      if (Amounts.cmp(specCoin.currentAmount, currentCoin.currentAmount) !== 
0) {
+        return;
       }
     }
     return sp;
@@ -1135,7 +1145,7 @@ export class Wallet {
     }
 
     // Only create speculative signature if we don't already have one for this 
proposal
-    if ((!this.speculativePayData) || (this.speculativePayData && 
this.speculativePayData.proposalId != proposalId)) {
+    if ((!this.speculativePayData) || (this.speculativePayData && 
this.speculativePayData.proposalId !== proposalId)) {
       const { exchangeUrl, cds } = res;
       const payCoinInfo = await 
this.cryptoApi.signDeposit(proposal.contractTerms, cds);
       this.speculativePayData = {
@@ -1250,7 +1260,7 @@ export class Wallet {
                 .finish();
 
       if (coin.status === CoinStatus.TainedByTip) {
-        let tip = await this.q().getIndexed(Stores.tips.coinPubIndex, 
coin.coinPub);
+        const tip = await this.q().getIndexed(Stores.tips.coinPubIndex, 
coin.coinPub);
         if (!tip) {
           throw Error(`inconsistent DB: tip for coin pub ${coin.coinPub} not 
found.`);
         }
@@ -1263,8 +1273,8 @@ export class Wallet {
               c.status = CoinStatus.Fresh;
             }
             return c;
-          }
-          await this.q().mutate(Stores.coins, coin.coinPub, mutateCoin)
+          };
+          await this.q().mutate(Stores.coins, coin.coinPub, mutateCoin);
           // Show notifications only for accepted tips
           this.badge.showNotification();
         }
@@ -1724,6 +1734,7 @@ export class Wallet {
     const ret: ReserveCreationInfo = {
       earliestDepositExpiration,
       exchangeInfo,
+      exchangeVersion: exchangeInfo.protocolVersion || "unknown",
       isAudited,
       isTrusted,
       numOfferedDenoms: possibleDenoms.length,
@@ -1731,11 +1742,10 @@ export class Wallet {
       selectedDenoms,
       trustedAuditorPubs,
       versionMatch,
+      walletVersion: WALLET_PROTOCOL_VERSION,
       wireFees,
       wireInfo,
       withdrawFee: acc,
-      exchangeVersion: exchangeInfo.protocolVersion || "unknown",
-      walletVersion: WALLET_PROTOCOL_VERSION,
     };
     return ret;
   }
@@ -1779,7 +1789,7 @@ export class Wallet {
           .indexJoinLeft(Stores.denominations.exchangeBaseUrlIndex,
                          (e) => e.exchangeBaseUrl)
           .fold((cd: JoinLeftResult<CoinRecord, DenominationRecord>,
-                   suspendedCoins: CoinRecord[]) => {
+                 suspendedCoins: CoinRecord[]) => {
             if ((!cd.right) || (!cd.right.isOffered)) {
               return Array.prototype.concat(suspendedCoins, [cd.left]);
             }
@@ -1922,8 +1932,7 @@ export class Wallet {
       this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex,
                          exchangeInfo.baseUrl)
           .fold((x: DenominationRecord,
-                   acc: typeof existingDenoms) => (acc[x.denomPub] = x, acc),
-                  {})
+                 acc: typeof existingDenoms) => (acc[x.denomPub] = x, acc), {})
     );
 
     const newDenoms: typeof existingDenoms = {};
@@ -2432,9 +2441,9 @@ export class Wallet {
     for (const tip of tips) {
       history.push({
         detail: {
-          merchantDomain: tip.merchantDomain,
-          amount: tip.amount,
           accepted: tip.accepted,
+          amount: tip.amount,
+          merchantDomain: tip.merchantDomain,
           tipId: tip.tipId,
         },
         timestamp: tip.timestamp,
@@ -2760,8 +2769,8 @@ export class Wallet {
         H_wire: coinsReturnRecord.contractTerms.H_wire,
         coin_pub: c.coinPaySig.coin_pub,
         coin_sig: c.coinPaySig.coin_sig,
-        denom_pub: c.coinPaySig.denom_pub,
         contribution: c.coinPaySig.contribution,
+        denom_pub: c.coinPaySig.denom_pub,
         h_contract_terms: coinsReturnRecord.contractTermsHash,
         merchant_pub: coinsReturnRecord.contractTerms.merchant_pub,
         pay_deadline: coinsReturnRecord.contractTerms.pay_deadline,
@@ -2950,7 +2959,12 @@ export class Wallet {
    * Get planchets for a tip.  Creates new planchets if they don't exist 
already
    * for this tip.  The tip is uniquely identified by the merchant's domain 
and the tip id.
    */
-  async getTipPlanchets(merchantDomain: string, tipId: string, amount: 
AmountJson, deadline: number, exchangeUrl: string, nextUrl: string): 
Promise<TipPlanchetDetail[]> {
+  async getTipPlanchets(merchantDomain: string,
+                        tipId: string,
+                        amount: AmountJson,
+                        deadline: number,
+                        exchangeUrl: string,
+                        nextUrl: string): Promise<TipPlanchetDetail[]> {
     let tipRecord = await this.q().get(Stores.tips, [tipId, merchantDomain]);
     if (!tipRecord) {
       await this.updateExchangeFromUrl(exchangeUrl);
@@ -2973,9 +2987,9 @@ export class Wallet {
       await this.q().put(Stores.tips, tipRecord).finish();
     }
     // Planchets in the form that the merchant expects
-    const planchetDetail: TipPlanchetDetail[]= tipRecord.planchets.map((p) => 
({
-      denom_pub_hash: p.denomPubHash,
+    const planchetDetail: TipPlanchetDetail[] = tipRecord.planchets.map((p) => 
({
       coin_ev: p.coinEv,
+      denom_pub_hash: p.denomPubHash,
     }));
     return planchetDetail;
   }
@@ -2985,7 +2999,7 @@ export class Wallet {
    * These coins will not appear in the wallet yet.
    */
   async processTipResponse(merchantDomain: string, tipId: string, response: 
TipResponse): Promise<void> {
-    let tipRecord = await this.q().get(Stores.tips, [tipId, merchantDomain]);
+    const tipRecord = await this.q().get(Stores.tips, [tipId, merchantDomain]);
     if (!tipRecord) {
       throw Error("tip not found");
     }
@@ -2995,18 +3009,18 @@ export class Wallet {
     }
 
     for (let i = 0; i < tipRecord.planchets.length; i++) {
-      let planchet = tipRecord.planchets[i];
-      let preCoin = {
-        coinPub: planchet.coinPub,
-        coinPriv: planchet.coinPriv,
+      const planchet = tipRecord.planchets[i];
+      const preCoin = {
+        blindingKey: planchet.blindingKey,
         coinEv: planchet.coinEv,
+        coinPriv: planchet.coinPriv,
+        coinPub: planchet.coinPub,
         coinValue: planchet.coinValue,
-        reservePub: response.reserve_pub,
         denomPub: planchet.denomPub,
-        blindingKey: planchet.blindingKey,
-        withdrawSig: response.reserve_sigs[i].reserve_sig,
         exchangeBaseUrl: tipRecord.exchangeUrl,
         isFromTip: true,
+        reservePub: response.reserve_pub,
+        withdrawSig: response.reserve_sigs[i].reserve_sig,
       };
       await this.q().put(Stores.precoins, preCoin);
       this.processPreCoin(preCoin);
@@ -3082,8 +3096,8 @@ export class Wallet {
     const gcProposal = (d: ProposalRecord, n: number) => {
       // Delete proposal after 60 minutes or 5 minutes before pay deadline,
       // whatever comes first.
-      let deadlinePayMilli = getTalerStampSec(d.contractTerms.pay_deadline)! * 
1000;
-      let deadlineExpireMilli = nowMilli + (1000 * 60 * 60);
+      const deadlinePayMilli = getTalerStampSec(d.contractTerms.pay_deadline)! 
* 1000;
+      const deadlineExpireMilli = nowMilli + (1000 * 60 * 60);
       return d.timestamp < Math.min(deadlinePayMilli, deadlineExpireMilli);
     };
     await this.q().deleteIf(Stores.proposals, gcProposal).finish();
@@ -3096,7 +3110,7 @@ export class Wallet {
       }
       activeExchanges.push(d.baseUrl);
       return false;
-    }
+    };
 
     await this.q().deleteIf(Stores.exchanges, gcExchange).finish();
 
diff --git a/src/walletTypes.ts b/src/walletTypes.ts
new file mode 100644
index 00000000..cd0eee4c
--- /dev/null
+++ b/src/walletTypes.ts
@@ -0,0 +1,572 @@
+/*
+ This file is part of TALER
+ (C) 2015-2017 GNUnet e.V. and INRIA
+
+ 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/>
+ */
+
+/**
+ * Types used by clients of the wallet.
+ *
+ * These types are defined in a separate file make tree shaking easier, since
+ * some components use these types (via RPC) but do not depend on the wallet
+ * code directly.
+ */
+
+/**
+ * Imports.
+ */
+import { Checkable } from "./checkable";
+import * as LibtoolVersion from "./libtoolVersion";
+
+import { AmountJson } from "./amounts";
+
+import {
+  CoinRecord,
+  DenominationRecord,
+  ExchangeRecord,
+  ExchangeWireFeesRecord,
+  TipRecord,
+} from "./dbTypes";
+import {
+  CoinPaySig,
+  ContractTerms,
+  PayReq,
+  TipResponse,
+} from "./talerTypes";
+
+
+/**
+ * Response for the create reserve request to the wallet.
+ */
address@hidden()
+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;
+}
+
+
+/**
+ * Wire info, sent to the bank when creating a reserve.  Fee information will
+ * be filtered out.  Only methods that the bank also supports should be sent.
+ */
+export interface WireInfo {
+  /**
+   * Mapping from wire method type to the exchange's wire info,
+   * excluding fees.
+   */
+  [type: string]: any;
+}
+
+
+/**
+ * Information about what will happen when creating a reserve.
+ *
+ * Sent to the wallet frontend to be rendered and shown to the user.
+ */
+export interface ReserveCreationInfo {
+  /**
+   * Exchange that the reserve will be created at.
+   */
+  exchangeInfo: ExchangeRecord;
+
+  /**
+   * Filtered wire info to send to the bank.
+   */
+  wireInfo: WireInfo;
+
+  /**
+   * Selected denominations for withdraw.
+   */
+  selectedDenoms: DenominationRecord[];
+
+  /**
+   * Fees for withdraw.
+   */
+  withdrawFee: AmountJson;
+
+  /**
+   * Remaining balance that is too small to be withdrawn.
+   */
+  overhead: AmountJson;
+
+  /**
+   * Wire fees from the exchange.
+   */
+  wireFees: ExchangeWireFeesRecord;
+
+  /**
+   * Does the wallet know about an auditor for
+   * the exchange that the reserve.
+   */
+  isAudited: boolean;
+
+  /**
+   * The exchange is trusted directly.
+   */
+  isTrusted: boolean;
+
+  /**
+   * The earliest deposit expiration of the selected coins.
+   */
+  earliestDepositExpiration: number;
+
+  /**
+   * Number of currently offered denominations.
+   */
+  numOfferedDenoms: number;
+  /**
+   * Public keys of trusted auditors for the currency we're withdrawing.
+   */
+  trustedAuditorPubs: string[];
+
+  /**
+   * Result of checking the wallet's version
+   * against the exchange's version.
+   *
+   * Older exchanges don't return version information.
+   */
+  versionMatch: LibtoolVersion.VersionMatchResult|undefined;
+
+  /**
+   * Libtool-style version string for the exchange or "unknown"
+   * for older exchanges.
+   */
+  exchangeVersion: string;
+
+  /**
+   * Libtool-style version string for the wallet.
+   */
+  walletVersion: string;
+}
+
+
+/**
+ * Mapping from currency/exchange to detailed balance
+ * information.
+ */
+export interface WalletBalance {
+  /**
+   * Mapping from currency name to detailed balance info.
+   */
+  byExchange: { [exchangeBaseUrl: string]: WalletBalanceEntry };
+
+  /**
+   * Mapping from currency name to detailed balance info.
+   */
+  byCurrency: { [currency: string]: WalletBalanceEntry };
+}
+
+
+/**
+ * Detailed wallet balance for a particular currency.
+ */
+export interface WalletBalanceEntry {
+  /**
+   * Directly available amount.
+   */
+  available: AmountJson;
+  /**
+   * Amount that we're waiting for (refresh, withdrawal).
+   */
+  pendingIncoming: AmountJson;
+  /**
+   * Amount that's marked for a pending payment.
+   */
+  pendingPayment: AmountJson;
+  /**
+   * Amount that was paid back and we could withdraw again.
+   */
+  paybackAmount: AmountJson;
+}
+
+
+/**
+ * Coins used for a payment, with signatures authorizing the payment and the
+ * coins with remaining value updated to accomodate for a payment.
+ */
+export interface PayCoinInfo {
+  originalCoins: CoinRecord[];
+  updatedCoins: CoinRecord[];
+  sigs: CoinPaySig[];
+}
+
+
+/**
+ * Listener for notifications from the wallet.
+ */
+export interface Notifier {
+  /**
+   * Called when a new notification arrives.
+   */
+  notify(): void;
+}
+
+
+/**
+ * For terseness.
+ */
+export function mkAmount(value: number, fraction: number, currency: string): 
AmountJson {
+  return {value, fraction, currency};
+}
+
+
+/**
+ * Possible results for checkPay.
+ */
+export interface CheckPayResult {
+  status: "paid" | "payment-possible" | "insufficient-balance";
+  coinSelection?: CoinSelectionResult;
+}
+
+
+/**
+ * Possible results for confirmPay.
+ */
+export type ConfirmPayResult = "paid" | "insufficient-balance";
+
+
+/**
+ * Activity history record.
+ */
+export interface HistoryRecord {
+  /**
+   * Type of the history event.
+   */
+  type: string;
+
+  /**
+   * Time when the activity was recorded.
+   */
+  timestamp: number;
+
+  /**
+   * Subject of the entry.  Used to group multiple history records together.
+   * Only the latest history record with the same subjectId will be shown.
+   */
+  subjectId?: string;
+
+  /**
+   * Details used when rendering the history record.
+   */
+  detail: any;
+}
+
+
+/**
+ * Response to a query payment request.  Tagged union over the 'found' field.
+ */
+export type QueryPaymentResult = QueryPaymentNotFound | QueryPaymentFound;
+
+
+/**
+ * Query payment response when the payment was found.
+ */
+export interface QueryPaymentNotFound {
+  found: false;
+}
+
+
+/**
+ * Query payment response when the payment wasn't found.
+ */
+export interface QueryPaymentFound {
+  found: true;
+  contractTermsHash: string;
+  contractTerms: ContractTerms;
+  payReq: PayReq;
+}
+
+
+/**
+ * Information about all sender wire details known to the wallet,
+ * as well as exchanges that accept these wire types.
+ */
+export interface SenderWireInfos {
+  /**
+   * Mapping from exchange base url to list of accepted
+   * wire types.
+   */
+  exchangeWireTypes: { [exchangeBaseUrl: string]: string[] };
+
+  /**
+   * Sender wire types stored in the wallet.
+   */
+  senderWires: object[];
+}
+
+
+/**
+ * Request to mark a reserve as confirmed.
+ */
address@hidden()
+export class 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;
+
+  /**
+   * Wire details for the bank account that sent the funds to the exchange.
+   */
+  @Checkable.Optional(Checkable.Any)
+  senderWire?: object;
+
+  /**
+   * Verify that a value matches the schema of this class and convert it into a
+   * member.
+   */
+  static checked: (obj: any) => CreateReserveRequest;
+}
+
+
+/**
+ * Request to mark a reserve as confirmed.
+ */
address@hidden()
+export class 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;
+}
+
+
+/**
+ * Wire coins to the user's own bank account.
+ */
address@hidden()
+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;
+
+  /**
+   * Verify that a value matches the schema of this class and convert it into a
+   * member.
+   */
+  static checked: (obj: any) => ReturnCoinsRequest;
+}
+
+
+/**
+ * Result of selecting coins, contains the exchange, and selected
+ * coins with their denomination.
+ */
+export interface CoinSelectionResult {
+  exchangeUrl: string;
+  cds: CoinWithDenom[];
+  totalFees: AmountJson;
+}
+
+
+/**
+ * Named tuple of coin and denomination.
+ */
+export interface CoinWithDenom {
+  /**
+   * A coin.  Must have the same denomination public key as the associated
+   * denomination.
+   */
+  coin: CoinRecord;
+  /**
+   * An associated denomination.
+   */
+  denom: DenominationRecord;
+}
+
+
+/**
+ * Status of processing a tip.
+ */
+export interface TipStatus {
+  tip: TipRecord;
+  rci?: ReserveCreationInfo;
+}
+
+
+/**
+ * Request to the wallet for the status of processing a tip.
+ */
address@hidden()
+export class TipStatusRequest {
+  /**
+   * Identifier of the tip.
+   */
+  @Checkable.String
+  tipId: string;
+
+  /**
+   * Merchant domain.  Within each merchant domain, the tip identifier
+   * uniquely identifies a tip.
+   */
+  @Checkable.String
+  merchantDomain: string;
+
+  /**
+   * Create a TipStatusRequest from untyped JSON.
+   */
+  static checked: (obj: any) => TipStatusRequest;
+}
+
+/**
+ * Request to the wallet to accept a tip.
+ */
address@hidden()
+export class AcceptTipRequest {
+  /**
+   * Identifier of the tip.
+   */
+  @Checkable.String
+  tipId: string;
+
+  /**
+   * Merchant domain.  Within each merchant domain, the tip identifier
+   * uniquely identifies a tip.
+   */
+  @Checkable.String
+  merchantDomain: string;
+
+  /**
+   * Create an AcceptTipRequest from untyped JSON.
+   * Validates the schema and throws on error.
+   */
+  static checked: (obj: any) => AcceptTipRequest;
+}
+
+
+/**
+ * Request for the wallet to process a tip response from a merchant.
+ */
address@hidden()
+export class ProcessTipResponseRequest {
+  /**
+   * Identifier of the tip.
+   */
+  @Checkable.String
+  tipId: string;
+
+  /**
+   * Merchant domain.  Within each merchant domain, the tip identifier
+   * uniquely identifies a tip.
+   */
+  @Checkable.String
+  merchantDomain: string;
+
+  /**
+   * Tip response from the merchant.
+   */
+  @Checkable.Value(TipResponse)
+  tipResponse: TipResponse;
+
+  /**
+   * Create an AcceptTipRequest from untyped JSON.
+   * Validates the schema and throws on error.
+   */
+  static checked: (obj: any) => ProcessTipResponseRequest;
+}
+
+
+/**
+ * Request for the wallet to generate tip planchets.
+ */
address@hidden()
+export class GetTipPlanchetsRequest {
+  /**
+   * Identifier of the tip.
+   */
+  @Checkable.String
+  tipId: string;
+
+  /**
+   * Merchant domain.  Within each merchant domain, the tip identifier
+   * uniquely identifies a tip.
+   */
+  @Checkable.String
+  merchantDomain: string;
+
+  /**
+   * Amount of the tip.
+   */
+  @Checkable.Optional(Checkable.Value(AmountJson))
+  amount: AmountJson;
+
+  /**
+   * Deadline for picking up the tip.
+   */
+  @Checkable.Number
+  deadline: number;
+
+  /**
+   * Exchange URL that must be used to pick up the tip.
+   */
+  @Checkable.String
+  exchangeUrl: string;
+
+  /**
+   * URL to nagivate to after processing the tip.
+   */
+  @Checkable.String
+  nextUrl: string;
+
+  /**
+   * Create an AcceptTipRequest from untyped JSON.
+   * Validates the schema and throws on error.
+   */
+  static checked: (obj: any) => GetTipPlanchetsRequest;
+}
diff --git a/src/webex/messages.ts b/src/webex/messages.ts
index 44c9f166..0d032980 100644
--- a/src/webex/messages.ts
+++ b/src/webex/messages.ts
@@ -21,7 +21,10 @@
 // Messages are already documented in wxApi.
 /* tslint:disable:completed-docs */
 
-import * as types from "../types";
+import { AmountJson } from "../amounts";
+import * as dbTypes from "../dbTypes";
+import * as talerTypes from "../talerTypes";
+import * as walletTypes from "../walletTypes";
 
 /**
  * Message type information.
@@ -29,7 +32,7 @@ import * as types from "../types";
 export interface MessageMap {
   "balances": {
     request: { };
-    response: types.WalletBalance;
+    response: walletTypes.WalletBalance;
   };
   "dump-db": {
     request: { };
@@ -55,7 +58,7 @@ export interface MessageMap {
   };
   "create-reserve": {
     request: {
-      amount: types.AmountJson;
+      amount: AmountJson;
       exchange: string
     };
     response: void;
@@ -70,11 +73,11 @@ export interface MessageMap {
   };
   "confirm-pay": {
     request: { proposalId: number; };
-    response: types.ConfirmPayResult;
+    response: walletTypes.ConfirmPayResult;
   };
   "check-pay": {
     request: { proposalId: number; };
-    response: types.CheckPayResult;
+    response: walletTypes.CheckPayResult;
   };
   "query-payment": {
     request: { };
@@ -82,31 +85,31 @@ export interface MessageMap {
   };
   "exchange-info": {
     request: { baseUrl: string };
-    response: types.ExchangeRecord;
+    response: dbTypes.ExchangeRecord;
   };
   "currency-info": {
     request: { name: string };
-    response: types.CurrencyRecord;
+    response: dbTypes.CurrencyRecord;
   };
   "hash-contract": {
     request: { contract: object };
     response: string;
   };
   "save-proposal": {
-    request: { proposal: types.ProposalRecord };
+    request: { proposal: dbTypes.ProposalRecord };
     response: void;
   };
   "reserve-creation-info": {
-    request: { baseUrl: string, amount: types.AmountJson };
-    response: types.ReserveCreationInfo;
+    request: { baseUrl: string, amount: AmountJson };
+    response: walletTypes.ReserveCreationInfo;
   };
   "get-history": {
     request: { };
-    response: types.HistoryRecord[];
+    response: walletTypes.HistoryRecord[];
   };
   "get-proposal": {
     request: { proposalId: number };
-    response: types.ProposalRecord | undefined;
+    response: dbTypes.ProposalRecord | undefined;
   };
   "get-coins": {
     request: { exchangeBaseUrl: string };
@@ -118,23 +121,23 @@ export interface MessageMap {
   };
   "get-currencies": {
     request: { };
-    response: types.CurrencyRecord[];
+    response: dbTypes.CurrencyRecord[];
   };
   "update-currency": {
-    request: { currencyRecord: types.CurrencyRecord };
+    request: { currencyRecord: dbTypes.CurrencyRecord };
     response: void;
   };
   "get-exchanges": {
     request: { };
-    response: types.ExchangeRecord[];
+    response: dbTypes.ExchangeRecord[];
   };
   "get-reserves": {
     request: { exchangeBaseUrl: string };
-    response: types.ReserveRecord[];
+    response: dbTypes.ReserveRecord[];
   };
   "get-payback-reserves": {
     request: { };
-    response: types.ReserveRecord[];
+    response: dbTypes.ReserveRecord[];
   };
   "withdraw-payback-reserve": {
     request: { reservePub: string };
@@ -142,11 +145,11 @@ export interface MessageMap {
   };
   "get-precoins": {
     request: { exchangeBaseUrl: string };
-    response: types.PreCoinRecord[];
+    response: dbTypes.PreCoinRecord[];
   };
   "get-denoms": {
     request: { exchangeBaseUrl: string };
-    response: types.DenominationRecord[];
+    response: dbTypes.DenominationRecord[];
   };
   "payback-coin": {
     request: { coinPub: string };
@@ -189,23 +192,23 @@ export interface MessageMap {
     response: void;
   };
   "get-full-refund-fees": {
-    request: { refundPermissions: types.RefundPermission[] };
+    request: { refundPermissions: talerTypes.RefundPermission[] };
     response: void;
   };
   "get-tip-planchets": {
-    request: types.GetTipPlanchetsRequest;
+    request: walletTypes.GetTipPlanchetsRequest;
     response: void;
   };
   "process-tip-response": {
-    request: types.ProcessTipResponseRequest;
+    request: walletTypes.ProcessTipResponseRequest;
     response: void;
   };
   "accept-tip": {
-    request: types.AcceptTipRequest;
+    request: walletTypes.AcceptTipRequest;
     response: void;
   };
   "get-tip-status": {
-    request: types.TipStatusRequest;
+    request: walletTypes.TipStatusRequest;
     response: void;
   };
   "clear-notification": {
diff --git a/src/webex/notify.ts b/src/webex/notify.ts
index 05883e8b..1a447c0a 100644
--- a/src/webex/notify.ts
+++ b/src/webex/notify.ts
@@ -29,7 +29,8 @@ import URI = require("urijs");
 import wxApi = require("./wxApi");
 
 import { getTalerStampSec } from "../helpers";
-import { TipToken, QueryPaymentResult } from "../types";
+import { TipToken } from "../talerTypes";
+import { QueryPaymentResult } from "../walletTypes";
 
 
 import axios from "axios";
@@ -272,7 +273,12 @@ function talerPay(msg: any): Promise<any> {
       const merchantDomain = new URI(document.location.href).origin();
       let walletResp;
       try {
-        walletResp = await wxApi.getTipPlanchets(merchantDomain, 
tipToken.tip_id, tipToken.amount, deadlineSec, tipToken.exchange_url, 
tipToken.next_url);
+        walletResp = await wxApi.getTipPlanchets(merchantDomain,
+                                                 tipToken.tip_id,
+                                                 tipToken.amount,
+                                                 deadlineSec,
+                                                 tipToken.exchange_url,
+                                                 tipToken.next_url);
       } catch (e) {
         wxApi.logAndDisplayError({
           message: e.message,
@@ -283,12 +289,12 @@ function talerPay(msg: any): Promise<any> {
         throw e;
       }
 
-      let planchets = walletResp;
+      const planchets = walletResp;
 
       if (!planchets) {
         wxApi.logAndDisplayError({
-          message: "processing tip failed",
           detail: walletResp,
+          message: "processing tip failed",
           name: "tipping-failed",
           sameTab: true,
         });
diff --git a/src/webex/pages/add-auditor.tsx b/src/webex/pages/add-auditor.tsx
index 4b898b13..1ab6fdf9 100644
--- a/src/webex/pages/add-auditor.tsx
+++ b/src/webex/pages/add-auditor.tsx
@@ -23,7 +23,7 @@
 
 import {
   CurrencyRecord,
-} from "../../types";
+} from "../../dbTypes";
 
 import { ImplicitStateComponent, StateHolder } from "../components";
 import {
diff --git a/src/webex/pages/auditors.tsx b/src/webex/pages/auditors.tsx
index 9d57218a..276a7e8e 100644
--- a/src/webex/pages/auditors.tsx
+++ b/src/webex/pages/auditors.tsx
@@ -25,7 +25,7 @@ import {
   AuditorRecord,
   CurrencyRecord,
   ExchangeForCurrencyRecord,
-} from "../../types";
+} from "../../dbTypes";
 
 import {
   getCurrencies,
diff --git a/src/webex/pages/confirm-contract.tsx 
b/src/webex/pages/confirm-contract.tsx
index e41b0a1d..83de738b 100644
--- a/src/webex/pages/confirm-contract.tsx
+++ b/src/webex/pages/confirm-contract.tsx
@@ -24,12 +24,15 @@
  * Imports.
  */
 import * as i18n from "../../i18n";
+
 import {
-  CheckPayResult,
-  ContractTerms,
   ExchangeRecord,
   ProposalRecord,
-} from "../../types";
+} from "../../dbTypes";
+import { ContractTerms } from "../../talerTypes";
+import {
+  CheckPayResult,
+} from "../../walletTypes";
 
 import { renderAmount } from "../renderHtml";
 import * as wxApi from "../wxApi";
diff --git a/src/webex/pages/confirm-create-reserve.tsx 
b/src/webex/pages/confirm-create-reserve.tsx
index 48bcd97c..903975c6 100644
--- a/src/webex/pages/confirm-create-reserve.tsx
+++ b/src/webex/pages/confirm-create-reserve.tsx
@@ -24,13 +24,17 @@
 
 import { canonicalizeBaseUrl } from "../../helpers";
 import * as i18n from "../../i18n";
+
+import { AmountJson } from "../../amounts";
+import * as Amounts from "../../amounts";
+
 import {
-  AmountJson,
-  Amounts,
-  CreateReserveResponse,
   CurrencyRecord,
+} from "../../dbTypes";
+import {
+  CreateReserveResponse,
   ReserveCreationInfo,
-} from "../../types";
+} from "../../walletTypes";
 
 import { ImplicitStateComponent, StateHolder } from "../components";
 import {
@@ -40,7 +44,10 @@ import {
   getReserveCreationInfo,
 } from "../wxApi";
 
-import { renderAmount, WithdrawDetailView } from "../renderHtml";
+import {
+  WithdrawDetailView,
+  renderAmount,
+} from "../renderHtml";
 
 import * as React from "react";
 import * as ReactDOM from "react-dom";
@@ -78,8 +85,6 @@ class EventTrigger {
 }
 
 
-
-
 interface ExchangeSelectionProps {
   suggestedExchangeUrl: string;
   amount: AmountJson;
@@ -273,7 +278,8 @@ class ExchangeSelection extends 
ImplicitStateComponent<ExchangeSelectionProps> {
     if (rci.versionMatch.currentCmp === -1) {
       return (
         <p className="errorbox">
-          Your wallet (protocol version <span>{rci.walletVersion}</span>) 
might be outdated.  The exchange has a higher, incompatible
+          Your wallet (protocol version <span>{rci.walletVersion}</span>) 
might be outdated.<span> </span>
+          The exchange has a higher, incompatible
           protocol version (<span>{rci.exchangeVersion}</span>).
         </p>
       );
@@ -281,7 +287,8 @@ class ExchangeSelection extends 
ImplicitStateComponent<ExchangeSelectionProps> {
     if (rci.versionMatch.currentCmp === 1) {
       return (
         <p className="errorbox">
-          The chosen exchange (protocol version 
<span>{rci.exchangeVersion}</span> might be outdated.  The exchange has a 
lower, incompatible
+          The chosen exchange (protocol version 
<span>{rci.exchangeVersion}</span> might be outdated.<span> </span>
+          The exchange has a lower, incompatible
           protocol version than your wallet (protocol version 
<span>{rci.walletVersion}</span>).
         </p>
       );
@@ -429,8 +436,8 @@ class ExchangeSelection extends 
ImplicitStateComponent<ExchangeSelectionProps> {
         amount_fraction: amount.fraction,
         amount_value: amount.value,
         exchange: resp.exchange,
-        reserve_pub: resp.reservePub,
         exchange_wire_details: JSON.stringify(filteredWireDetails),
+        reserve_pub: resp.reservePub,
       };
       const url = new URI(callback_url).addQuery(q);
       if (!url.is("absolute")) {
diff --git a/src/webex/pages/payback.tsx b/src/webex/pages/payback.tsx
index a380a33d..f69a3349 100644
--- a/src/webex/pages/payback.tsx
+++ b/src/webex/pages/payback.tsx
@@ -26,7 +26,7 @@
  */
 import {
   ReserveRecord,
-} from "../../types";
+} from "../../dbTypes";
 
 import { ImplicitStateComponent, StateHolder } from "../components";
 import { renderAmount } from "../renderHtml";
diff --git a/src/webex/pages/popup.tsx b/src/webex/pages/popup.tsx
index ded430d2..134ee6de 100644
--- a/src/webex/pages/popup.tsx
+++ b/src/webex/pages/popup.tsx
@@ -26,13 +26,15 @@
  * Imports.
  */
 import * as i18n from "../../i18n";
+
+import { AmountJson } from "../../amounts";
+import * as Amounts from "../../amounts";
+
 import {
-  AmountJson,
-  Amounts,
   HistoryRecord,
   WalletBalance,
   WalletBalanceEntry,
-} from "../../types";
+} from "../../walletTypes";
 
 import { abbrev, renderAmount } from "../renderHtml";
 import * as wxApi from "../wxApi";
@@ -407,7 +409,8 @@ function formatHistoryItem(historyItem: HistoryRecord) {
       const url = tipPageUrl.query(params).href();
       return (
         <i18n.Translate wrap="p">
-          Merchant <span>{d.merchantDomain}</span> gave a <a href={url} 
onClick={openTab(url)}> tip</a> of <span>{renderAmount(d.amount)}</span>.
+          Merchant <span>{d.merchantDomain}</span> gave
+          a <a href={url} onClick={openTab(url)}> tip</a> of 
<span>{renderAmount(d.amount)}</span>.
           <span> </span>
           { d.accepted ? null : <span>You did not accept the tip yet.</span> }
         </i18n.Translate>
diff --git a/src/webex/pages/refund.tsx b/src/webex/pages/refund.tsx
index e76fdfff..3e82f366 100644
--- a/src/webex/pages/refund.tsx
+++ b/src/webex/pages/refund.tsx
@@ -26,7 +26,10 @@ import * as React from "react";
 import * as ReactDOM from "react-dom";
 import URI = require("urijs");
 
-import * as types from "../../types";
+import * as dbTypes from "../../dbTypes";
+
+import { AmountJson } from "../../amounts";
+import * as Amounts from "../../amounts";
 
 import { AmountDisplay } from "../renderHtml";
 import * as wxApi from "../wxApi";
@@ -36,14 +39,14 @@ interface RefundStatusViewProps {
 }
 
 interface RefundStatusViewState {
-  purchase?: types.PurchaseRecord;
-  refundFees?: types.AmountJson;
+  purchase?: dbTypes.PurchaseRecord;
+  refundFees?: AmountJson;
   gotResult: boolean;
 }
 
 interface RefundDetailProps {
-  purchase: types.PurchaseRecord;
-  fullRefundFees: types.AmountJson;
+  purchase: dbTypes.PurchaseRecord;
+  fullRefundFees: AmountJson;
 }
 
 const RefundDetail = ({purchase, fullRefundFees}: RefundDetailProps) => {
@@ -59,13 +62,13 @@ const RefundDetail = ({purchase, fullRefundFees}: 
RefundDetailProps) => {
     throw Error("invariant");
   }
 
-  let amountPending = types.Amounts.getZero(currency);
+  let amountPending = Amounts.getZero(currency);
   for (const k of pendingKeys) {
-    amountPending = types.Amounts.add(amountPending, 
purchase.refundsPending[k].refund_amount).amount;
+    amountPending = Amounts.add(amountPending, 
purchase.refundsPending[k].refund_amount).amount;
   }
-  let amountDone = types.Amounts.getZero(currency);
+  let amountDone = Amounts.getZero(currency);
   for (const k of doneKeys) {
-    amountDone = types.Amounts.add(amountDone, 
purchase.refundsDone[k].refund_amount).amount;
+    amountDone = Amounts.add(amountDone, 
purchase.refundsDone[k].refund_amount).amount;
   }
 
   const hasPending = amountPending.fraction !== 0 || amountPending.value !== 0;
diff --git a/src/webex/pages/return-coins.tsx b/src/webex/pages/return-coins.tsx
index 5bcb2252..26db52ef 100644
--- a/src/webex/pages/return-coins.tsx
+++ b/src/webex/pages/return-coins.tsx
@@ -25,12 +25,13 @@
  * Imports.
  */
 
+import { AmountJson } from "../../amounts";
+import * as Amounts from "../../amounts";
+
 import {
-  AmountJson,
-  Amounts,
   SenderWireInfos,
   WalletBalance,
-} from "../../types";
+} from "../../walletTypes";
 
 import * as i18n from "../../i18n";
 
diff --git a/src/webex/pages/tip.tsx b/src/webex/pages/tip.tsx
index 678c0dfd..7f96401c 100644
--- a/src/webex/pages/tip.tsx
+++ b/src/webex/pages/tip.tsx
@@ -33,9 +33,13 @@ import {
   getTipStatus,
 } from "../wxApi";
 
-import { renderAmount, WithdrawDetailView } from "../renderHtml";
+import {
+  WithdrawDetailView,
+  renderAmount,
+} from "../renderHtml";
 
-import { Amounts, TipStatus } from "../../types";
+import * as Amounts from "../../amounts";
+import { TipStatus } from "../../walletTypes";
 
 interface TipDisplayProps {
   merchantDomain: string;
@@ -54,7 +58,7 @@ class TipDisplay extends React.Component<TipDisplayProps, 
TipDisplayState> {
   }
 
   async update() {
-    let tipStatus = await getTipStatus(this.props.merchantDomain, 
this.props.tipId);
+    const tipStatus = await getTipStatus(this.props.merchantDomain, 
this.props.tipId);
     this.setState({ tipStatus });
   }
 
@@ -73,7 +77,7 @@ class TipDisplay extends React.Component<TipDisplayProps, 
TipDisplayState> {
   renderExchangeInfo(ts: TipStatus) {
     const rci = ts.rci;
     if (!rci) {
-      return <p>Waiting for info about exchange ...</p>
+      return <p>Waiting for info about exchange ...</p>;
     }
     const totalCost = Amounts.add(rci.overhead, rci.withdrawFee).amount;
     return (
@@ -102,7 +106,9 @@ class TipDisplay extends React.Component<TipDisplayProps, 
TipDisplayState> {
             className="pure-button pure-button-primary"
             type="button"
             onClick={() => this.accept()}>
-          { this.state.working ? <span><object className="svg-icon 
svg-baseline" data="/img/spinner-bars.svg" /> </span> : null }
+          { this.state.working
+            ? <span><object className="svg-icon svg-baseline" 
data="/img/spinner-bars.svg" /> </span>
+            : null }
           Accept tip
         </button>
         {" "}
@@ -119,7 +125,8 @@ class TipDisplay extends React.Component<TipDisplayProps, 
TipDisplayState> {
     return (
       <div>
         <h2>Tip Received!</h2>
-        <p>You received a tip of 
<strong>{renderAmount(ts.tip.amount)}</strong> from 
<strong>{this.props.merchantDomain}</strong>.</p>
+        <p>You received a tip of 
<strong>{renderAmount(ts.tip.amount)}</strong> from <span> </span>
+        <strong>{this.props.merchantDomain}</strong>.</p>
         {ts.tip.accepted
           ? <p>You've accepted this tip! <a href={ts.tip.nextUrl}>Go back to 
merchant</a></p>
           : this.renderButtons()
@@ -134,10 +141,10 @@ async function main() {
   try {
     const url = new URI(document.location.href);
     const query: any = URI.parseQuery(url.query());
-  
-    let merchantDomain = query.merchant_domain;
-    let tipId = query.tip_id;
-    let props: TipDisplayProps = { tipId, merchantDomain };
+
+    const merchantDomain = query.merchant_domain;
+    const tipId = query.tip_id;
+    const props: TipDisplayProps = { tipId, merchantDomain };
 
     ReactDOM.render(<TipDisplay {...props} />,
                     document.getElementById("container")!);
diff --git a/src/webex/pages/tree.tsx b/src/webex/pages/tree.tsx
index 2ac0b863..67e58a1d 100644
--- a/src/webex/pages/tree.tsx
+++ b/src/webex/pages/tree.tsx
@@ -22,6 +22,7 @@
 
 
 import { getTalerStampDate } from "../../helpers";
+
 import {
   CoinRecord,
   CoinStatus,
@@ -29,7 +30,7 @@ import {
   ExchangeRecord,
   PreCoinRecord,
   ReserveRecord,
-} from "../../types";
+} from "../../dbTypes";
 
 import { ImplicitStateComponent, StateHolder } from "../components";
 import {
diff --git a/src/webex/renderHtml.tsx b/src/webex/renderHtml.tsx
index d225cef0..2e21932b 100644
--- a/src/webex/renderHtml.tsx
+++ b/src/webex/renderHtml.tsx
@@ -24,12 +24,16 @@
 /**
  * Imports.
  */
+import { AmountJson } from "../amounts";
+import * as Amounts from "../amounts";
+
 import {
-  AmountJson,
-  Amounts,
   DenominationRecord,
+} from "../dbTypes";
+import {
   ReserveCreationInfo,
-} from "../types";
+} from "../walletTypes";
+
 
 import { ImplicitStateComponent } from "./components";
 
@@ -239,7 +243,9 @@ function FeeDetailsView(props: {rci: 
ReserveCreationInfo|null}): JSX.Element {
   );
 }
 
-
+/**
+ * Shows details about a withdraw request.
+ */
 export function WithdrawDetailView(props: {rci: ReserveCreationInfo | null}): 
JSX.Element {
   const rci = props.rci;
   return (
@@ -259,6 +265,9 @@ interface ExpanderTextProps {
   text: string;
 }
 
+/**
+ * Show a heading with a toggle to show/hide the expandable content.
+ */
 export class ExpanderText extends ImplicitStateComponent<ExpanderTextProps> {
   private expanded = this.makeState<boolean>(false);
   private textArea: any = undefined;
diff --git a/src/webex/wxApi.ts b/src/webex/wxApi.ts
index 2575eec9..2f7a13c4 100644
--- a/src/webex/wxApi.ts
+++ b/src/webex/wxApi.ts
@@ -22,26 +22,31 @@
 /**
  * Imports.
  */
+import { AmountJson } from "../amounts";
 import {
-  AmountJson,
-  CheckPayResult,
   CoinRecord,
-  ConfirmPayResult,
   CurrencyRecord,
   DenominationRecord,
   ExchangeRecord,
   PreCoinRecord,
   PurchaseRecord,
+  ReserveRecord,
+} from "../dbTypes";
+import {
+  CheckPayResult,
+  ConfirmPayResult,
   QueryPaymentResult,
-  RefundPermission,
   ReserveCreationInfo,
-  ReserveRecord,
   SenderWireInfos,
-  TipResponse,
-  TipPlanchetDetail,
   TipStatus,
   WalletBalance,
-} from "../types";
+} from "../walletTypes";
+
+import {
+  RefundPermission,
+  TipPlanchetDetail,
+  TipResponse,
+} from "../talerTypes";
 
 import { MessageMap, MessageType } from "./messages";
 
@@ -366,22 +371,39 @@ export function getFullRefundFees(args: { 
refundPermissions: RefundPermission[]
 /**
  * Get or generate planchets to give the merchant that wants to tip us.
  */
-export function getTipPlanchets(merchantDomain: string, tipId: string, amount: 
AmountJson, deadline: number, exchangeUrl: string, nextUrl: string): 
Promise<TipPlanchetDetail[]> {
+export function getTipPlanchets(merchantDomain: string,
+                                tipId: string,
+                                amount: AmountJson,
+                                deadline: number,
+                                exchangeUrl: string,
+                                nextUrl: string): Promise<TipPlanchetDetail[]> 
{
   return callBackend("get-tip-planchets", { merchantDomain, tipId, amount, 
deadline, exchangeUrl, nextUrl });
 }
 
+/**
+ * Get the status of processing a tip.
+ */
 export function getTipStatus(merchantDomain: string, tipId: string): 
Promise<TipStatus> {
   return callBackend("get-tip-status", { merchantDomain, tipId });
 }
 
+/**
+ * Mark a tip as accepted by the user.
+ */
 export function acceptTip(merchantDomain: string, tipId: string): 
Promise<TipStatus> {
   return callBackend("accept-tip", { merchantDomain, tipId });
 }
 
+/**
+ * Process a response from the merchant for a tip request.
+ */
 export function processTipResponse(merchantDomain: string, tipId: string, 
tipResponse: TipResponse): Promise<void> {
   return callBackend("process-tip-response", { merchantDomain, tipId, 
tipResponse });
 }
 
+/**
+ * Clear notifications that the wallet shows to the user.
+ */
 export function clearNotification(): Promise<void> {
   return callBackend("clear-notification", { });
 }
diff --git a/src/webex/wxBackend.ts b/src/webex/wxBackend.ts
index 213d234d..a8ce5eeb 100644
--- a/src/webex/wxBackend.ts
+++ b/src/webex/wxBackend.ts
@@ -30,18 +30,21 @@ import {
   Index,
   Store,
 } from "../query";
+
+import { AmountJson } from "../amounts";
+
+import { ProposalRecord } from "../dbTypes";
 import {
   AcceptTipRequest,
-  AmountJson,
   ConfirmReserveRequest,
   CreateReserveRequest,
   GetTipPlanchetsRequest,
   Notifier,
   ProcessTipResponseRequest,
-  ProposalRecord,
   ReturnCoinsRequest,
   TipStatusRequest,
-} from "../types";
+} from "../walletTypes";
+
 import {
   Stores,
   WALLET_DB_VERSION,
@@ -335,7 +338,12 @@ function handleMessage(sender: MessageSender,
     }
     case "get-tip-planchets": {
       const req = GetTipPlanchetsRequest.checked(detail);
-      return needsWallet().getTipPlanchets(req.merchantDomain, req.tipId, 
req.amount, req.deadline, req.exchangeUrl, req.nextUrl);
+      return needsWallet().getTipPlanchets(req.merchantDomain,
+                                           req.tipId,
+                                           req.amount,
+                                           req.deadline,
+                                           req.exchangeUrl,
+                                           req.nextUrl);
     }
     case "clear-notification": {
       return needsWallet().clearNotification();
@@ -702,11 +710,10 @@ export async function wxMain() {
   });
 
 
-
   // Clear notifications both when the popop opens,
   // as well when it closes.
   chrome.runtime.onConnect.addListener((port) => {
-    if (port.name == "popup") {
+    if (port.name === "popup") {
       if (currentWallet) {
         currentWallet.clearNotification();
       }
diff --git a/tooling/pogen/dumpTree.ts b/tooling/pogen/dumpTree.ts
index 958c7941..af25caf3 100644
--- a/tooling/pogen/dumpTree.ts
+++ b/tooling/pogen/dumpTree.ts
@@ -21,12 +21,10 @@
  * @author Florian Dold
  */
 
-/// <reference path="../decl/node.d.ts" />
-
 "use strict";
 
-import {readFileSync} from "fs";
-import {execSync} from "child_process";
+import { readFileSync } from "fs";
+import { execSync } from "child_process";
 import * as ts from "typescript";
 
 
diff --git a/tsconfig.json b/tsconfig.json
index d2a7f552..ae77fb27 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,4 +1,5 @@
 {
+  "compileOnSave": true,
   "compilerOptions": {
     "target": "es6",
     "jsx": "react",
@@ -7,8 +8,8 @@
     "module": "commonjs",
     "sourceMap": true,
     "lib": [
-      "ES6",
-      "DOM"
+      "es6",
+      "dom"
     ],
     "noImplicitReturns": true,
     "noFallthroughCasesInSwitch": true,
@@ -23,6 +24,7 @@
     "decl/chrome/chrome.d.ts",
     "decl/jed.d.ts",
     "decl/urijs.d.ts",
+    "src/amounts.ts",
     "src/checkable.ts",
     "src/crypto/cryptoApi-test.ts",
     "src/crypto/cryptoApi.ts",
@@ -34,6 +36,7 @@
     "src/crypto/nodeWorker.ts",
     "src/crypto/nodeWorkerEntry.ts",
     "src/crypto/startWorker.js",
+    "src/dbTypes.ts",
     "src/helpers-test.ts",
     "src/helpers.ts",
     "src/http.ts",
@@ -42,18 +45,13 @@
     "src/libtoolVersion-test.ts",
     "src/libtoolVersion.ts",
     "src/logging.ts",
-    "src/memidb/aatree-test.ts",
-    "src/memidb/aatree.ts",
-    "src/memidb/memidb-test.ts",
-    "src/memidb/memidb.ts",
-    "src/memidb/w3c-wpt/abort-in-initial-upgradeneeded-test.ts",
-    "src/memidb/w3c-wpt/support.ts",
     "src/query.ts",
+    "src/talerTypes.ts",
     "src/timer.ts",
     "src/types-test.ts",
-    "src/types.ts",
     "src/wallet-test.ts",
     "src/wallet.ts",
+    "src/walletTypes.ts",
     "src/webex/background.ts",
     "src/webex/chromeBadge.ts",
     "src/webex/components.ts",
diff --git a/tslint.json b/tslint.json
index fbd1975b..a56b56a9 100644
--- a/tslint.json
+++ b/tslint.json
@@ -5,6 +5,7 @@
     ],
     "jsRules": {},
     "rules": {
+      "arrow-parens": false,
       "max-line-length": {
         "options": [120]
       },

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]