gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [taler-wallet-webex] branch master updated (fd2cd9c3 -> 202


From: gnunet
Subject: [GNUnet-SVN] [taler-wallet-webex] branch master updated (fd2cd9c3 -> 202d51c6)
Date: Thu, 04 Jan 2018 11:35:11 +0100

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

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

    from fd2cd9c3 fix lint issues and separate message types into multiple files
     new 02b4a2ad store sender wire info in separate store
     new 202d51c6 refactor / put some types where they belong

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/dbTypes.ts                   | 275 +++++++++++++++++++++------
 src/helpers.ts                   |  31 +++
 src/i18n/de.po                   | 113 +++++------
 src/i18n/en-US.po                | 113 +++++------
 src/i18n/fr.po                   | 113 +++++------
 src/i18n/it.po                   | 113 +++++------
 src/i18n/strings.ts              |   8 +-
 src/i18n/taler-wallet-webex.pot  | 113 +++++------
 src/talerTypes.ts                | 153 +++++++++++++++
 src/wallet.ts                    | 394 +++------------------------------------
 src/walletTypes.ts               |  28 ++-
 src/webex/chromeBadge.ts         |   2 +-
 src/webex/pages/return-coins.tsx |   2 +-
 src/webex/wxBackend.ts           |   7 +-
 14 files changed, 749 insertions(+), 716 deletions(-)

diff --git a/src/dbTypes.ts b/src/dbTypes.ts
index e0adb6fc..b5040bee 100644
--- a/src/dbTypes.ts
+++ b/src/dbTypes.ts
@@ -34,8 +34,23 @@ import {
   PayReq,
   RefundPermission,
   TipResponse,
+  WireDetail,
 } from "./talerTypes";
 
+import {
+  Index,
+  Store,
+} from "./query";
+
+
+/**
+ * Current database version, should be incremented
+ * each time we do incompatible schema changes on the database.
+ * In the future we might consider adding migration functions for
+ * each version increment.
+ */
+export const WALLET_DB_VERSION = 24;
+
 
 /**
  * A reserve record as stored in the wallet's database.
@@ -377,60 +392,6 @@ export interface RefreshPreCoinRecord {
 
 
 /**
- * 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 {
@@ -809,3 +770,209 @@ export interface PurchaseRecord {
    */
   timestamp_refund: number;
 }
+
+
+/**
+ * Information about wire information for bank accounts we withdrew coins from.
+ */
+export interface SenderWireRecord {
+  /**
+   * Wire details.
+   */
+  senderWire: WireDetail;
+
+  /**
+   * Identifier, hash code of canonicalized senderWire.
+   */
+  id: number;
+}
+
+
+/**
+ * Nonce record as stored in the wallet's database.
+ */
+export interface NonceRecord {
+  priv: string;
+  pub: string;
+}
+
+
+/**
+ * Configuration key/value entries to configure
+ * the wallet.
+ */
+export interface ConfigRecord {
+  key: string;
+  value: any;
+}
+
+
+/**
+ * Coin that we're depositing ourselves.
+ */
+export interface DepositCoin {
+  coinPaySig: CoinPaySig;
+
+  /**
+   * Undefined if coin not deposited, otherwise signature
+   * from the exchange confirming the deposit.
+   */
+  depositedSig?: string;
+}
+
+
+/**
+ * Record stored in the wallet's database when the user sends coins back to
+ * their own bank account.  Stores the status of coins that are deposited to
+ * the wallet itself, where the wallet acts as a "merchant" for the customer.
+ */
+export interface CoinsReturnRecord {
+  /**
+   * Hash of the contract for sending coins to our own bank account.
+   */
+  contractTermsHash: string;
+
+  contractTerms: ContractTerms;
+
+  /**
+   * Private key where corresponding
+   * public key is used in the contract terms
+   * as merchant pub.
+   */
+  merchantPriv: string;
+
+  coins: DepositCoin[];
+
+  /**
+   * Exchange base URL to deposit coins at.
+   */
+  exchange: string;
+
+  /**
+   * Our own wire information for the deposit.
+   */
+  wire: any;
+}
+
+
+/* tslint:disable:completed-docs */
+
+/**
+ * The stores and indices for the wallet database.
+ */
+export namespace Stores {
+  class ExchangeStore extends Store<ExchangeRecord> {
+    constructor() {
+      super("exchanges", { keyPath: "baseUrl" });
+    }
+
+    pubKeyIndex = new Index<string, ExchangeRecord>(this, "pubKeyIndex", 
"masterPublicKey");
+  }
+
+  class NonceStore extends Store<NonceRecord> {
+    constructor() {
+      super("nonces", { keyPath: "pub" });
+    }
+  }
+
+  class CoinsStore extends Store<CoinRecord> {
+    constructor() {
+      super("coins", { keyPath: "coinPub" });
+    }
+
+    exchangeBaseUrlIndex = new Index<string, CoinRecord>(this, 
"exchangeBaseUrl", "exchangeBaseUrl");
+    denomPubIndex = new Index<string, CoinRecord>(this, "denomPubIndex", 
"denomPub");
+  }
+
+  class ProposalsStore extends Store<ProposalRecord> {
+    constructor() {
+      super("proposals", {
+        autoIncrement: true,
+        keyPath: "id",
+      });
+    }
+    timestampIndex = new Index<string, ProposalRecord>(this, "timestampIndex", 
"timestamp");
+  }
+
+  class PurchasesStore extends Store<PurchaseRecord> {
+    constructor() {
+      super("purchases", { keyPath: "contractTermsHash" });
+    }
+
+    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");
+  }
+
+  class DenominationsStore extends Store<DenominationRecord> {
+    constructor() {
+      // cast needed because of bug in type annotations
+      super("denominations",
+            {keyPath: ["exchangeBaseUrl", "denomPub"] as any as IDBKeyPath});
+    }
+
+    denomPubHashIndex = new Index<string, DenominationRecord>(this, 
"denomPubHashIndex", "denomPubHash");
+    exchangeBaseUrlIndex = new Index<string, DenominationRecord>(this, 
"exchangeBaseUrlIndex", "exchangeBaseUrl");
+    denomPubIndex = new Index<string, DenominationRecord>(this, 
"denomPubIndex", "denomPub");
+  }
+
+  class CurrenciesStore extends Store<CurrencyRecord> {
+    constructor() {
+      super("currencies", { keyPath: "name" });
+    }
+  }
+
+  class ConfigStore extends Store<ConfigRecord> {
+    constructor() {
+      super("config", { keyPath: "key" });
+    }
+  }
+
+  class ExchangeWireFeesStore extends Store<ExchangeWireFeesRecord> {
+    constructor() {
+      super("exchangeWireFees", { keyPath: "exchangeBaseUrl" });
+    }
+  }
+
+  class ReservesStore extends Store<ReserveRecord> {
+    constructor() {
+      super("reserves", { keyPath: "reserve_pub" });
+    }
+    timestampCreatedIndex = new Index<string, ReserveRecord>(this, 
"timestampCreatedIndex", "created");
+    timestampConfirmedIndex = new Index<string, ReserveRecord>(this, 
"timestampConfirmedIndex", "timestamp_confirmed");
+    timestampDepletedIndex = new Index<string, ReserveRecord>(this, 
"timestampDepletedIndex", "timestamp_depleted");
+  }
+
+  class TipsStore extends Store<TipRecord> {
+    constructor() {
+      super("tips", { keyPath: ["tipId", "merchantDomain"] as any as 
IDBKeyPath });
+    }
+    coinPubIndex = new Index<string, TipRecord>(this, "coinPubIndex", 
"coinPubs", { multiEntry: true });
+  }
+
+  class SenderWiresStore extends Store<SenderWireRecord> {
+    constructor() {
+      super("senderWires", { keyPath: "id" });
+    }
+  }
+
+  export const coins = new CoinsStore();
+  export const coinsReturns = new Store<CoinsReturnRecord>("coinsReturns", 
{keyPath: "contractTermsHash"});
+  export const config = new ConfigStore();
+  export const currencies = new CurrenciesStore();
+  export const denominations = new DenominationsStore();
+  export const exchangeWireFees = new ExchangeWireFeesStore();
+  export const exchanges = new ExchangeStore();
+  export const nonces = new NonceStore();
+  export const precoins = new Store<PreCoinRecord>("precoins", {keyPath: 
"coinPub"});
+  export const proposals = new ProposalsStore();
+  export const refresh = new Store<RefreshSessionRecord>("refresh", {keyPath: 
"id", autoIncrement: true});
+  export const reserves = new ReservesStore();
+  export const purchases = new PurchasesStore();
+  export const tips = new TipsStore();
+  export const senderWires = new SenderWiresStore();
+}
+
+/* tslint:enable:completed-docs */
diff --git a/src/helpers.ts b/src/helpers.ts
index d85808ac..3b7cd36f 100644
--- a/src/helpers.ts
+++ b/src/helpers.ts
@@ -138,3 +138,34 @@ export function getTalerStampDate(stamp: string): Date | 
null {
   return new Date(sec * 1000);
 }
 
+/**
+ * Compute the hash function of a JSON object.
+ */
+export function hash(val: any): number {
+  const str = canonicalJson(val);
+  // https://github.com/darkskyapp/string-hash
+  let h = 5381;
+  let i = str.length;
+  while (i) {
+    h = (h * 33) ^ str.charCodeAt(--i);
+  }
+
+  /* JavaScript does bitwise operations (like XOR, above) on 32-bit signed
+  * integers. Since we want the results to be always positive, convert the
+  * signed int to an unsigned by doing an unsigned bitshift. */
+  return h >>> 0;
+}
+
+
+/**
+ * Lexically compare two strings.
+ */
+export function strcmp(s1: string, s2: string): number {
+  if (s1 < s2) {
+    return -1;
+  }
+  if (s1 > s2) {
+    return 1;
+  }
+  return 0;
+}
diff --git a/src/i18n/de.po b/src/i18n/de.po
index 49b7ada8..21ff8dfe 100644
--- a/src/i18n/de.po
+++ b/src/i18n/de.po
@@ -27,28 +27,28 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
-#: src/webex/pages/confirm-contract.tsx:70
+#: src/webex/pages/confirm-contract.tsx:73
 #, c-format
 msgid "show more details\n"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:84
+#: src/webex/pages/confirm-contract.tsx:87
 #, c-format
 msgid "Accepted exchanges:"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:89
+#: src/webex/pages/confirm-contract.tsx:92
 #, c-format
 msgid "Exchanges in the wallet:"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:156
+#: src/webex/pages/confirm-contract.tsx:159
 #, c-format
 msgid "You have insufficient funds of the requested currency in your wallet."
 msgstr ""
 
 #. tslint:disable-next-line:max-line-length
-#: src/webex/pages/confirm-contract.tsx:158
+#: src/webex/pages/confirm-contract.tsx:161
 #, c-format
 msgid ""
 "You do not have any funds from an exchange that is accepted by this "
@@ -56,37 +56,37 @@ msgid ""
 "wallet."
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:214
+#: src/webex/pages/confirm-contract.tsx:217
 #, c-format
 msgid "The merchant%1$s offers you to purchase:\n"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:235
+#: src/webex/pages/confirm-contract.tsx:238
 #, fuzzy, c-format
 msgid "Confirm payment"
 msgstr "Bezahlung bestätigen"
 
-#: src/webex/pages/confirm-create-reserve.tsx:121
+#: src/webex/pages/confirm-create-reserve.tsx:126
 #, c-format
 msgid "Select"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:137
+#: src/webex/pages/confirm-create-reserve.tsx:142
 #, c-format
 msgid "Error: URL may not be relative"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:205
+#: src/webex/pages/confirm-create-reserve.tsx:210
 #, c-format
 msgid "The exchange is trusted by the wallet.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:211
+#: src/webex/pages/confirm-create-reserve.tsx:216
 #, c-format
 msgid "The exchange is audited by a trusted auditor.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:217
+#: src/webex/pages/confirm-create-reserve.tsx:222
 #, c-format
 msgid ""
 "Warning:  The exchange is neither directly trusted nor audited by a trusted "
@@ -94,7 +94,7 @@ msgid ""
 "If you withdraw from this exchange, it will be trusted in the future.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:226
+#: src/webex/pages/confirm-create-reserve.tsx:231
 #, c-format
 msgid ""
 "Using exchange provider%1$s.\n"
@@ -102,135 +102,135 @@ msgid ""
 " %2$s in fees.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:240
+#: src/webex/pages/confirm-create-reserve.tsx:245
 #, c-format
 msgid ""
 "Waiting for a response from\n"
 " %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:257
+#: src/webex/pages/confirm-create-reserve.tsx:262
 #, c-format
 msgid ""
 "Information about fees will be available when an exchange provider is "
 "selected."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:300
+#: src/webex/pages/confirm-create-reserve.tsx:307
 #, c-format
 msgid "Accept fees and withdraw"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:305
+#: src/webex/pages/confirm-create-reserve.tsx:312
 #, c-format
 msgid "Change Exchange Provider"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:357
+#: src/webex/pages/confirm-create-reserve.tsx:364
 #, c-format
 msgid "You are about to withdraw %1$s from your bank account into your wallet."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:442
+#: src/webex/pages/confirm-create-reserve.tsx:449
 #, c-format
 msgid ""
 "Oops, something went wrong. The wallet responded with error status (%1$s)."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:451
+#: src/webex/pages/confirm-create-reserve.tsx:458
 #, c-format
 msgid "Checking URL, please wait ..."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:465
+#: src/webex/pages/confirm-create-reserve.tsx:472
 #, c-format
 msgid "Can't parse amount: %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:472
+#: src/webex/pages/confirm-create-reserve.tsx:479
 #, c-format
 msgid "Can't parse wire_types: %1$s"
 msgstr ""
 
 #. #-#-#-#-#  - (PACKAGE VERSION)  #-#-#-#-#
 #. TODO:generic error reporting function or component.
-#: src/webex/pages/confirm-create-reserve.tsx:498 src/webex/pages/tip.tsx:148
+#: src/webex/pages/confirm-create-reserve.tsx:505 src/webex/pages/tip.tsx:155
 #, c-format
 msgid "Fatal error: \"%1$s\"."
 msgstr ""
 
-#: src/webex/pages/popup.tsx:160
+#: src/webex/pages/popup.tsx:162
 #, c-format
 msgid "Balance"
 msgstr "Saldo"
 
-#: src/webex/pages/popup.tsx:163
+#: src/webex/pages/popup.tsx:165
 #, c-format
 msgid "History"
 msgstr "Verlauf"
 
-#: src/webex/pages/popup.tsx:166
+#: src/webex/pages/popup.tsx:168
 #, c-format
 msgid "Debug"
 msgstr "Debug"
 
-#: src/webex/pages/popup.tsx:246
+#: src/webex/pages/popup.tsx:248
 #, c-format
 msgid "help"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:251
+#: src/webex/pages/popup.tsx:253
 #, fuzzy, c-format
 msgid ""
 "You have no balance to show. Need some\n"
 " %1$s getting started?\n"
 msgstr "Sie haben kein Digitalgeld. Wollen Sie %1$s? abheben?"
 
-#: src/webex/pages/popup.tsx:268
+#: src/webex/pages/popup.tsx:270
 #, c-format
 msgid "%1$s incoming\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:281
+#: src/webex/pages/popup.tsx:283
 #, c-format
 msgid "%1$s being spent\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:307
+#: src/webex/pages/popup.tsx:309
 #, c-format
 msgid "Error: could not retrieve balance information."
 msgstr ""
 
-#: src/webex/pages/popup.tsx:334
+#: src/webex/pages/popup.tsx:336
 #, c-format
 msgid "Payback"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:335
+#: src/webex/pages/popup.tsx:337
 #, c-format
 msgid "Return Electronic Cash to Bank Account"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:336
+#: src/webex/pages/popup.tsx:338
 #, c-format
 msgid "Manage Trusted Auditors and Exchanges"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:348
+#: src/webex/pages/popup.tsx:350
 #, fuzzy, c-format
 msgid ""
 "Bank requested reserve (%1$s) for\n"
 " %2$s.\n"
 msgstr "Bank bestätig anlegen der Reserve (%1$s) bei %2$s"
 
-#: src/webex/pages/popup.tsx:358
+#: src/webex/pages/popup.tsx:360
 #, fuzzy, c-format
 msgid ""
 "Started to withdraw\n"
 " %1$s%2$sfrom%3$s(%4$s).\n"
 msgstr "Reserve (%1$s) mit %2$s bei %3$s erzeugt"
 
-#: src/webex/pages/popup.tsx:367
+#: src/webex/pages/popup.tsx:369
 #, fuzzy, c-format
 msgid "Merchant%1$soffered%2$scontract%3$s.\n"
 msgstr ""
@@ -238,99 +238,100 @@ msgstr ""
 "               möchte einen Vertrag über %2$s\n"
 "               mit Ihnen abschließen."
 
-#: src/webex/pages/popup.tsx:378
+#: src/webex/pages/popup.tsx:380
 #, fuzzy, c-format
 msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
 msgstr "Reserve (%1$s) mit %2$s bei %3$s erzeugt"
 
-#: src/webex/pages/popup.tsx:388
+#: src/webex/pages/popup.tsx:390
 #, fuzzy, c-format
 msgid ""
 "Paid%1$sto merchant%2$s.\n"
 "%3$s(%4$s)\n"
 msgstr "Reserve (%1$s) mit %2$s bei %3$s erzeugt"
 
-#: src/webex/pages/popup.tsx:398
+#: src/webex/pages/popup.tsx:400
 #, c-format
 msgid "Merchant%1$sgave a refund over%2$s.\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:408
+#: src/webex/pages/popup.tsx:410
 #, fuzzy, c-format
 msgid ""
-"Merchant%1$sgave a%2$sof%3$s.\n"
+"Merchant%1$sgave\n"
+"a%2$sof%3$s.\n"
 "%4$s%5$s"
 msgstr ""
 "%1$s\n"
 "               möchte einen Vertrag über %2$s\n"
 "               mit Ihnen abschließen."
 
-#: src/webex/pages/popup.tsx:417
+#: src/webex/pages/popup.tsx:420
 #, c-format
 msgid "Unknown event (%1$s)"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:460
+#: src/webex/pages/popup.tsx:463
 #, c-format
 msgid "Error: could not retrieve event history"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:485
+#: src/webex/pages/popup.tsx:488
 #, c-format
 msgid "Your wallet has no events recorded."
 msgstr "Ihre Geldbörse verzeichnet keine Vorkommnisse."
 
-#: src/webex/pages/return-coins.tsx:104
+#: src/webex/pages/return-coins.tsx:105
 #, c-format
 msgid "Wire to bank account"
 msgstr ""
 
-#: src/webex/pages/return-coins.tsx:172
+#: src/webex/pages/return-coins.tsx:173
 #, fuzzy, c-format
 msgid "Confirm"
 msgstr "Bezahlung bestätigen"
 
-#: src/webex/pages/return-coins.tsx:175
+#: src/webex/pages/return-coins.tsx:176
 #, fuzzy, c-format
 msgid "Cancel"
 msgstr "Saldo"
 
-#: src/webex/renderHtml.tsx:212
+#: src/webex/renderHtml.tsx:216
 #, fuzzy, c-format
 msgid "Withdrawal fees:"
 msgstr "Abheben bei"
 
-#: src/webex/renderHtml.tsx:213
+#: src/webex/renderHtml.tsx:217
 #, c-format
 msgid "Rounding loss:"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:214
+#: src/webex/renderHtml.tsx:218
 #, c-format
 msgid "Earliest expiration (for deposit): %1$s"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:220
+#: src/webex/renderHtml.tsx:224
 #, c-format
 msgid "# Coins"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:221
+#: src/webex/renderHtml.tsx:225
 #, c-format
 msgid "Value"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:222
+#: src/webex/renderHtml.tsx:226
 #, fuzzy, c-format
 msgid "Withdraw Fee"
 msgstr "Abheben bei %1$s"
 
-#: src/webex/renderHtml.tsx:223
+#: src/webex/renderHtml.tsx:227
 #, c-format
 msgid "Refresh Fee"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:224
+#: src/webex/renderHtml.tsx:228
 #, c-format
 msgid "Deposit Fee"
 msgstr ""
diff --git a/src/i18n/en-US.po b/src/i18n/en-US.po
index e42d81fb..3307229b 100644
--- a/src/i18n/en-US.po
+++ b/src/i18n/en-US.po
@@ -27,28 +27,28 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
-#: src/webex/pages/confirm-contract.tsx:70
+#: src/webex/pages/confirm-contract.tsx:73
 #, c-format
 msgid "show more details\n"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:84
+#: src/webex/pages/confirm-contract.tsx:87
 #, c-format
 msgid "Accepted exchanges:"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:89
+#: src/webex/pages/confirm-contract.tsx:92
 #, c-format
 msgid "Exchanges in the wallet:"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:156
+#: src/webex/pages/confirm-contract.tsx:159
 #, c-format
 msgid "You have insufficient funds of the requested currency in your wallet."
 msgstr ""
 
 #. tslint:disable-next-line:max-line-length
-#: src/webex/pages/confirm-contract.tsx:158
+#: src/webex/pages/confirm-contract.tsx:161
 #, c-format
 msgid ""
 "You do not have any funds from an exchange that is accepted by this "
@@ -56,37 +56,37 @@ msgid ""
 "wallet."
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:214
+#: src/webex/pages/confirm-contract.tsx:217
 #, c-format
 msgid "The merchant%1$s offers you to purchase:\n"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:235
+#: src/webex/pages/confirm-contract.tsx:238
 #, c-format
 msgid "Confirm payment"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:121
+#: src/webex/pages/confirm-create-reserve.tsx:126
 #, c-format
 msgid "Select"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:137
+#: src/webex/pages/confirm-create-reserve.tsx:142
 #, c-format
 msgid "Error: URL may not be relative"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:205
+#: src/webex/pages/confirm-create-reserve.tsx:210
 #, c-format
 msgid "The exchange is trusted by the wallet.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:211
+#: src/webex/pages/confirm-create-reserve.tsx:216
 #, c-format
 msgid "The exchange is audited by a trusted auditor.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:217
+#: src/webex/pages/confirm-create-reserve.tsx:222
 #, c-format
 msgid ""
 "Warning:  The exchange is neither directly trusted nor audited by a trusted "
@@ -94,7 +94,7 @@ msgid ""
 "If you withdraw from this exchange, it will be trusted in the future.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:226
+#: src/webex/pages/confirm-create-reserve.tsx:231
 #, c-format
 msgid ""
 "Using exchange provider%1$s.\n"
@@ -102,229 +102,230 @@ msgid ""
 " %2$s in fees.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:240
+#: src/webex/pages/confirm-create-reserve.tsx:245
 #, c-format
 msgid ""
 "Waiting for a response from\n"
 " %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:257
+#: src/webex/pages/confirm-create-reserve.tsx:262
 #, c-format
 msgid ""
 "Information about fees will be available when an exchange provider is "
 "selected."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:300
+#: src/webex/pages/confirm-create-reserve.tsx:307
 #, c-format
 msgid "Accept fees and withdraw"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:305
+#: src/webex/pages/confirm-create-reserve.tsx:312
 #, c-format
 msgid "Change Exchange Provider"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:357
+#: src/webex/pages/confirm-create-reserve.tsx:364
 #, c-format
 msgid "You are about to withdraw %1$s from your bank account into your wallet."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:442
+#: src/webex/pages/confirm-create-reserve.tsx:449
 #, c-format
 msgid ""
 "Oops, something went wrong. The wallet responded with error status (%1$s)."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:451
+#: src/webex/pages/confirm-create-reserve.tsx:458
 #, c-format
 msgid "Checking URL, please wait ..."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:465
+#: src/webex/pages/confirm-create-reserve.tsx:472
 #, c-format
 msgid "Can't parse amount: %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:472
+#: src/webex/pages/confirm-create-reserve.tsx:479
 #, c-format
 msgid "Can't parse wire_types: %1$s"
 msgstr ""
 
 #. #-#-#-#-#  - (PACKAGE VERSION)  #-#-#-#-#
 #. TODO:generic error reporting function or component.
-#: src/webex/pages/confirm-create-reserve.tsx:498 src/webex/pages/tip.tsx:148
+#: src/webex/pages/confirm-create-reserve.tsx:505 src/webex/pages/tip.tsx:155
 #, c-format
 msgid "Fatal error: \"%1$s\"."
 msgstr ""
 
-#: src/webex/pages/popup.tsx:160
+#: src/webex/pages/popup.tsx:162
 #, c-format
 msgid "Balance"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:163
+#: src/webex/pages/popup.tsx:165
 #, c-format
 msgid "History"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:166
+#: src/webex/pages/popup.tsx:168
 #, c-format
 msgid "Debug"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:246
+#: src/webex/pages/popup.tsx:248
 #, c-format
 msgid "help"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:251
+#: src/webex/pages/popup.tsx:253
 #, c-format
 msgid ""
 "You have no balance to show. Need some\n"
 " %1$s getting started?\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:268
+#: src/webex/pages/popup.tsx:270
 #, c-format
 msgid "%1$s incoming\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:281
+#: src/webex/pages/popup.tsx:283
 #, c-format
 msgid "%1$s being spent\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:307
+#: src/webex/pages/popup.tsx:309
 #, c-format
 msgid "Error: could not retrieve balance information."
 msgstr ""
 
-#: src/webex/pages/popup.tsx:334
+#: src/webex/pages/popup.tsx:336
 #, c-format
 msgid "Payback"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:335
+#: src/webex/pages/popup.tsx:337
 #, c-format
 msgid "Return Electronic Cash to Bank Account"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:336
+#: src/webex/pages/popup.tsx:338
 #, c-format
 msgid "Manage Trusted Auditors and Exchanges"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:348
+#: src/webex/pages/popup.tsx:350
 #, c-format
 msgid ""
 "Bank requested reserve (%1$s) for\n"
 " %2$s.\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:358
+#: src/webex/pages/popup.tsx:360
 #, c-format
 msgid ""
 "Started to withdraw\n"
 " %1$s%2$sfrom%3$s(%4$s).\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:367
+#: src/webex/pages/popup.tsx:369
 #, c-format
 msgid "Merchant%1$soffered%2$scontract%3$s.\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:378
+#: src/webex/pages/popup.tsx:380
 #, c-format
 msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:388
+#: src/webex/pages/popup.tsx:390
 #, c-format
 msgid ""
 "Paid%1$sto merchant%2$s.\n"
 "%3$s(%4$s)\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:398
+#: src/webex/pages/popup.tsx:400
 #, c-format
 msgid "Merchant%1$sgave a refund over%2$s.\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:408
+#: src/webex/pages/popup.tsx:410
 #, c-format
 msgid ""
-"Merchant%1$sgave a%2$sof%3$s.\n"
+"Merchant%1$sgave\n"
+"a%2$sof%3$s.\n"
 "%4$s%5$s"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:417
+#: src/webex/pages/popup.tsx:420
 #, c-format
 msgid "Unknown event (%1$s)"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:460
+#: src/webex/pages/popup.tsx:463
 #, c-format
 msgid "Error: could not retrieve event history"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:485
+#: src/webex/pages/popup.tsx:488
 #, c-format
 msgid "Your wallet has no events recorded."
 msgstr ""
 
-#: src/webex/pages/return-coins.tsx:104
+#: src/webex/pages/return-coins.tsx:105
 #, c-format
 msgid "Wire to bank account"
 msgstr ""
 
-#: src/webex/pages/return-coins.tsx:172
+#: src/webex/pages/return-coins.tsx:173
 #, c-format
 msgid "Confirm"
 msgstr ""
 
-#: src/webex/pages/return-coins.tsx:175
+#: src/webex/pages/return-coins.tsx:176
 #, c-format
 msgid "Cancel"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:212
+#: src/webex/renderHtml.tsx:216
 #, c-format
 msgid "Withdrawal fees:"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:213
+#: src/webex/renderHtml.tsx:217
 #, c-format
 msgid "Rounding loss:"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:214
+#: src/webex/renderHtml.tsx:218
 #, c-format
 msgid "Earliest expiration (for deposit): %1$s"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:220
+#: src/webex/renderHtml.tsx:224
 #, c-format
 msgid "# Coins"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:221
+#: src/webex/renderHtml.tsx:225
 #, c-format
 msgid "Value"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:222
+#: src/webex/renderHtml.tsx:226
 #, c-format
 msgid "Withdraw Fee"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:223
+#: src/webex/renderHtml.tsx:227
 #, c-format
 msgid "Refresh Fee"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:224
+#: src/webex/renderHtml.tsx:228
 #, c-format
 msgid "Deposit Fee"
 msgstr ""
diff --git a/src/i18n/fr.po b/src/i18n/fr.po
index 6b126178..b955dc6a 100644
--- a/src/i18n/fr.po
+++ b/src/i18n/fr.po
@@ -27,28 +27,28 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
-#: src/webex/pages/confirm-contract.tsx:70
+#: src/webex/pages/confirm-contract.tsx:73
 #, c-format
 msgid "show more details\n"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:84
+#: src/webex/pages/confirm-contract.tsx:87
 #, c-format
 msgid "Accepted exchanges:"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:89
+#: src/webex/pages/confirm-contract.tsx:92
 #, c-format
 msgid "Exchanges in the wallet:"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:156
+#: src/webex/pages/confirm-contract.tsx:159
 #, c-format
 msgid "You have insufficient funds of the requested currency in your wallet."
 msgstr ""
 
 #. tslint:disable-next-line:max-line-length
-#: src/webex/pages/confirm-contract.tsx:158
+#: src/webex/pages/confirm-contract.tsx:161
 #, c-format
 msgid ""
 "You do not have any funds from an exchange that is accepted by this "
@@ -56,37 +56,37 @@ msgid ""
 "wallet."
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:214
+#: src/webex/pages/confirm-contract.tsx:217
 #, c-format
 msgid "The merchant%1$s offers you to purchase:\n"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:235
+#: src/webex/pages/confirm-contract.tsx:238
 #, c-format
 msgid "Confirm payment"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:121
+#: src/webex/pages/confirm-create-reserve.tsx:126
 #, c-format
 msgid "Select"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:137
+#: src/webex/pages/confirm-create-reserve.tsx:142
 #, c-format
 msgid "Error: URL may not be relative"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:205
+#: src/webex/pages/confirm-create-reserve.tsx:210
 #, c-format
 msgid "The exchange is trusted by the wallet.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:211
+#: src/webex/pages/confirm-create-reserve.tsx:216
 #, c-format
 msgid "The exchange is audited by a trusted auditor.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:217
+#: src/webex/pages/confirm-create-reserve.tsx:222
 #, c-format
 msgid ""
 "Warning:  The exchange is neither directly trusted nor audited by a trusted "
@@ -94,7 +94,7 @@ msgid ""
 "If you withdraw from this exchange, it will be trusted in the future.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:226
+#: src/webex/pages/confirm-create-reserve.tsx:231
 #, c-format
 msgid ""
 "Using exchange provider%1$s.\n"
@@ -102,229 +102,230 @@ msgid ""
 " %2$s in fees.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:240
+#: src/webex/pages/confirm-create-reserve.tsx:245
 #, c-format
 msgid ""
 "Waiting for a response from\n"
 " %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:257
+#: src/webex/pages/confirm-create-reserve.tsx:262
 #, c-format
 msgid ""
 "Information about fees will be available when an exchange provider is "
 "selected."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:300
+#: src/webex/pages/confirm-create-reserve.tsx:307
 #, c-format
 msgid "Accept fees and withdraw"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:305
+#: src/webex/pages/confirm-create-reserve.tsx:312
 #, c-format
 msgid "Change Exchange Provider"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:357
+#: src/webex/pages/confirm-create-reserve.tsx:364
 #, c-format
 msgid "You are about to withdraw %1$s from your bank account into your wallet."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:442
+#: src/webex/pages/confirm-create-reserve.tsx:449
 #, c-format
 msgid ""
 "Oops, something went wrong. The wallet responded with error status (%1$s)."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:451
+#: src/webex/pages/confirm-create-reserve.tsx:458
 #, c-format
 msgid "Checking URL, please wait ..."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:465
+#: src/webex/pages/confirm-create-reserve.tsx:472
 #, c-format
 msgid "Can't parse amount: %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:472
+#: src/webex/pages/confirm-create-reserve.tsx:479
 #, c-format
 msgid "Can't parse wire_types: %1$s"
 msgstr ""
 
 #. #-#-#-#-#  - (PACKAGE VERSION)  #-#-#-#-#
 #. TODO:generic error reporting function or component.
-#: src/webex/pages/confirm-create-reserve.tsx:498 src/webex/pages/tip.tsx:148
+#: src/webex/pages/confirm-create-reserve.tsx:505 src/webex/pages/tip.tsx:155
 #, c-format
 msgid "Fatal error: \"%1$s\"."
 msgstr ""
 
-#: src/webex/pages/popup.tsx:160
+#: src/webex/pages/popup.tsx:162
 #, c-format
 msgid "Balance"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:163
+#: src/webex/pages/popup.tsx:165
 #, c-format
 msgid "History"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:166
+#: src/webex/pages/popup.tsx:168
 #, c-format
 msgid "Debug"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:246
+#: src/webex/pages/popup.tsx:248
 #, c-format
 msgid "help"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:251
+#: src/webex/pages/popup.tsx:253
 #, c-format
 msgid ""
 "You have no balance to show. Need some\n"
 " %1$s getting started?\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:268
+#: src/webex/pages/popup.tsx:270
 #, c-format
 msgid "%1$s incoming\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:281
+#: src/webex/pages/popup.tsx:283
 #, c-format
 msgid "%1$s being spent\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:307
+#: src/webex/pages/popup.tsx:309
 #, c-format
 msgid "Error: could not retrieve balance information."
 msgstr ""
 
-#: src/webex/pages/popup.tsx:334
+#: src/webex/pages/popup.tsx:336
 #, c-format
 msgid "Payback"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:335
+#: src/webex/pages/popup.tsx:337
 #, c-format
 msgid "Return Electronic Cash to Bank Account"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:336
+#: src/webex/pages/popup.tsx:338
 #, c-format
 msgid "Manage Trusted Auditors and Exchanges"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:348
+#: src/webex/pages/popup.tsx:350
 #, c-format
 msgid ""
 "Bank requested reserve (%1$s) for\n"
 " %2$s.\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:358
+#: src/webex/pages/popup.tsx:360
 #, c-format
 msgid ""
 "Started to withdraw\n"
 " %1$s%2$sfrom%3$s(%4$s).\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:367
+#: src/webex/pages/popup.tsx:369
 #, c-format
 msgid "Merchant%1$soffered%2$scontract%3$s.\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:378
+#: src/webex/pages/popup.tsx:380
 #, c-format
 msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:388
+#: src/webex/pages/popup.tsx:390
 #, c-format
 msgid ""
 "Paid%1$sto merchant%2$s.\n"
 "%3$s(%4$s)\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:398
+#: src/webex/pages/popup.tsx:400
 #, c-format
 msgid "Merchant%1$sgave a refund over%2$s.\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:408
+#: src/webex/pages/popup.tsx:410
 #, c-format
 msgid ""
-"Merchant%1$sgave a%2$sof%3$s.\n"
+"Merchant%1$sgave\n"
+"a%2$sof%3$s.\n"
 "%4$s%5$s"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:417
+#: src/webex/pages/popup.tsx:420
 #, c-format
 msgid "Unknown event (%1$s)"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:460
+#: src/webex/pages/popup.tsx:463
 #, c-format
 msgid "Error: could not retrieve event history"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:485
+#: src/webex/pages/popup.tsx:488
 #, c-format
 msgid "Your wallet has no events recorded."
 msgstr ""
 
-#: src/webex/pages/return-coins.tsx:104
+#: src/webex/pages/return-coins.tsx:105
 #, c-format
 msgid "Wire to bank account"
 msgstr ""
 
-#: src/webex/pages/return-coins.tsx:172
+#: src/webex/pages/return-coins.tsx:173
 #, c-format
 msgid "Confirm"
 msgstr ""
 
-#: src/webex/pages/return-coins.tsx:175
+#: src/webex/pages/return-coins.tsx:176
 #, c-format
 msgid "Cancel"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:212
+#: src/webex/renderHtml.tsx:216
 #, c-format
 msgid "Withdrawal fees:"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:213
+#: src/webex/renderHtml.tsx:217
 #, c-format
 msgid "Rounding loss:"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:214
+#: src/webex/renderHtml.tsx:218
 #, c-format
 msgid "Earliest expiration (for deposit): %1$s"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:220
+#: src/webex/renderHtml.tsx:224
 #, c-format
 msgid "# Coins"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:221
+#: src/webex/renderHtml.tsx:225
 #, c-format
 msgid "Value"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:222
+#: src/webex/renderHtml.tsx:226
 #, c-format
 msgid "Withdraw Fee"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:223
+#: src/webex/renderHtml.tsx:227
 #, c-format
 msgid "Refresh Fee"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:224
+#: src/webex/renderHtml.tsx:228
 #, c-format
 msgid "Deposit Fee"
 msgstr ""
diff --git a/src/i18n/it.po b/src/i18n/it.po
index 6b126178..b955dc6a 100644
--- a/src/i18n/it.po
+++ b/src/i18n/it.po
@@ -27,28 +27,28 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
-#: src/webex/pages/confirm-contract.tsx:70
+#: src/webex/pages/confirm-contract.tsx:73
 #, c-format
 msgid "show more details\n"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:84
+#: src/webex/pages/confirm-contract.tsx:87
 #, c-format
 msgid "Accepted exchanges:"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:89
+#: src/webex/pages/confirm-contract.tsx:92
 #, c-format
 msgid "Exchanges in the wallet:"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:156
+#: src/webex/pages/confirm-contract.tsx:159
 #, c-format
 msgid "You have insufficient funds of the requested currency in your wallet."
 msgstr ""
 
 #. tslint:disable-next-line:max-line-length
-#: src/webex/pages/confirm-contract.tsx:158
+#: src/webex/pages/confirm-contract.tsx:161
 #, c-format
 msgid ""
 "You do not have any funds from an exchange that is accepted by this "
@@ -56,37 +56,37 @@ msgid ""
 "wallet."
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:214
+#: src/webex/pages/confirm-contract.tsx:217
 #, c-format
 msgid "The merchant%1$s offers you to purchase:\n"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:235
+#: src/webex/pages/confirm-contract.tsx:238
 #, c-format
 msgid "Confirm payment"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:121
+#: src/webex/pages/confirm-create-reserve.tsx:126
 #, c-format
 msgid "Select"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:137
+#: src/webex/pages/confirm-create-reserve.tsx:142
 #, c-format
 msgid "Error: URL may not be relative"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:205
+#: src/webex/pages/confirm-create-reserve.tsx:210
 #, c-format
 msgid "The exchange is trusted by the wallet.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:211
+#: src/webex/pages/confirm-create-reserve.tsx:216
 #, c-format
 msgid "The exchange is audited by a trusted auditor.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:217
+#: src/webex/pages/confirm-create-reserve.tsx:222
 #, c-format
 msgid ""
 "Warning:  The exchange is neither directly trusted nor audited by a trusted "
@@ -94,7 +94,7 @@ msgid ""
 "If you withdraw from this exchange, it will be trusted in the future.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:226
+#: src/webex/pages/confirm-create-reserve.tsx:231
 #, c-format
 msgid ""
 "Using exchange provider%1$s.\n"
@@ -102,229 +102,230 @@ msgid ""
 " %2$s in fees.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:240
+#: src/webex/pages/confirm-create-reserve.tsx:245
 #, c-format
 msgid ""
 "Waiting for a response from\n"
 " %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:257
+#: src/webex/pages/confirm-create-reserve.tsx:262
 #, c-format
 msgid ""
 "Information about fees will be available when an exchange provider is "
 "selected."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:300
+#: src/webex/pages/confirm-create-reserve.tsx:307
 #, c-format
 msgid "Accept fees and withdraw"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:305
+#: src/webex/pages/confirm-create-reserve.tsx:312
 #, c-format
 msgid "Change Exchange Provider"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:357
+#: src/webex/pages/confirm-create-reserve.tsx:364
 #, c-format
 msgid "You are about to withdraw %1$s from your bank account into your wallet."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:442
+#: src/webex/pages/confirm-create-reserve.tsx:449
 #, c-format
 msgid ""
 "Oops, something went wrong. The wallet responded with error status (%1$s)."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:451
+#: src/webex/pages/confirm-create-reserve.tsx:458
 #, c-format
 msgid "Checking URL, please wait ..."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:465
+#: src/webex/pages/confirm-create-reserve.tsx:472
 #, c-format
 msgid "Can't parse amount: %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:472
+#: src/webex/pages/confirm-create-reserve.tsx:479
 #, c-format
 msgid "Can't parse wire_types: %1$s"
 msgstr ""
 
 #. #-#-#-#-#  - (PACKAGE VERSION)  #-#-#-#-#
 #. TODO:generic error reporting function or component.
-#: src/webex/pages/confirm-create-reserve.tsx:498 src/webex/pages/tip.tsx:148
+#: src/webex/pages/confirm-create-reserve.tsx:505 src/webex/pages/tip.tsx:155
 #, c-format
 msgid "Fatal error: \"%1$s\"."
 msgstr ""
 
-#: src/webex/pages/popup.tsx:160
+#: src/webex/pages/popup.tsx:162
 #, c-format
 msgid "Balance"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:163
+#: src/webex/pages/popup.tsx:165
 #, c-format
 msgid "History"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:166
+#: src/webex/pages/popup.tsx:168
 #, c-format
 msgid "Debug"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:246
+#: src/webex/pages/popup.tsx:248
 #, c-format
 msgid "help"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:251
+#: src/webex/pages/popup.tsx:253
 #, c-format
 msgid ""
 "You have no balance to show. Need some\n"
 " %1$s getting started?\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:268
+#: src/webex/pages/popup.tsx:270
 #, c-format
 msgid "%1$s incoming\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:281
+#: src/webex/pages/popup.tsx:283
 #, c-format
 msgid "%1$s being spent\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:307
+#: src/webex/pages/popup.tsx:309
 #, c-format
 msgid "Error: could not retrieve balance information."
 msgstr ""
 
-#: src/webex/pages/popup.tsx:334
+#: src/webex/pages/popup.tsx:336
 #, c-format
 msgid "Payback"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:335
+#: src/webex/pages/popup.tsx:337
 #, c-format
 msgid "Return Electronic Cash to Bank Account"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:336
+#: src/webex/pages/popup.tsx:338
 #, c-format
 msgid "Manage Trusted Auditors and Exchanges"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:348
+#: src/webex/pages/popup.tsx:350
 #, c-format
 msgid ""
 "Bank requested reserve (%1$s) for\n"
 " %2$s.\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:358
+#: src/webex/pages/popup.tsx:360
 #, c-format
 msgid ""
 "Started to withdraw\n"
 " %1$s%2$sfrom%3$s(%4$s).\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:367
+#: src/webex/pages/popup.tsx:369
 #, c-format
 msgid "Merchant%1$soffered%2$scontract%3$s.\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:378
+#: src/webex/pages/popup.tsx:380
 #, c-format
 msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:388
+#: src/webex/pages/popup.tsx:390
 #, c-format
 msgid ""
 "Paid%1$sto merchant%2$s.\n"
 "%3$s(%4$s)\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:398
+#: src/webex/pages/popup.tsx:400
 #, c-format
 msgid "Merchant%1$sgave a refund over%2$s.\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:408
+#: src/webex/pages/popup.tsx:410
 #, c-format
 msgid ""
-"Merchant%1$sgave a%2$sof%3$s.\n"
+"Merchant%1$sgave\n"
+"a%2$sof%3$s.\n"
 "%4$s%5$s"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:417
+#: src/webex/pages/popup.tsx:420
 #, c-format
 msgid "Unknown event (%1$s)"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:460
+#: src/webex/pages/popup.tsx:463
 #, c-format
 msgid "Error: could not retrieve event history"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:485
+#: src/webex/pages/popup.tsx:488
 #, c-format
 msgid "Your wallet has no events recorded."
 msgstr ""
 
-#: src/webex/pages/return-coins.tsx:104
+#: src/webex/pages/return-coins.tsx:105
 #, c-format
 msgid "Wire to bank account"
 msgstr ""
 
-#: src/webex/pages/return-coins.tsx:172
+#: src/webex/pages/return-coins.tsx:173
 #, c-format
 msgid "Confirm"
 msgstr ""
 
-#: src/webex/pages/return-coins.tsx:175
+#: src/webex/pages/return-coins.tsx:176
 #, c-format
 msgid "Cancel"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:212
+#: src/webex/renderHtml.tsx:216
 #, c-format
 msgid "Withdrawal fees:"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:213
+#: src/webex/renderHtml.tsx:217
 #, c-format
 msgid "Rounding loss:"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:214
+#: src/webex/renderHtml.tsx:218
 #, c-format
 msgid "Earliest expiration (for deposit): %1$s"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:220
+#: src/webex/renderHtml.tsx:224
 #, c-format
 msgid "# Coins"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:221
+#: src/webex/renderHtml.tsx:225
 #, c-format
 msgid "Value"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:222
+#: src/webex/renderHtml.tsx:226
 #, c-format
 msgid "Withdraw Fee"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:223
+#: src/webex/renderHtml.tsx:227
 #, c-format
 msgid "Refresh Fee"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:224
+#: src/webex/renderHtml.tsx:228
 #, c-format
 msgid "Deposit Fee"
 msgstr ""
diff --git a/src/i18n/strings.ts b/src/i18n/strings.ts
index d18368ad..9e78abc3 100644
--- a/src/i18n/strings.ts
+++ b/src/i18n/strings.ts
@@ -144,7 +144,7 @@ strings['de'] = {
       "Merchant%1$sgave a refund over%2$s.\n": [
         ""
       ],
-      "Merchant%1$sgave a%2$sof%3$s.\n%4$s%5$s": [
+      "Merchant%1$sgave\na%2$sof%3$s.\n%4$s%5$s": [
         "%1$s\n               möchte einen Vertrag über %2$s\n               
mit Ihnen abschließen."
       ],
       "Unknown event (%1$s)": [
@@ -333,7 +333,7 @@ strings['en-US'] = {
       "Merchant%1$sgave a refund over%2$s.\n": [
         ""
       ],
-      "Merchant%1$sgave a%2$sof%3$s.\n%4$s%5$s": [
+      "Merchant%1$sgave\na%2$sof%3$s.\n%4$s%5$s": [
         ""
       ],
       "Unknown event (%1$s)": [
@@ -522,7 +522,7 @@ strings['fr'] = {
       "Merchant%1$sgave a refund over%2$s.\n": [
         ""
       ],
-      "Merchant%1$sgave a%2$sof%3$s.\n%4$s%5$s": [
+      "Merchant%1$sgave\na%2$sof%3$s.\n%4$s%5$s": [
         ""
       ],
       "Unknown event (%1$s)": [
@@ -711,7 +711,7 @@ strings['it'] = {
       "Merchant%1$sgave a refund over%2$s.\n": [
         ""
       ],
-      "Merchant%1$sgave a%2$sof%3$s.\n%4$s%5$s": [
+      "Merchant%1$sgave\na%2$sof%3$s.\n%4$s%5$s": [
         ""
       ],
       "Unknown event (%1$s)": [
diff --git a/src/i18n/taler-wallet-webex.pot b/src/i18n/taler-wallet-webex.pot
index 6b126178..b955dc6a 100644
--- a/src/i18n/taler-wallet-webex.pot
+++ b/src/i18n/taler-wallet-webex.pot
@@ -27,28 +27,28 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
-#: src/webex/pages/confirm-contract.tsx:70
+#: src/webex/pages/confirm-contract.tsx:73
 #, c-format
 msgid "show more details\n"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:84
+#: src/webex/pages/confirm-contract.tsx:87
 #, c-format
 msgid "Accepted exchanges:"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:89
+#: src/webex/pages/confirm-contract.tsx:92
 #, c-format
 msgid "Exchanges in the wallet:"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:156
+#: src/webex/pages/confirm-contract.tsx:159
 #, c-format
 msgid "You have insufficient funds of the requested currency in your wallet."
 msgstr ""
 
 #. tslint:disable-next-line:max-line-length
-#: src/webex/pages/confirm-contract.tsx:158
+#: src/webex/pages/confirm-contract.tsx:161
 #, c-format
 msgid ""
 "You do not have any funds from an exchange that is accepted by this "
@@ -56,37 +56,37 @@ msgid ""
 "wallet."
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:214
+#: src/webex/pages/confirm-contract.tsx:217
 #, c-format
 msgid "The merchant%1$s offers you to purchase:\n"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:235
+#: src/webex/pages/confirm-contract.tsx:238
 #, c-format
 msgid "Confirm payment"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:121
+#: src/webex/pages/confirm-create-reserve.tsx:126
 #, c-format
 msgid "Select"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:137
+#: src/webex/pages/confirm-create-reserve.tsx:142
 #, c-format
 msgid "Error: URL may not be relative"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:205
+#: src/webex/pages/confirm-create-reserve.tsx:210
 #, c-format
 msgid "The exchange is trusted by the wallet.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:211
+#: src/webex/pages/confirm-create-reserve.tsx:216
 #, c-format
 msgid "The exchange is audited by a trusted auditor.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:217
+#: src/webex/pages/confirm-create-reserve.tsx:222
 #, c-format
 msgid ""
 "Warning:  The exchange is neither directly trusted nor audited by a trusted "
@@ -94,7 +94,7 @@ msgid ""
 "If you withdraw from this exchange, it will be trusted in the future.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:226
+#: src/webex/pages/confirm-create-reserve.tsx:231
 #, c-format
 msgid ""
 "Using exchange provider%1$s.\n"
@@ -102,229 +102,230 @@ msgid ""
 " %2$s in fees.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:240
+#: src/webex/pages/confirm-create-reserve.tsx:245
 #, c-format
 msgid ""
 "Waiting for a response from\n"
 " %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:257
+#: src/webex/pages/confirm-create-reserve.tsx:262
 #, c-format
 msgid ""
 "Information about fees will be available when an exchange provider is "
 "selected."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:300
+#: src/webex/pages/confirm-create-reserve.tsx:307
 #, c-format
 msgid "Accept fees and withdraw"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:305
+#: src/webex/pages/confirm-create-reserve.tsx:312
 #, c-format
 msgid "Change Exchange Provider"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:357
+#: src/webex/pages/confirm-create-reserve.tsx:364
 #, c-format
 msgid "You are about to withdraw %1$s from your bank account into your wallet."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:442
+#: src/webex/pages/confirm-create-reserve.tsx:449
 #, c-format
 msgid ""
 "Oops, something went wrong. The wallet responded with error status (%1$s)."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:451
+#: src/webex/pages/confirm-create-reserve.tsx:458
 #, c-format
 msgid "Checking URL, please wait ..."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:465
+#: src/webex/pages/confirm-create-reserve.tsx:472
 #, c-format
 msgid "Can't parse amount: %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:472
+#: src/webex/pages/confirm-create-reserve.tsx:479
 #, c-format
 msgid "Can't parse wire_types: %1$s"
 msgstr ""
 
 #. #-#-#-#-#  - (PACKAGE VERSION)  #-#-#-#-#
 #. TODO:generic error reporting function or component.
-#: src/webex/pages/confirm-create-reserve.tsx:498 src/webex/pages/tip.tsx:148
+#: src/webex/pages/confirm-create-reserve.tsx:505 src/webex/pages/tip.tsx:155
 #, c-format
 msgid "Fatal error: \"%1$s\"."
 msgstr ""
 
-#: src/webex/pages/popup.tsx:160
+#: src/webex/pages/popup.tsx:162
 #, c-format
 msgid "Balance"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:163
+#: src/webex/pages/popup.tsx:165
 #, c-format
 msgid "History"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:166
+#: src/webex/pages/popup.tsx:168
 #, c-format
 msgid "Debug"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:246
+#: src/webex/pages/popup.tsx:248
 #, c-format
 msgid "help"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:251
+#: src/webex/pages/popup.tsx:253
 #, c-format
 msgid ""
 "You have no balance to show. Need some\n"
 " %1$s getting started?\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:268
+#: src/webex/pages/popup.tsx:270
 #, c-format
 msgid "%1$s incoming\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:281
+#: src/webex/pages/popup.tsx:283
 #, c-format
 msgid "%1$s being spent\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:307
+#: src/webex/pages/popup.tsx:309
 #, c-format
 msgid "Error: could not retrieve balance information."
 msgstr ""
 
-#: src/webex/pages/popup.tsx:334
+#: src/webex/pages/popup.tsx:336
 #, c-format
 msgid "Payback"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:335
+#: src/webex/pages/popup.tsx:337
 #, c-format
 msgid "Return Electronic Cash to Bank Account"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:336
+#: src/webex/pages/popup.tsx:338
 #, c-format
 msgid "Manage Trusted Auditors and Exchanges"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:348
+#: src/webex/pages/popup.tsx:350
 #, c-format
 msgid ""
 "Bank requested reserve (%1$s) for\n"
 " %2$s.\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:358
+#: src/webex/pages/popup.tsx:360
 #, c-format
 msgid ""
 "Started to withdraw\n"
 " %1$s%2$sfrom%3$s(%4$s).\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:367
+#: src/webex/pages/popup.tsx:369
 #, c-format
 msgid "Merchant%1$soffered%2$scontract%3$s.\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:378
+#: src/webex/pages/popup.tsx:380
 #, c-format
 msgid "Withdrew%1$sfrom%2$s(%3$s).\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:388
+#: src/webex/pages/popup.tsx:390
 #, c-format
 msgid ""
 "Paid%1$sto merchant%2$s.\n"
 "%3$s(%4$s)\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:398
+#: src/webex/pages/popup.tsx:400
 #, c-format
 msgid "Merchant%1$sgave a refund over%2$s.\n"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:408
+#: src/webex/pages/popup.tsx:410
 #, c-format
 msgid ""
-"Merchant%1$sgave a%2$sof%3$s.\n"
+"Merchant%1$sgave\n"
+"a%2$sof%3$s.\n"
 "%4$s%5$s"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:417
+#: src/webex/pages/popup.tsx:420
 #, c-format
 msgid "Unknown event (%1$s)"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:460
+#: src/webex/pages/popup.tsx:463
 #, c-format
 msgid "Error: could not retrieve event history"
 msgstr ""
 
-#: src/webex/pages/popup.tsx:485
+#: src/webex/pages/popup.tsx:488
 #, c-format
 msgid "Your wallet has no events recorded."
 msgstr ""
 
-#: src/webex/pages/return-coins.tsx:104
+#: src/webex/pages/return-coins.tsx:105
 #, c-format
 msgid "Wire to bank account"
 msgstr ""
 
-#: src/webex/pages/return-coins.tsx:172
+#: src/webex/pages/return-coins.tsx:173
 #, c-format
 msgid "Confirm"
 msgstr ""
 
-#: src/webex/pages/return-coins.tsx:175
+#: src/webex/pages/return-coins.tsx:176
 #, c-format
 msgid "Cancel"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:212
+#: src/webex/renderHtml.tsx:216
 #, c-format
 msgid "Withdrawal fees:"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:213
+#: src/webex/renderHtml.tsx:217
 #, c-format
 msgid "Rounding loss:"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:214
+#: src/webex/renderHtml.tsx:218
 #, c-format
 msgid "Earliest expiration (for deposit): %1$s"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:220
+#: src/webex/renderHtml.tsx:224
 #, c-format
 msgid "# Coins"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:221
+#: src/webex/renderHtml.tsx:225
 #, c-format
 msgid "Value"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:222
+#: src/webex/renderHtml.tsx:226
 #, c-format
 msgid "Withdraw Fee"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:223
+#: src/webex/renderHtml.tsx:227
 #, c-format
 msgid "Refresh Fee"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:224
+#: src/webex/renderHtml.tsx:228
 #, c-format
 msgid "Deposit Fee"
 msgstr ""
diff --git a/src/talerTypes.ts b/src/talerTypes.ts
index 2ac2a515..5ba5af17 100644
--- a/src/talerTypes.ts
+++ b/src/talerTypes.ts
@@ -630,3 +630,156 @@ export class TipToken {
    */
   static checked: (obj: any) => TipToken;
 }
+
+
+/**
+ * Element of the payback list that the
+ * exchange gives us in /keys.
+ */
address@hidden()
+export class Payback {
+  /**
+   * The hash of the denomination public key for which the payback is offered.
+   */
+  @Checkable.String
+  h_denom_pub: string;
+}
+
+
+/**
+ * Structure that the exchange gives us in /keys.
+ */
address@hidden({extra: true})
+export class KeysJson {
+  /**
+   * List of offered denominations.
+   */
+  @Checkable.List(Checkable.Value(Denomination))
+  denoms: Denomination[];
+
+  /**
+   * The exchange's master public key.
+   */
+  @Checkable.String
+  master_public_key: string;
+
+  /**
+   * The list of auditors (partially) auditing the exchange.
+   */
+  @Checkable.List(Checkable.Value(Auditor))
+  auditors: Auditor[];
+
+  /**
+   * Timestamp when this response was issued.
+   */
+  @Checkable.String
+  list_issue_date: string;
+
+  /**
+   * List of paybacks for compromised denominations.
+   */
+  @Checkable.Optional(Checkable.List(Checkable.Value(Payback)))
+  payback?: Payback[];
+
+  /**
+   * Short-lived signing keys used to sign online
+   * responses.
+   */
+  @Checkable.Any
+  signkeys: any;
+
+  /**
+   * Protocol version.
+   */
+  @Checkable.Optional(Checkable.String)
+  version?: string;
+
+  /**
+   * Verify that a value matches the schema of this class and convert it into a
+   * member.
+   */
+  static checked: (obj: any) => KeysJson;
+}
+
+
+/**
+ * Wire fees as anounced by the exchange.
+ */
address@hidden()
+export class WireFeesJson {
+  /**
+   * Cost of a wire transfer.
+   */
+  @Checkable.Value(AmountJson)
+  wire_fee: AmountJson;
+
+  /**
+   * Cost of clising a reserve.
+   */
+  @Checkable.Value(AmountJson)
+  closing_fee: AmountJson;
+
+  /**
+   * Signature made with the exchange's master key.
+   */
+  @Checkable.String
+  sig: string;
+
+  /**
+   * Date from which the fee applies.
+   */
+  @Checkable.String
+  start_date: string;
+
+  /**
+   * Data after which the fee doesn't apply anymore.
+   */
+  @Checkable.String
+  end_date: string;
+
+  /**
+   * Verify that a value matches the schema of this class and convert it into a
+   * member.
+   */
+  static checked: (obj: any) => WireFeesJson;
+}
+
+
+/**
+ * Information about wire transfer methods supported
+ * by the exchange.
+ */
address@hidden({extra: true})
+export class WireDetailJson {
+  /**
+   * Name of the wire transfer method.
+   */
+  @Checkable.String
+  type: string;
+
+  /**
+   * Fees associated with the wire transfer method.
+   */
+  @Checkable.List(Checkable.Value(WireFeesJson))
+  fees: WireFeesJson[];
+
+  /**
+   * Verify that a value matches the schema of this class and convert it into a
+   * member.
+   */
+  static checked: (obj: any) => WireDetailJson;
+}
+
+
+/**
+ * Wire detail, arbitrary object that must at least
+ * contain a "type" key.
+ */
+export type WireDetail = object & { type: string };
+
+/**
+ * Type guard for wire details.
+ */
+export function isWireDetail(x: any): x is WireDetail {
+  return x && typeof x === "object" && typeof x.type === "string";
+}
diff --git a/src/wallet.ts b/src/wallet.ts
index 41f8e727..b3ef3bf3 100644
--- a/src/wallet.ts
+++ b/src/wallet.ts
@@ -22,13 +22,14 @@
 /**
  * Imports.
  */
-import {Checkable} from "./checkable";
-import {CryptoApi} from "./crypto/cryptoApi";
+import { CryptoApi } from "./crypto/cryptoApi";
 import {
   amountToPretty,
   canonicalJson,
   canonicalizeBaseUrl,
   getTalerStampSec,
+  hash,
+  strcmp,
 } from "./helpers";
 import {
   HttpRequestLibrary,
@@ -37,20 +38,21 @@ import {
 import * as LibtoolVersion from "./libtoolVersion";
 import {
   AbortTransaction,
-  Index,
   JoinLeftResult,
   JoinResult,
   QueryRoot,
-  Store,
 } from "./query";
 import { TimerGroup } from "./timer";
 
 import { AmountJson } from "./amounts";
 import * as Amounts from "./amounts";
 
+import URI = require("urijs");
+
 import {
   CoinRecord,
   CoinStatus,
+  CoinsReturnRecord,
   CurrencyRecord,
   DenominationRecord,
   DenominationStatus,
@@ -62,25 +64,26 @@ import {
   RefreshPreCoinRecord,
   RefreshSessionRecord,
   ReserveRecord,
+  Stores,
   TipRecord,
   WireFee,
 } from "./dbTypes";
-
-import URI = require("urijs");
-
 import {
   Auditor,
-  CoinPaySig,
   ContractTerms,
   Denomination,
   ExchangeHandle,
+  KeysJson,
   PayReq,
   PaybackConfirmation,
   RefundPermission,
   TipPlanchetDetail,
   TipResponse,
+  WireDetailJson,
+  isWireDetail,
 } from "./talerTypes";
 import {
+  Badge,
   CheckPayResult,
   CoinSelectionResult,
   CoinWithDenom,
@@ -99,239 +102,9 @@ import {
   WalletBalance,
   WalletBalanceEntry,
   WireInfo,
-
 } from "./walletTypes";
 
 
-/**
- * Element of the payback list that the
- * exchange gives us in /keys.
- */
address@hidden()
-export class Payback {
-  /**
-   * The hash of the denomination public key for which the payback is offered.
-   */
-  @Checkable.String
-  h_denom_pub: string;
-}
-
-
-/**
- * Structure that the exchange gives us in /keys.
- */
address@hidden({extra: true})
-export class KeysJson {
-  /**
-   * List of offered denominations.
-   */
-  @Checkable.List(Checkable.Value(Denomination))
-  denoms: Denomination[];
-
-  /**
-   * The exchange's master public key.
-   */
-  @Checkable.String
-  master_public_key: string;
-
-  /**
-   * The list of auditors (partially) auditing the exchange.
-   */
-  @Checkable.List(Checkable.Value(Auditor))
-  auditors: Auditor[];
-
-  /**
-   * Timestamp when this response was issued.
-   */
-  @Checkable.String
-  list_issue_date: string;
-
-  /**
-   * List of paybacks for compromised denominations.
-   */
-  @Checkable.Optional(Checkable.List(Checkable.Value(Payback)))
-  payback?: Payback[];
-
-  /**
-   * Short-lived signing keys used to sign online
-   * responses.
-   */
-  @Checkable.Any
-  signkeys: any;
-
-  /**
-   * Protocol version.
-   */
-  @Checkable.Optional(Checkable.String)
-  version?: string;
-
-  /**
-   * Verify that a value matches the schema of this class and convert it into a
-   * member.
-   */
-  static checked: (obj: any) => KeysJson;
-}
-
-
-/**
- * Wire fees as anounced by the exchange.
- */
address@hidden()
-class WireFeesJson {
-  /**
-   * Cost of a wire transfer.
-   */
-  @Checkable.Value(AmountJson)
-  wire_fee: AmountJson;
-
-  /**
-   * Cost of clising a reserve.
-   */
-  @Checkable.Value(AmountJson)
-  closing_fee: AmountJson;
-
-  /**
-   * Signature made with the exchange's master key.
-   */
-  @Checkable.String
-  sig: string;
-
-  /**
-   * Date from which the fee applies.
-   */
-  @Checkable.String
-  start_date: string;
-
-  /**
-   * Data after which the fee doesn't apply anymore.
-   */
-  @Checkable.String
-  end_date: string;
-
-  /**
-   * Verify that a value matches the schema of this class and convert it into a
-   * member.
-   */
-  static checked: (obj: any) => WireFeesJson;
-}
-
-
-/**
- * Information about wire transfer methods supported
- * by the exchange.
- */
address@hidden({extra: true})
-class WireDetailJson {
-  /**
-   * Name of the wire transfer method.
-   */
-  @Checkable.String
-  type: string;
-
-  /**
-   * Fees associated with the wire transfer method.
-   */
-  @Checkable.List(Checkable.Value(WireFeesJson))
-  fees: WireFeesJson[];
-
-  /**
-   * Verify that a value matches the schema of this class and convert it into a
-   * member.
-   */
-  static checked: (obj: any) => WireDetailJson;
-}
-
-
-/**
- * Badge that shows activity for the wallet.
- */
-export interface Badge {
-  /**
-   * Start indicating background activity.
-   */
-  startBusy(): void;
-
-  /**
-   * Stop indicating background activity.
-   */
-  stopBusy(): void;
-
-  /**
-   * Show the notification in the badge.
-   */
-  showNotification(): void;
-
-  /**
-   * Stop showing the notification.
-   */
-  clearNotification(): void;
-}
-
-
-/**
- * Nonce record as stored in the wallet's database.
- */
-export interface NonceRecord {
-  priv: string;
-  pub: string;
-}
-
-/**
- * Configuration key/value entries to configure
- * the wallet.
- */
-export interface ConfigRecord {
-  key: string;
-  value: any;
-}
-
-
-/**
- * Coin that we're depositing ourselves.
- */
-export interface DepositCoin {
-  coinPaySig: CoinPaySig;
-
-  /**
-   * Undefined if coin not deposited, otherwise signature
-   * from the exchange confirming the deposit.
-   */
-  depositedSig?: string;
-}
-
-/**
- * Record stored in the wallet's database when the user sends coins back to
- * their own bank account.  Stores the status of coins that are deposited to
- * the wallet itself, where the wallet acts as a "merchant" for the customer.
- */
-export interface CoinsReturnRecord {
-  /**
-   * Hash of the contract for sending coins to our own bank account.
-   */
-  contractTermsHash: string;
-
-  contractTerms: ContractTerms;
-
-  /**
-   * Private key where corresponding
-   * public key is used in the contract terms
-   * as merchant pub.
-   */
-  merchantPriv: string;
-
-  coins: DepositCoin[];
-
-  /**
-   * Exchange base URL to deposit coins at.
-   */
-  exchange: string;
-
-  /**
-   * Our own wire information for the deposit.
-   */
-  wire: any;
-}
-
 interface SpeculativePayData {
   payCoinInfo: PayCoinInfo;
   exchangeUrl: string;
@@ -348,14 +121,6 @@ interface SpeculativePayData {
  */
 export const WALLET_PROTOCOL_VERSION = "2:0:0";
 
-/**
- * Current database version, should be incremented
- * each time we do incompatible schema changes on the database.
- * In the future we might consider adding migration functions for
- * each version increment.
- */
-export const WALLET_DB_VERSION = 23;
-
 const builtinCurrencies: CurrencyRecord[] = [
   {
     auditors: [
@@ -390,17 +155,6 @@ function isWithdrawableDenom(d: DenominationRecord) {
 }
 
 
-function strcmp(s1: string, s2: string): number {
-  if (s1 < s2) {
-    return -1;
-  }
-  if (s1 > s2) {
-    return 1;
-  }
-  return 0;
-}
-
-
 interface SelectPayCoinsResult {
   cds: CoinWithDenom[];
   totalFees: AmountJson;
@@ -525,121 +279,6 @@ function getWithdrawDenomList(amountAvailable: AmountJson,
   return ds;
 }
 
-/* tslint:disable:completed-docs */
-
-/**
- * The stores and indices for the wallet database.
- */
-export namespace Stores {
-  class ExchangeStore extends Store<ExchangeRecord> {
-    constructor() {
-      super("exchanges", {keyPath: "baseUrl"});
-    }
-
-    pubKeyIndex = new Index<string, ExchangeRecord>(this, "pubKeyIndex", 
"masterPublicKey");
-  }
-
-  class NonceStore extends Store<NonceRecord> {
-    constructor() {
-      super("nonces", {keyPath: "pub"});
-    }
-  }
-
-  class CoinsStore extends Store<CoinRecord> {
-    constructor() {
-      super("coins", {keyPath: "coinPub"});
-    }
-
-    exchangeBaseUrlIndex = new Index<string, CoinRecord>(this, 
"exchangeBaseUrl", "exchangeBaseUrl");
-    denomPubIndex = new Index<string, CoinRecord>(this, "denomPubIndex", 
"denomPub");
-  }
-
-  class ProposalsStore extends Store<ProposalRecord> {
-    constructor() {
-      super("proposals", {
-        autoIncrement: true,
-        keyPath: "id",
-      });
-    }
-    timestampIndex = new Index<string, ProposalRecord>(this, "timestampIndex", 
"timestamp");
-  }
-
-  class PurchasesStore extends Store<PurchaseRecord> {
-    constructor() {
-      super("purchases", {keyPath: "contractTermsHash"});
-    }
-
-    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");
-  }
-
-  class DenominationsStore extends Store<DenominationRecord> {
-    constructor() {
-      // cast needed because of bug in type annotations
-      super("denominations",
-            {keyPath: ["exchangeBaseUrl", "denomPub"] as any as IDBKeyPath});
-    }
-
-    denomPubHashIndex = new Index<string, DenominationRecord>(this, 
"denomPubHashIndex", "denomPubHash");
-    exchangeBaseUrlIndex = new Index<string, DenominationRecord>(this, 
"exchangeBaseUrlIndex", "exchangeBaseUrl");
-    denomPubIndex = new Index<string, DenominationRecord>(this, 
"denomPubIndex", "denomPub");
-  }
-
-  class CurrenciesStore extends Store<CurrencyRecord> {
-    constructor() {
-      super("currencies", {keyPath: "name"});
-    }
-  }
-
-  class ConfigStore extends Store<ConfigRecord> {
-    constructor() {
-      super("config", {keyPath: "key"});
-    }
-  }
-
-  class ExchangeWireFeesStore extends Store<ExchangeWireFeesRecord> {
-    constructor() {
-      super("exchangeWireFees", {keyPath: "exchangeBaseUrl"});
-    }
-  }
-
-  class ReservesStore extends Store<ReserveRecord> {
-    constructor() {
-      super("reserves", {keyPath: "reserve_pub"});
-    }
-    timestampCreatedIndex = new Index<string, ReserveRecord>(this, 
"timestampCreatedIndex", "created");
-    timestampConfirmedIndex = new Index<string, ReserveRecord>(this, 
"timestampConfirmedIndex", "timestamp_confirmed");
-    timestampDepletedIndex = new Index<string, ReserveRecord>(this, 
"timestampDepletedIndex", "timestamp_depleted");
-  }
-
-  class TipsStore extends Store<TipRecord> {
-    constructor() {
-      super("tips", {keyPath: ["tipId", "merchantDomain"] as any as 
IDBKeyPath});
-    }
-    coinPubIndex = new Index<string, TipRecord>(this, "coinPubIndex", 
"coinPubs", { multiEntry: true });
-  }
-
-  export const coins = new CoinsStore();
-  export const coinsReturns = new Store<CoinsReturnRecord>("coinsReturns", 
{keyPath: "contractTermsHash"});
-  export const config = new ConfigStore();
-  export const currencies = new CurrenciesStore();
-  export const denominations = new DenominationsStore();
-  export const exchangeWireFees = new ExchangeWireFeesStore();
-  export const exchanges = new ExchangeStore();
-  export const nonces = new NonceStore();
-  export const precoins = new Store<PreCoinRecord>("precoins", {keyPath: 
"coinPub"});
-  export const proposals = new ProposalsStore();
-  export const refresh = new Store<RefreshSessionRecord>("refresh", {keyPath: 
"id", autoIncrement: true});
-  export const reserves = new ReservesStore();
-  export const purchases = new PurchasesStore();
-  export const tips = new TipsStore();
-}
-
-/* tslint:enable:completed-docs */
-
 
 interface CoinsForPaymentArgs {
   allowedAuditors: Auditor[];
@@ -1338,6 +977,15 @@ export class Wallet {
       timestamp_depleted: 0,
     };
 
+    const senderWire = req.senderWire;
+    if (isWireDetail(senderWire)) {
+      const rec = {
+        id: hash(senderWire),
+        senderWire,
+      };
+      await this.q().put(Stores.senderWires, rec);
+    }
+
     await this.updateExchangeUsedTime(req.exchange);
     const exchangeInfo = await this.updateExchangeFromUrl(req.exchange);
     const {isAudited, isTrusted} = await this.getExchangeTrust(exchangeInfo);
@@ -2671,7 +2319,7 @@ export class Wallet {
     Object.keys(m).map((e) => { exchangeWireTypes[e] = Array.from(m[e]); });
 
     const senderWiresSet = new Set();
-    await this.q().iter(Stores.reserves).map((x) => {
+    await this.q().iter(Stores.senderWires).map((x) => {
       if (x.senderWire) {
         senderWiresSet.add(canonicalJson(x.senderWire));
       }
diff --git a/src/walletTypes.ts b/src/walletTypes.ts
index cd0eee4c..3c7bff1e 100644
--- a/src/walletTypes.ts
+++ b/src/walletTypes.ts
@@ -315,7 +315,7 @@ export interface SenderWireInfos {
   exchangeWireTypes: { [exchangeBaseUrl: string]: string[] };
 
   /**
-   * Sender wire types stored in the wallet.
+   * Sender wire information stored in the wallet.
    */
   senderWires: object[];
 }
@@ -570,3 +570,29 @@ export class GetTipPlanchetsRequest {
    */
   static checked: (obj: any) => GetTipPlanchetsRequest;
 }
+
+
+/**
+ * Badge that shows activity for the wallet.
+ */
+export interface Badge {
+  /**
+   * Start indicating background activity.
+   */
+  startBusy(): void;
+
+  /**
+   * Stop indicating background activity.
+   */
+  stopBusy(): void;
+
+  /**
+   * Show the notification in the badge.
+   */
+  showNotification(): void;
+
+  /**
+   * Stop showing the notification.
+   */
+  clearNotification(): void;
+}
diff --git a/src/webex/chromeBadge.ts b/src/webex/chromeBadge.ts
index 3dfe9451..beb1dc44 100644
--- a/src/webex/chromeBadge.ts
+++ b/src/webex/chromeBadge.ts
@@ -16,7 +16,7 @@
 
 import {
   Badge,
-} from "../wallet";
+} from "../walletTypes";
 
 
 /**
diff --git a/src/webex/pages/return-coins.tsx b/src/webex/pages/return-coins.tsx
index 26db52ef..ff998d86 100644
--- a/src/webex/pages/return-coins.tsx
+++ b/src/webex/pages/return-coins.tsx
@@ -15,7 +15,7 @@
  */
 
 /**
- * View and edit auditors.
+ * Return coins to own bank account.
  *
  * @author Florian Dold
  */
diff --git a/src/webex/wxBackend.ts b/src/webex/wxBackend.ts
index a8ce5eeb..02a1543e 100644
--- a/src/webex/wxBackend.ts
+++ b/src/webex/wxBackend.ts
@@ -46,11 +46,14 @@ import {
 } from "../walletTypes";
 
 import {
-  Stores,
-  WALLET_DB_VERSION,
   Wallet,
 } from "../wallet";
 
+import {
+  Stores,
+  WALLET_DB_VERSION,
+} from "../dbTypes";
+
 
 import { ChromeBadge } from "./chromeBadge";
 import { MessageType } from "./messages";

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



reply via email to

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