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: compute full fees for refresh a


From: gnunet
Subject: [GNUnet-SVN] [taler-wallet-webex] 02/02: compute full fees for refresh and spending
Date: Wed, 30 Aug 2017 17:09:01 +0200

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

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

commit 008926b18470e7f394cd640302957b29728a9803
Author: Florian Dold <address@hidden>
AuthorDate: Wed Aug 30 17:08:54 2017 +0200

    compute full fees for refresh and spending
---
 src/crypto/cryptoApi.ts               |   5 +-
 src/crypto/cryptoWorker.ts            |   4 +-
 src/i18n/de.po                        |  97 +++++++++---------
 src/i18n/en-US.po                     |  83 +++++++--------
 src/i18n/fr.po                        |  83 +++++++--------
 src/i18n/it.po                        |  83 +++++++--------
 src/i18n/strings.ts                   |  60 +++++------
 src/i18n/taler-wallet-webex.pot       |  83 +++++++--------
 src/types.ts                          |  36 ++++++-
 src/wallet-test.ts                    |  34 +++----
 src/wallet.ts                         | 186 +++++++++++++++++++++++++---------
 src/webex/messages.ts                 |   6 +-
 src/webex/pages/confirm-contract.html |   1 +
 src/webex/pages/confirm-contract.tsx  |  43 ++++++--
 src/webex/pages/refund.tsx            |  17 ++--
 src/webex/renderHtml.tsx              |  32 ------
 src/webex/wxApi.ts                    |   5 +
 src/webex/wxBackend.ts                |   2 +
 18 files changed, 478 insertions(+), 382 deletions(-)

diff --git a/src/crypto/cryptoApi.ts b/src/crypto/cryptoApi.ts
index 227c3d34..00013f0d 100644
--- a/src/crypto/cryptoApi.ts
+++ b/src/crypto/cryptoApi.ts
@@ -26,6 +26,7 @@
 import {
   AmountJson,
   CoinRecord,
+  CoinWithDenom,
   ContractTerms,
   DenominationRecord,
   PayCoinInfo,
@@ -36,10 +37,6 @@ import {
   WireFee,
 } from "../types";
 
-import {
-  CoinWithDenom,
-} from "../wallet";
-
 import * as timer from "../timer";
 
 import { startWorker } from "./startWorker";
diff --git a/src/crypto/cryptoWorker.ts b/src/crypto/cryptoWorker.ts
index 1db6e62d..92b766e9 100644
--- a/src/crypto/cryptoWorker.ts
+++ b/src/crypto/cryptoWorker.ts
@@ -28,6 +28,7 @@ import {
   CoinPaySig,
   CoinRecord,
   CoinStatus,
+  CoinWithDenom,
   ContractTerms,
   DenominationRecord,
   PayCoinInfo,
@@ -41,9 +42,6 @@ import {
 import {
   canonicalJson,
 } from "../helpers";
-import {
-  CoinWithDenom,
-} from "../wallet";
 
 import {
   Amount,
diff --git a/src/i18n/de.po b/src/i18n/de.po
index cb57219c..38ce00c4 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:69
+#: src/webex/pages/confirm-contract.tsx:70
 #, c-format
 msgid "show more details\n"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:83
+#: src/webex/pages/confirm-contract.tsx:84
 #, c-format
 msgid "Accepted exchanges:"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:88
+#: src/webex/pages/confirm-contract.tsx:89
 #, c-format
 msgid "Exchanges in the wallet:"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:154
+#: src/webex/pages/confirm-contract.tsx:156
 #, 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:156
+#: src/webex/pages/confirm-contract.tsx:158
 #, c-format
 msgid ""
 "You do not have any funds from an exchange that is accepted by this "
@@ -56,67 +56,77 @@ msgid ""
 "wallet."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:213
+#: src/webex/pages/confirm-contract.tsx:214
+#, c-format
+msgid "The merchant%1$s offers you to purchase:\n"
+msgstr ""
+
+#: src/webex/pages/confirm-contract.tsx:232
+#, fuzzy, c-format
+msgid "Confirm payment"
+msgstr "Bezahlung bestätigen"
+
+#: src/webex/pages/confirm-create-reserve.tsx:179
 #, fuzzy, c-format
 msgid "Withdrawal fees:"
 msgstr "Abheben bei %1$s"
 
-#: src/webex/pages/confirm-create-reserve.tsx:214
+#: src/webex/pages/confirm-create-reserve.tsx:180
 #, c-format
 msgid "Rounding loss:"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:215
+#: src/webex/pages/confirm-create-reserve.tsx:181
 #, c-format
 msgid "Earliest expiration (for deposit): %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:220
+#: src/webex/pages/confirm-create-reserve.tsx:186
 #, c-format
 msgid "# Coins"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:221
+#: src/webex/pages/confirm-create-reserve.tsx:187
 #, c-format
 msgid "Value"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:222
+#: src/webex/pages/confirm-create-reserve.tsx:188
 #, fuzzy, c-format
 msgid "Withdraw Fee"
 msgstr "Abheben bei %1$s"
 
-#: src/webex/pages/confirm-create-reserve.tsx:223
+#: src/webex/pages/confirm-create-reserve.tsx:189
 #, c-format
 msgid "Refresh Fee"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:224
+#: src/webex/pages/confirm-create-reserve.tsx:190
 #, c-format
 msgid "Deposit Fee"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:278
+#: src/webex/pages/confirm-create-reserve.tsx:244
 #, c-format
 msgid "Select"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:294
+#: src/webex/pages/confirm-create-reserve.tsx:260
 #, c-format
 msgid "Error: URL may not be relative"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:362
+#: src/webex/pages/confirm-create-reserve.tsx:328
 #, c-format
 msgid "The exchange is trusted by the wallet.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:368
+#: src/webex/pages/confirm-create-reserve.tsx:334
 #, c-format
 msgid "The exchange is audited by a trusted auditor.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:374
+#: src/webex/pages/confirm-create-reserve.tsx:340
 #, c-format
 msgid ""
 "Warning:  The exchange is neither directly trusted nor audited by a trusted "
@@ -124,7 +134,7 @@ msgid ""
 "If you withdraw from this exchange, it will be trusted in the future.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:383
+#: src/webex/pages/confirm-create-reserve.tsx:349
 #, c-format
 msgid ""
 "Using exchange provider%1$s.\n"
@@ -132,63 +142,58 @@ msgid ""
 " %2$s in fees.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:397
+#: src/webex/pages/confirm-create-reserve.tsx:363
 #, c-format
 msgid ""
 "Waiting for a response from\n"
 " %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:408
-#, c-format
-msgid "A problem occured, see below. %1$s"
-msgstr ""
-
-#: src/webex/pages/confirm-create-reserve.tsx:414
+#: src/webex/pages/confirm-create-reserve.tsx:380
 #, c-format
 msgid ""
 "Information about fees will be available when an exchange provider is "
 "selected."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:457
+#: src/webex/pages/confirm-create-reserve.tsx:423
 #, c-format
 msgid "Accept fees and withdraw"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:462
+#: src/webex/pages/confirm-create-reserve.tsx:428
 #, c-format
 msgid "Change Exchange Provider"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:519
+#: src/webex/pages/confirm-create-reserve.tsx:485
 #, 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:607
+#: src/webex/pages/confirm-create-reserve.tsx:570
 #, c-format
 msgid ""
 "Oops, something went wrong. The wallet responded with error status (%1$s)."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:616
+#: src/webex/pages/confirm-create-reserve.tsx:579
 #, c-format
 msgid "Checking URL, please wait ..."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:630
+#: src/webex/pages/confirm-create-reserve.tsx:593
 #, c-format
 msgid "Can't parse amount: %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:637
+#: src/webex/pages/confirm-create-reserve.tsx:600
 #, c-format
 msgid "Can't parse wire_types: %1$s"
 msgstr ""
 
 #. TODO:generic error reporting function or component.
-#: src/webex/pages/confirm-create-reserve.tsx:663
+#: src/webex/pages/confirm-create-reserve.tsx:626
 #, c-format
 msgid "Fatal error: \"%1$s\"."
 msgstr ""
@@ -311,19 +316,6 @@ msgstr "Bezahlung bestätigen"
 msgid "Cancel"
 msgstr "Saldo"
 
-#: src/webex/renderHtml.tsx:51
-#, fuzzy, c-format
-msgid "The merchant%1$swants to enter a contract over%2$s with you.\n"
-msgstr ""
-"%1$s\n"
-"               möchte einen Vertrag über %2$s\n"
-"               mit Ihnen abschließen."
-
-#: src/webex/renderHtml.tsx:56
-#, fuzzy, c-format
-msgid "You are about to purchase:"
-msgstr "Sie sind dabei, Folgendes zu kaufen:"
-
 #: src/wire.ts:38
 #, c-format
 msgid "Invalid Wire"
@@ -345,6 +337,17 @@ msgid "Unknown Wire Detail"
 msgstr ""
 
 #, fuzzy
+#~ msgid "The merchant%1$swants to enter a contract over%2$s with you.\n"
+#~ msgstr ""
+#~ "%1$s\n"
+#~ "               möchte einen Vertrag über %2$s\n"
+#~ "               mit Ihnen abschließen."
+
+#, fuzzy
+#~ msgid "You are about to purchase:"
+#~ msgstr "Sie sind dabei, Folgendes zu kaufen:"
+
+#, fuzzy
 #~ msgid "Withdrawal fees: %1$s"
 #~ msgstr "Abheben bei %1$s"
 
diff --git a/src/i18n/en-US.po b/src/i18n/en-US.po
index a39c8331..66d4bd11 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:69
+#: src/webex/pages/confirm-contract.tsx:70
 #, c-format
 msgid "show more details\n"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:83
+#: src/webex/pages/confirm-contract.tsx:84
 #, c-format
 msgid "Accepted exchanges:"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:88
+#: src/webex/pages/confirm-contract.tsx:89
 #, c-format
 msgid "Exchanges in the wallet:"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:154
+#: src/webex/pages/confirm-contract.tsx:156
 #, 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:156
+#: src/webex/pages/confirm-contract.tsx:158
 #, c-format
 msgid ""
 "You do not have any funds from an exchange that is accepted by this "
@@ -56,67 +56,77 @@ msgid ""
 "wallet."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:213
+#: src/webex/pages/confirm-contract.tsx:214
+#, c-format
+msgid "The merchant%1$s offers you to purchase:\n"
+msgstr ""
+
+#: src/webex/pages/confirm-contract.tsx:232
+#, c-format
+msgid "Confirm payment"
+msgstr ""
+
+#: src/webex/pages/confirm-create-reserve.tsx:179
 #, c-format
 msgid "Withdrawal fees:"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:214
+#: src/webex/pages/confirm-create-reserve.tsx:180
 #, c-format
 msgid "Rounding loss:"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:215
+#: src/webex/pages/confirm-create-reserve.tsx:181
 #, c-format
 msgid "Earliest expiration (for deposit): %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:220
+#: src/webex/pages/confirm-create-reserve.tsx:186
 #, c-format
 msgid "# Coins"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:221
+#: src/webex/pages/confirm-create-reserve.tsx:187
 #, c-format
 msgid "Value"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:222
+#: src/webex/pages/confirm-create-reserve.tsx:188
 #, c-format
 msgid "Withdraw Fee"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:223
+#: src/webex/pages/confirm-create-reserve.tsx:189
 #, c-format
 msgid "Refresh Fee"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:224
+#: src/webex/pages/confirm-create-reserve.tsx:190
 #, c-format
 msgid "Deposit Fee"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:278
+#: src/webex/pages/confirm-create-reserve.tsx:244
 #, c-format
 msgid "Select"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:294
+#: src/webex/pages/confirm-create-reserve.tsx:260
 #, c-format
 msgid "Error: URL may not be relative"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:362
+#: src/webex/pages/confirm-create-reserve.tsx:328
 #, c-format
 msgid "The exchange is trusted by the wallet.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:368
+#: src/webex/pages/confirm-create-reserve.tsx:334
 #, c-format
 msgid "The exchange is audited by a trusted auditor.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:374
+#: src/webex/pages/confirm-create-reserve.tsx:340
 #, c-format
 msgid ""
 "Warning:  The exchange is neither directly trusted nor audited by a trusted "
@@ -124,7 +134,7 @@ msgid ""
 "If you withdraw from this exchange, it will be trusted in the future.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:383
+#: src/webex/pages/confirm-create-reserve.tsx:349
 #, c-format
 msgid ""
 "Using exchange provider%1$s.\n"
@@ -132,63 +142,58 @@ msgid ""
 " %2$s in fees.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:397
+#: src/webex/pages/confirm-create-reserve.tsx:363
 #, c-format
 msgid ""
 "Waiting for a response from\n"
 " %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:408
-#, c-format
-msgid "A problem occured, see below. %1$s"
-msgstr ""
-
-#: src/webex/pages/confirm-create-reserve.tsx:414
+#: src/webex/pages/confirm-create-reserve.tsx:380
 #, c-format
 msgid ""
 "Information about fees will be available when an exchange provider is "
 "selected."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:457
+#: src/webex/pages/confirm-create-reserve.tsx:423
 #, c-format
 msgid "Accept fees and withdraw"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:462
+#: src/webex/pages/confirm-create-reserve.tsx:428
 #, c-format
 msgid "Change Exchange Provider"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:519
+#: src/webex/pages/confirm-create-reserve.tsx:485
 #, 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:607
+#: src/webex/pages/confirm-create-reserve.tsx:570
 #, c-format
 msgid ""
 "Oops, something went wrong. The wallet responded with error status (%1$s)."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:616
+#: src/webex/pages/confirm-create-reserve.tsx:579
 #, c-format
 msgid "Checking URL, please wait ..."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:630
+#: src/webex/pages/confirm-create-reserve.tsx:593
 #, c-format
 msgid "Can't parse amount: %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:637
+#: src/webex/pages/confirm-create-reserve.tsx:600
 #, c-format
 msgid "Can't parse wire_types: %1$s"
 msgstr ""
 
 #. TODO:generic error reporting function or component.
-#: src/webex/pages/confirm-create-reserve.tsx:663
+#: src/webex/pages/confirm-create-reserve.tsx:626
 #, c-format
 msgid "Fatal error: \"%1$s\"."
 msgstr ""
@@ -311,16 +316,6 @@ msgstr ""
 msgid "Cancel"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:51
-#, c-format
-msgid "The merchant%1$swants to enter a contract over%2$s with you.\n"
-msgstr ""
-
-#: src/webex/renderHtml.tsx:56
-#, c-format
-msgid "You are about to purchase:"
-msgstr ""
-
 #: src/wire.ts:38
 #, c-format
 msgid "Invalid Wire"
diff --git a/src/i18n/fr.po b/src/i18n/fr.po
index dc271a74..d804bd20 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:69
+#: src/webex/pages/confirm-contract.tsx:70
 #, c-format
 msgid "show more details\n"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:83
+#: src/webex/pages/confirm-contract.tsx:84
 #, c-format
 msgid "Accepted exchanges:"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:88
+#: src/webex/pages/confirm-contract.tsx:89
 #, c-format
 msgid "Exchanges in the wallet:"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:154
+#: src/webex/pages/confirm-contract.tsx:156
 #, 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:156
+#: src/webex/pages/confirm-contract.tsx:158
 #, c-format
 msgid ""
 "You do not have any funds from an exchange that is accepted by this "
@@ -56,67 +56,77 @@ msgid ""
 "wallet."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:213
+#: src/webex/pages/confirm-contract.tsx:214
+#, c-format
+msgid "The merchant%1$s offers you to purchase:\n"
+msgstr ""
+
+#: src/webex/pages/confirm-contract.tsx:232
+#, c-format
+msgid "Confirm payment"
+msgstr ""
+
+#: src/webex/pages/confirm-create-reserve.tsx:179
 #, c-format
 msgid "Withdrawal fees:"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:214
+#: src/webex/pages/confirm-create-reserve.tsx:180
 #, c-format
 msgid "Rounding loss:"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:215
+#: src/webex/pages/confirm-create-reserve.tsx:181
 #, c-format
 msgid "Earliest expiration (for deposit): %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:220
+#: src/webex/pages/confirm-create-reserve.tsx:186
 #, c-format
 msgid "# Coins"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:221
+#: src/webex/pages/confirm-create-reserve.tsx:187
 #, c-format
 msgid "Value"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:222
+#: src/webex/pages/confirm-create-reserve.tsx:188
 #, c-format
 msgid "Withdraw Fee"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:223
+#: src/webex/pages/confirm-create-reserve.tsx:189
 #, c-format
 msgid "Refresh Fee"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:224
+#: src/webex/pages/confirm-create-reserve.tsx:190
 #, c-format
 msgid "Deposit Fee"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:278
+#: src/webex/pages/confirm-create-reserve.tsx:244
 #, c-format
 msgid "Select"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:294
+#: src/webex/pages/confirm-create-reserve.tsx:260
 #, c-format
 msgid "Error: URL may not be relative"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:362
+#: src/webex/pages/confirm-create-reserve.tsx:328
 #, c-format
 msgid "The exchange is trusted by the wallet.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:368
+#: src/webex/pages/confirm-create-reserve.tsx:334
 #, c-format
 msgid "The exchange is audited by a trusted auditor.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:374
+#: src/webex/pages/confirm-create-reserve.tsx:340
 #, c-format
 msgid ""
 "Warning:  The exchange is neither directly trusted nor audited by a trusted "
@@ -124,7 +134,7 @@ msgid ""
 "If you withdraw from this exchange, it will be trusted in the future.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:383
+#: src/webex/pages/confirm-create-reserve.tsx:349
 #, c-format
 msgid ""
 "Using exchange provider%1$s.\n"
@@ -132,63 +142,58 @@ msgid ""
 " %2$s in fees.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:397
+#: src/webex/pages/confirm-create-reserve.tsx:363
 #, c-format
 msgid ""
 "Waiting for a response from\n"
 " %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:408
-#, c-format
-msgid "A problem occured, see below. %1$s"
-msgstr ""
-
-#: src/webex/pages/confirm-create-reserve.tsx:414
+#: src/webex/pages/confirm-create-reserve.tsx:380
 #, c-format
 msgid ""
 "Information about fees will be available when an exchange provider is "
 "selected."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:457
+#: src/webex/pages/confirm-create-reserve.tsx:423
 #, c-format
 msgid "Accept fees and withdraw"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:462
+#: src/webex/pages/confirm-create-reserve.tsx:428
 #, c-format
 msgid "Change Exchange Provider"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:519
+#: src/webex/pages/confirm-create-reserve.tsx:485
 #, 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:607
+#: src/webex/pages/confirm-create-reserve.tsx:570
 #, c-format
 msgid ""
 "Oops, something went wrong. The wallet responded with error status (%1$s)."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:616
+#: src/webex/pages/confirm-create-reserve.tsx:579
 #, c-format
 msgid "Checking URL, please wait ..."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:630
+#: src/webex/pages/confirm-create-reserve.tsx:593
 #, c-format
 msgid "Can't parse amount: %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:637
+#: src/webex/pages/confirm-create-reserve.tsx:600
 #, c-format
 msgid "Can't parse wire_types: %1$s"
 msgstr ""
 
 #. TODO:generic error reporting function or component.
-#: src/webex/pages/confirm-create-reserve.tsx:663
+#: src/webex/pages/confirm-create-reserve.tsx:626
 #, c-format
 msgid "Fatal error: \"%1$s\"."
 msgstr ""
@@ -311,16 +316,6 @@ msgstr ""
 msgid "Cancel"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:51
-#, c-format
-msgid "The merchant%1$swants to enter a contract over%2$s with you.\n"
-msgstr ""
-
-#: src/webex/renderHtml.tsx:56
-#, c-format
-msgid "You are about to purchase:"
-msgstr ""
-
 #: src/wire.ts:38
 #, c-format
 msgid "Invalid Wire"
diff --git a/src/i18n/it.po b/src/i18n/it.po
index dc271a74..d804bd20 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:69
+#: src/webex/pages/confirm-contract.tsx:70
 #, c-format
 msgid "show more details\n"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:83
+#: src/webex/pages/confirm-contract.tsx:84
 #, c-format
 msgid "Accepted exchanges:"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:88
+#: src/webex/pages/confirm-contract.tsx:89
 #, c-format
 msgid "Exchanges in the wallet:"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:154
+#: src/webex/pages/confirm-contract.tsx:156
 #, 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:156
+#: src/webex/pages/confirm-contract.tsx:158
 #, c-format
 msgid ""
 "You do not have any funds from an exchange that is accepted by this "
@@ -56,67 +56,77 @@ msgid ""
 "wallet."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:213
+#: src/webex/pages/confirm-contract.tsx:214
+#, c-format
+msgid "The merchant%1$s offers you to purchase:\n"
+msgstr ""
+
+#: src/webex/pages/confirm-contract.tsx:232
+#, c-format
+msgid "Confirm payment"
+msgstr ""
+
+#: src/webex/pages/confirm-create-reserve.tsx:179
 #, c-format
 msgid "Withdrawal fees:"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:214
+#: src/webex/pages/confirm-create-reserve.tsx:180
 #, c-format
 msgid "Rounding loss:"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:215
+#: src/webex/pages/confirm-create-reserve.tsx:181
 #, c-format
 msgid "Earliest expiration (for deposit): %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:220
+#: src/webex/pages/confirm-create-reserve.tsx:186
 #, c-format
 msgid "# Coins"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:221
+#: src/webex/pages/confirm-create-reserve.tsx:187
 #, c-format
 msgid "Value"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:222
+#: src/webex/pages/confirm-create-reserve.tsx:188
 #, c-format
 msgid "Withdraw Fee"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:223
+#: src/webex/pages/confirm-create-reserve.tsx:189
 #, c-format
 msgid "Refresh Fee"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:224
+#: src/webex/pages/confirm-create-reserve.tsx:190
 #, c-format
 msgid "Deposit Fee"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:278
+#: src/webex/pages/confirm-create-reserve.tsx:244
 #, c-format
 msgid "Select"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:294
+#: src/webex/pages/confirm-create-reserve.tsx:260
 #, c-format
 msgid "Error: URL may not be relative"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:362
+#: src/webex/pages/confirm-create-reserve.tsx:328
 #, c-format
 msgid "The exchange is trusted by the wallet.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:368
+#: src/webex/pages/confirm-create-reserve.tsx:334
 #, c-format
 msgid "The exchange is audited by a trusted auditor.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:374
+#: src/webex/pages/confirm-create-reserve.tsx:340
 #, c-format
 msgid ""
 "Warning:  The exchange is neither directly trusted nor audited by a trusted "
@@ -124,7 +134,7 @@ msgid ""
 "If you withdraw from this exchange, it will be trusted in the future.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:383
+#: src/webex/pages/confirm-create-reserve.tsx:349
 #, c-format
 msgid ""
 "Using exchange provider%1$s.\n"
@@ -132,63 +142,58 @@ msgid ""
 " %2$s in fees.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:397
+#: src/webex/pages/confirm-create-reserve.tsx:363
 #, c-format
 msgid ""
 "Waiting for a response from\n"
 " %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:408
-#, c-format
-msgid "A problem occured, see below. %1$s"
-msgstr ""
-
-#: src/webex/pages/confirm-create-reserve.tsx:414
+#: src/webex/pages/confirm-create-reserve.tsx:380
 #, c-format
 msgid ""
 "Information about fees will be available when an exchange provider is "
 "selected."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:457
+#: src/webex/pages/confirm-create-reserve.tsx:423
 #, c-format
 msgid "Accept fees and withdraw"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:462
+#: src/webex/pages/confirm-create-reserve.tsx:428
 #, c-format
 msgid "Change Exchange Provider"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:519
+#: src/webex/pages/confirm-create-reserve.tsx:485
 #, 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:607
+#: src/webex/pages/confirm-create-reserve.tsx:570
 #, c-format
 msgid ""
 "Oops, something went wrong. The wallet responded with error status (%1$s)."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:616
+#: src/webex/pages/confirm-create-reserve.tsx:579
 #, c-format
 msgid "Checking URL, please wait ..."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:630
+#: src/webex/pages/confirm-create-reserve.tsx:593
 #, c-format
 msgid "Can't parse amount: %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:637
+#: src/webex/pages/confirm-create-reserve.tsx:600
 #, c-format
 msgid "Can't parse wire_types: %1$s"
 msgstr ""
 
 #. TODO:generic error reporting function or component.
-#: src/webex/pages/confirm-create-reserve.tsx:663
+#: src/webex/pages/confirm-create-reserve.tsx:626
 #, c-format
 msgid "Fatal error: \"%1$s\"."
 msgstr ""
@@ -311,16 +316,6 @@ msgstr ""
 msgid "Cancel"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:51
-#, c-format
-msgid "The merchant%1$swants to enter a contract over%2$s with you.\n"
-msgstr ""
-
-#: src/webex/renderHtml.tsx:56
-#, c-format
-msgid "You are about to purchase:"
-msgstr ""
-
 #: src/wire.ts:38
 #, c-format
 msgid "Invalid Wire"
diff --git a/src/i18n/strings.ts b/src/i18n/strings.ts
index 75672cbd..41c8d72a 100644
--- a/src/i18n/strings.ts
+++ b/src/i18n/strings.ts
@@ -39,6 +39,12 @@ strings['de'] = {
       "You do not have any funds from an exchange that is accepted by this 
merchant. None of the exchanges accepted by the merchant is known to your 
wallet.": [
         ""
       ],
+      "The merchant%1$s offers you to purchase:\n": [
+        ""
+      ],
+      "Confirm payment": [
+        "Bezahlung bestätigen"
+      ],
       "Withdrawal fees:": [
         "Abheben bei %1$s"
       ],
@@ -84,9 +90,6 @@ strings['de'] = {
       "Waiting for a response from\n %1$s": [
         ""
       ],
-      "A problem occured, see below. %1$s": [
-        ""
-      ],
       "Information about fees will be available when an exchange provider is 
selected.": [
         ""
       ],
@@ -180,12 +183,6 @@ strings['de'] = {
       "Cancel": [
         "Saldo"
       ],
-      "The merchant%1$swants to enter a contract over%2$s with you.\n": [
-        "%1$s\n               möchte einen Vertrag über %2$s\n               
mit Ihnen abschließen."
-      ],
-      "You are about to purchase:": [
-        "Sie sind dabei, Folgendes zu kaufen:"
-      ],
       "Invalid Wire": [
         ""
       ],
@@ -225,6 +222,12 @@ strings['en-US'] = {
       "You do not have any funds from an exchange that is accepted by this 
merchant. None of the exchanges accepted by the merchant is known to your 
wallet.": [
         ""
       ],
+      "The merchant%1$s offers you to purchase:\n": [
+        ""
+      ],
+      "Confirm payment": [
+        ""
+      ],
       "Withdrawal fees:": [
         ""
       ],
@@ -270,9 +273,6 @@ strings['en-US'] = {
       "Waiting for a response from\n %1$s": [
         ""
       ],
-      "A problem occured, see below. %1$s": [
-        ""
-      ],
       "Information about fees will be available when an exchange provider is 
selected.": [
         ""
       ],
@@ -366,12 +366,6 @@ strings['en-US'] = {
       "Cancel": [
         ""
       ],
-      "The merchant%1$swants to enter a contract over%2$s with you.\n": [
-        ""
-      ],
-      "You are about to purchase:": [
-        ""
-      ],
       "Invalid Wire": [
         ""
       ],
@@ -411,6 +405,12 @@ strings['fr'] = {
       "You do not have any funds from an exchange that is accepted by this 
merchant. None of the exchanges accepted by the merchant is known to your 
wallet.": [
         ""
       ],
+      "The merchant%1$s offers you to purchase:\n": [
+        ""
+      ],
+      "Confirm payment": [
+        ""
+      ],
       "Withdrawal fees:": [
         ""
       ],
@@ -456,9 +456,6 @@ strings['fr'] = {
       "Waiting for a response from\n %1$s": [
         ""
       ],
-      "A problem occured, see below. %1$s": [
-        ""
-      ],
       "Information about fees will be available when an exchange provider is 
selected.": [
         ""
       ],
@@ -552,12 +549,6 @@ strings['fr'] = {
       "Cancel": [
         ""
       ],
-      "The merchant%1$swants to enter a contract over%2$s with you.\n": [
-        ""
-      ],
-      "You are about to purchase:": [
-        ""
-      ],
       "Invalid Wire": [
         ""
       ],
@@ -597,6 +588,12 @@ strings['it'] = {
       "You do not have any funds from an exchange that is accepted by this 
merchant. None of the exchanges accepted by the merchant is known to your 
wallet.": [
         ""
       ],
+      "The merchant%1$s offers you to purchase:\n": [
+        ""
+      ],
+      "Confirm payment": [
+        ""
+      ],
       "Withdrawal fees:": [
         ""
       ],
@@ -642,9 +639,6 @@ strings['it'] = {
       "Waiting for a response from\n %1$s": [
         ""
       ],
-      "A problem occured, see below. %1$s": [
-        ""
-      ],
       "Information about fees will be available when an exchange provider is 
selected.": [
         ""
       ],
@@ -738,12 +732,6 @@ strings['it'] = {
       "Cancel": [
         ""
       ],
-      "The merchant%1$swants to enter a contract over%2$s with you.\n": [
-        ""
-      ],
-      "You are about to purchase:": [
-        ""
-      ],
       "Invalid Wire": [
         ""
       ],
diff --git a/src/i18n/taler-wallet-webex.pot b/src/i18n/taler-wallet-webex.pot
index dc271a74..d804bd20 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:69
+#: src/webex/pages/confirm-contract.tsx:70
 #, c-format
 msgid "show more details\n"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:83
+#: src/webex/pages/confirm-contract.tsx:84
 #, c-format
 msgid "Accepted exchanges:"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:88
+#: src/webex/pages/confirm-contract.tsx:89
 #, c-format
 msgid "Exchanges in the wallet:"
 msgstr ""
 
-#: src/webex/pages/confirm-contract.tsx:154
+#: src/webex/pages/confirm-contract.tsx:156
 #, 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:156
+#: src/webex/pages/confirm-contract.tsx:158
 #, c-format
 msgid ""
 "You do not have any funds from an exchange that is accepted by this "
@@ -56,67 +56,77 @@ msgid ""
 "wallet."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:213
+#: src/webex/pages/confirm-contract.tsx:214
+#, c-format
+msgid "The merchant%1$s offers you to purchase:\n"
+msgstr ""
+
+#: src/webex/pages/confirm-contract.tsx:232
+#, c-format
+msgid "Confirm payment"
+msgstr ""
+
+#: src/webex/pages/confirm-create-reserve.tsx:179
 #, c-format
 msgid "Withdrawal fees:"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:214
+#: src/webex/pages/confirm-create-reserve.tsx:180
 #, c-format
 msgid "Rounding loss:"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:215
+#: src/webex/pages/confirm-create-reserve.tsx:181
 #, c-format
 msgid "Earliest expiration (for deposit): %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:220
+#: src/webex/pages/confirm-create-reserve.tsx:186
 #, c-format
 msgid "# Coins"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:221
+#: src/webex/pages/confirm-create-reserve.tsx:187
 #, c-format
 msgid "Value"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:222
+#: src/webex/pages/confirm-create-reserve.tsx:188
 #, c-format
 msgid "Withdraw Fee"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:223
+#: src/webex/pages/confirm-create-reserve.tsx:189
 #, c-format
 msgid "Refresh Fee"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:224
+#: src/webex/pages/confirm-create-reserve.tsx:190
 #, c-format
 msgid "Deposit Fee"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:278
+#: src/webex/pages/confirm-create-reserve.tsx:244
 #, c-format
 msgid "Select"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:294
+#: src/webex/pages/confirm-create-reserve.tsx:260
 #, c-format
 msgid "Error: URL may not be relative"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:362
+#: src/webex/pages/confirm-create-reserve.tsx:328
 #, c-format
 msgid "The exchange is trusted by the wallet.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:368
+#: src/webex/pages/confirm-create-reserve.tsx:334
 #, c-format
 msgid "The exchange is audited by a trusted auditor.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:374
+#: src/webex/pages/confirm-create-reserve.tsx:340
 #, c-format
 msgid ""
 "Warning:  The exchange is neither directly trusted nor audited by a trusted "
@@ -124,7 +134,7 @@ msgid ""
 "If you withdraw from this exchange, it will be trusted in the future.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:383
+#: src/webex/pages/confirm-create-reserve.tsx:349
 #, c-format
 msgid ""
 "Using exchange provider%1$s.\n"
@@ -132,63 +142,58 @@ msgid ""
 " %2$s in fees.\n"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:397
+#: src/webex/pages/confirm-create-reserve.tsx:363
 #, c-format
 msgid ""
 "Waiting for a response from\n"
 " %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:408
-#, c-format
-msgid "A problem occured, see below. %1$s"
-msgstr ""
-
-#: src/webex/pages/confirm-create-reserve.tsx:414
+#: src/webex/pages/confirm-create-reserve.tsx:380
 #, c-format
 msgid ""
 "Information about fees will be available when an exchange provider is "
 "selected."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:457
+#: src/webex/pages/confirm-create-reserve.tsx:423
 #, c-format
 msgid "Accept fees and withdraw"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:462
+#: src/webex/pages/confirm-create-reserve.tsx:428
 #, c-format
 msgid "Change Exchange Provider"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:519
+#: src/webex/pages/confirm-create-reserve.tsx:485
 #, 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:607
+#: src/webex/pages/confirm-create-reserve.tsx:570
 #, c-format
 msgid ""
 "Oops, something went wrong. The wallet responded with error status (%1$s)."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:616
+#: src/webex/pages/confirm-create-reserve.tsx:579
 #, c-format
 msgid "Checking URL, please wait ..."
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:630
+#: src/webex/pages/confirm-create-reserve.tsx:593
 #, c-format
 msgid "Can't parse amount: %1$s"
 msgstr ""
 
-#: src/webex/pages/confirm-create-reserve.tsx:637
+#: src/webex/pages/confirm-create-reserve.tsx:600
 #, c-format
 msgid "Can't parse wire_types: %1$s"
 msgstr ""
 
 #. TODO:generic error reporting function or component.
-#: src/webex/pages/confirm-create-reserve.tsx:663
+#: src/webex/pages/confirm-create-reserve.tsx:626
 #, c-format
 msgid "Fatal error: \"%1$s\"."
 msgstr ""
@@ -311,16 +316,6 @@ msgstr ""
 msgid "Cancel"
 msgstr ""
 
-#: src/webex/renderHtml.tsx:51
-#, c-format
-msgid "The merchant%1$swants to enter a contract over%2$s with you.\n"
-msgstr ""
-
-#: src/webex/renderHtml.tsx:56
-#, c-format
-msgid "You are about to purchase:"
-msgstr ""
-
 #: src/wire.ts:38
 #, c-format
 msgid "Invalid Wire"
diff --git a/src/types.ts b/src/types.ts
index d016b7fe..90fe7cf9 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -822,6 +822,10 @@ export enum CoinStatus {
    * Coin fully paid back.
    */
   PaybackDone,
+  /**
+   * Coin was dirty but can't be refreshed.
+   */
+  Useless,
 }
 
 
@@ -1467,7 +1471,10 @@ export function mkAmount(value: number, fraction: 
number, currency: string): Amo
 /**
  * Possible results for checkPay.
  */
-export type CheckPayResult = "paid" | "payment-possible" | 
"insufficient-balance";
+export interface CheckPayResult {
+  status: "paid" | "payment-possible" | "insufficient-balance";
+  coinSelection?: CoinSelectionResult;
+}
 
 /**
  * Possible results for confirmPay.
@@ -1695,3 +1702,30 @@ export interface PurchaseRecord {
   refundsPending: { [refundSig: string]: RefundPermission };
   refundsDone: { [refundSig: string]: RefundPermission };
 }
+
+
+/**
+ * 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;
+}
diff --git a/src/wallet-test.ts b/src/wallet-test.ts
index acd776d6..037cc759 100644
--- a/src/wallet-test.ts
+++ b/src/wallet-test.ts
@@ -29,7 +29,7 @@ function a(x: string): types.AmountJson {
 }
 
 
-function fakeCwd(current: string, value: string, feeDeposit: string): 
wallet.CoinWithDenom {
+function fakeCwd(current: string, value: string, feeDeposit: string): 
types.CoinWithDenom {
   return {
     coin: {
       blindingKey: "(mock)",
@@ -64,89 +64,89 @@ function fakeCwd(current: string, value: string, 
feeDeposit: string): wallet.Coi
 
 
 test("coin selection 1", (t) => {
-  const cds: wallet.CoinWithDenom[] = [
+  const cds: types.CoinWithDenom[] = [
     fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.1"),
     fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.0"),
   ];
 
-  const res = wallet.selectPayCoins(cds, a("EUR:2.0"), a("EUR:0.1"));
+  const res = wallet.selectPayCoins([], cds, a("EUR:2.0"), a("EUR:0.1"));
   if (!res) {
     t.fail();
     return;
   }
-  t.true(res.length === 2);
+  t.true(res.cds.length === 2);
   t.pass();
 });
 
 
 test("coin selection 2", (t) => {
-  const cds: wallet.CoinWithDenom[] = [
+  const cds: types.CoinWithDenom[] = [
     fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
     fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.0"),
     // Merchant covers the fee, this one shouldn't be used
     fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.0"),
   ];
-  const res = wallet.selectPayCoins(cds, a("EUR:2.0"), a("EUR:0.5"));
+  const res = wallet.selectPayCoins([], cds, a("EUR:2.0"), a("EUR:0.5"));
   if (!res) {
     t.fail();
     return;
   }
-  t.true(res.length === 2);
+  t.true(res.cds.length === 2);
   t.pass();
 });
 
 
 test("coin selection 3", (t) => {
-  const cds: wallet.CoinWithDenom[] = [
+  const cds: types.CoinWithDenom[] = [
     fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
     fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
     // this coin should be selected instead of previous one with fee
     fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.0"),
   ];
-  const res = wallet.selectPayCoins(cds, a("EUR:2.0"), a("EUR:0.5"));
+  const res = wallet.selectPayCoins([], cds, a("EUR:2.0"), a("EUR:0.5"));
   if (!res) {
     t.fail();
     return;
   }
-  t.true(res.length === 2);
+  t.true(res.cds.length === 2);
   t.pass();
 });
 
 
 test("coin selection 4", (t) => {
-  const cds: wallet.CoinWithDenom[] = [
+  const cds: types.CoinWithDenom[] = [
     fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
     fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
     fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
   ];
-  const res = wallet.selectPayCoins(cds, a("EUR:2.0"), a("EUR:0.2"));
+  const res = wallet.selectPayCoins([], cds, a("EUR:2.0"), a("EUR:0.2"));
   if (!res) {
     t.fail();
     return;
   }
-  t.true(res.length === 3);
+  t.true(res.cds.length === 3);
   t.pass();
 });
 
 
 test("coin selection 5", (t) => {
-  const cds: wallet.CoinWithDenom[] = [
+  const cds: types.CoinWithDenom[] = [
     fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
     fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
     fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
   ];
-  const res = wallet.selectPayCoins(cds, a("EUR:4.0"), a("EUR:0.2"));
+  const res = wallet.selectPayCoins([], cds, a("EUR:4.0"), a("EUR:0.2"));
   t.true(!res);
   t.pass();
 });
 
 
 test("coin selection 6", (t) => {
-  const cds: wallet.CoinWithDenom[] = [
+  const cds: types.CoinWithDenom[] = [
     fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
     fakeCwd("EUR:1.0", "EUR:1.0", "EUR:0.5"),
   ];
-  const res = wallet.selectPayCoins(cds, a("EUR:2.0"), a("EUR:0.2"));
+  const res = wallet.selectPayCoins([], cds, a("EUR:2.0"), a("EUR:0.2"));
   t.true(!res);
   t.pass();
 });
diff --git a/src/wallet.ts b/src/wallet.ts
index 3d095fc0..f194755e 100644
--- a/src/wallet.ts
+++ b/src/wallet.ts
@@ -51,7 +51,9 @@ import {
   CheckPayResult,
   CoinPaySig,
   CoinRecord,
+  CoinSelectionResult,
   CoinStatus,
+  CoinWithDenom,
   ConfirmPayResult,
   ConfirmReserveRequest,
   ContractTerms,
@@ -72,8 +74,10 @@ import {
   PaybackConfirmation,
   PreCoinRecord,
   ProposalRecord,
+  PurchaseRecord,
   QueryPaymentResult,
   RefreshSessionRecord,
+  RefundPermission,
   ReserveCreationInfo,
   ReserveRecord,
   ReturnCoinsRequest,
@@ -82,27 +86,10 @@ import {
   WalletBalanceEntry,
   WireFee,
   WireInfo,
-  RefundPermission,
-  PurchaseRecord,
 } from "./types";
 import URI = require("urijs");
 
 
-/**
- * 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;
-}
-
 
 /**
  * Element of the payback list that the
@@ -370,30 +357,62 @@ 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;
+}
+
+
 /**
- * Result of selecting coins, contains the exchange, and selected
- * coins with their denomination.
+ * Get the amount that we lose when refreshing a coin of the given denomination
+ * with a certain amount left.
+ *
+ * If the amount left is zero, then the refresh cost
+ * is also considered to be zero.  If a refresh isn't possible (e.g. due to 
lack of
+ * the right denominations), then the cost is the full amount left.
+ *
+ * Considers refresh fees, withdrawal fees after refresh and amounts too small
+ * to refresh.
  */
-export type CoinSelectionResult = {exchangeUrl: string, cds: 
CoinWithDenom[]}|undefined;
+export function getTotalRefreshCost(denoms: DenominationRecord[], 
refreshedDenom: DenominationRecord, amountLeft: AmountJson): AmountJson {
+  const withdrawAmount = Amounts.sub(amountLeft, 
refreshedDenom.feeRefresh).amount;
+  const withdrawDenoms = getWithdrawDenomList(withdrawAmount, denoms);
+  const resultingAmount = 
Amounts.add(Amounts.getZero(withdrawAmount.currency), ...withdrawDenoms.map((d) 
=> d.value)).amount;
+  const totalCost = Amounts.sub(amountLeft, resultingAmount).amount;
+  console.log("total refresh cost for", amountToPretty(amountLeft), "is", 
amountToPretty(totalCost));
+  return totalCost;
+}
+
 
 /**
  * Select coins for a payment under the merchant's constraints.
+ *
+ * @param denoms all available denoms, used to compute refresh fees
  */
-export function selectPayCoins(cds: CoinWithDenom[], paymentAmount: AmountJson,
-                               depositFeeLimit: AmountJson): 
CoinWithDenom[]|undefined {
+export function selectPayCoins(denoms: DenominationRecord[], cds: 
CoinWithDenom[], paymentAmount: AmountJson,
+                               depositFeeLimit: AmountJson): 
SelectPayCoinsResult|undefined {
   if (cds.length === 0) {
     return undefined;
   }
-  // Sort by ascending deposit fee
-  cds.sort((o1, o2) => Amounts.cmp(o1.denom.feeDeposit,
-                                   o2.denom.feeDeposit));
+  // Sort by ascending deposit fee and denomPub if deposit fee is the same
+  // (to guarantee deterministic results)
+  cds.sort((o1, o2) => Amounts.cmp(o1.denom.feeDeposit, o2.denom.feeDeposit) 
|| strcmp(o1.denom.denomPub, o2.denom.denomPub));
   const currency = cds[0].denom.value.currency;
   const cdsResult: CoinWithDenom[] = [];
-  let accFee: AmountJson = Amounts.getZero(currency);
+  let accDepositFee: AmountJson = Amounts.getZero(currency);
   let accAmount: AmountJson = Amounts.getZero(currency);
-  let isBelowFee = false;
-  let coversAmount = false;
-  let coversAmountWithFee = false;
   for (const {coin, denom} of cds) {
     if (coin.suspended) {
       continue;
@@ -405,18 +424,30 @@ export function selectPayCoins(cds: CoinWithDenom[], 
paymentAmount: AmountJson,
       continue;
     }
     cdsResult.push({coin, denom});
-    accFee = Amounts.add(denom.feeDeposit, accFee).amount;
+    accDepositFee = Amounts.add(denom.feeDeposit, accDepositFee).amount;
+    let leftAmount = Amounts.sub(coin.currentAmount, 
Amounts.sub(paymentAmount, accAmount).amount).amount;
     accAmount = Amounts.add(coin.currentAmount, accAmount).amount;
-    coversAmount = Amounts.cmp(accAmount, paymentAmount) >= 0;
-    coversAmountWithFee = Amounts.cmp(accAmount,
+    const coversAmount = Amounts.cmp(accAmount, paymentAmount) >= 0;
+    const coversAmountWithFee = Amounts.cmp(accAmount,
                                       Amounts.add(paymentAmount,
                                                   denom.feeDeposit).amount) >= 
0;
-    isBelowFee = Amounts.cmp(accFee, depositFeeLimit) <= 0;
+    const isBelowFee = Amounts.cmp(accDepositFee, depositFeeLimit) <= 0;
 
-    console.log("coin selection", { coversAmount, isBelowFee, accFee, 
accAmount, paymentAmount });
+    console.log("coin selection", { coversAmount, isBelowFee, accDepositFee, 
accAmount, paymentAmount });
 
     if ((coversAmount && isBelowFee) || coversAmountWithFee) {
-      return cdsResult;
+      let depositFeeToCover = Amounts.sub(accDepositFee, 
depositFeeLimit).amount;
+      leftAmount = Amounts.sub(leftAmount, depositFeeToCover).amount;
+      console.log("deposit fee to cover", amountToPretty(depositFeeToCover));
+
+      let totalFees: AmountJson = Amounts.getZero(currency);
+      if (coversAmountWithFee && !isBelowFee) {
+        // these are the fees the customer has to pay
+        // because the merchant doesn't cover them
+        totalFees = Amounts.sub(depositFeeLimit, accDepositFee).amount;
+      }
+      totalFees = Amounts.add(totalFees, getTotalRefreshCost(denoms, denom, 
leftAmount)).amount;
+      return { cds: cdsResult, totalFees };
     }
   }
   return undefined;
@@ -729,6 +760,8 @@ export class Wallet {
       return [];
     }
 
+    const denoms = await 
this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex, 
exchange.baseUrl).toArray();
+
     // Denomination of the first coin, we assume that all other
     // coins have the same currency
     const firstDenom = await this.q().get(Stores.denominations,
@@ -763,7 +796,11 @@ export class Wallet {
 
     console.log("coin return:  selecting from possible coins", { cds, amount } 
);
 
-    return selectPayCoins(cds, amount, amount);
+    const res = selectPayCoins(denoms, cds, amount, amount);
+    if (res) {
+      return res.cds;
+    }
+    return undefined
   }
 
 
@@ -771,7 +808,7 @@ export class Wallet {
    * Get exchanges and associated coins that are still spendable,
    * but only if the sum the coins' remaining value exceeds the payment amount.
    */
-  private async getCoinsForPayment(args: CoinsForPaymentArgs): 
Promise<CoinSelectionResult> {
+  private async getCoinsForPayment(args: CoinsForPaymentArgs): 
Promise<CoinSelectionResult|undefined> {
     const {
       allowedAuditors,
       allowedExchanges,
@@ -821,6 +858,7 @@ export class Wallet {
                                           
.iterIndex(Stores.coins.exchangeBaseUrlIndex,
                                                      exchange.baseUrl)
                                           .toArray();
+      const denoms = await 
this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex, 
exchange.baseUrl).toArray();
       if (!coins || coins.length === 0) {
         continue;
       }
@@ -862,6 +900,7 @@ export class Wallet {
         continue;
       }
 
+      let totalFees = Amounts.getZero(currency);
       let wireFee: AmountJson|undefined;
       for (const fee of (fees.feesForType[wireMethod] || [])) {
         if (fee.startStamp >= wireFeeTime && fee.endStamp <= wireFeeTime) {
@@ -873,15 +912,18 @@ export class Wallet {
       if (wireFee) {
         const amortizedWireFee = Amounts.divide(wireFee, wireFeeAmortization);
         if (Amounts.cmp(wireFeeLimit, amortizedWireFee) < 0) {
+          totalFees = Amounts.add(amortizedWireFee, totalFees).amount;
           remainingAmount = Amounts.add(amortizedWireFee, 
remainingAmount).amount;
         }
       }
 
-      const res = selectPayCoins(cds, remainingAmount, depositFeeLimit);
+      const res = selectPayCoins(denoms, cds, remainingAmount, 
depositFeeLimit);
       if (res) {
+        totalFees = Amounts.add(totalFees, res.totalFees).amount;
         return {
-          cds: res,
+          cds: res.cds,
           exchangeUrl: exchange.baseUrl,
+          totalFees,
         };
       }
     }
@@ -1014,7 +1056,7 @@ export class Wallet {
     // First check if we already payed for it.
     const purchase = await this.q().get(Stores.purchases, 
proposal.contractTermsHash);
     if (purchase) {
-      return "paid";
+      return { status: "paid" };
     }
 
     // If not already payed, check if we could pay for it.
@@ -1031,9 +1073,9 @@ export class Wallet {
 
     if (!res) {
       console.log("not confirming payment, insufficient coins");
-      return "insufficient-balance";
+      return { status: "insufficient-balance" };
     }
-    return "payment-possible";
+    return { status: "payment-possible", coinSelection: res };
   }
 
 
@@ -1653,6 +1695,7 @@ export class Wallet {
       console.log("suspending coin", c);
       c.suspended = true;
       q.put(Stores.coins, c);
+      this.notifier.notify();
     });
     await q.finish();
   }
@@ -1840,11 +1883,14 @@ export class Wallet {
       if (c.suspended) {
         return balance;
       }
-      if (!(c.status === CoinStatus.Fresh)) {
+      if (c.status === CoinStatus.Fresh) {
+        addTo(balance, "available", c.currentAmount, c.exchangeBaseUrl);
+        return balance;
+      }
+      if (c.status === CoinStatus.Dirty) {
+        addTo(balance, "pendingIncoming", c.currentAmount, c.exchangeBaseUrl);
         return balance;
       }
-      console.log("collecting balance");
-      addTo(balance, "available", c.currentAmount, c.exchangeBaseUrl);
       return balance;
     }
 
@@ -1978,6 +2024,9 @@ export class Wallet {
 
     if (newCoinDenoms.length === 0) {
       console.log(`not refreshing, available amount 
${amountToPretty(availableAmount)} too small`);
+      coin.status = CoinStatus.Useless;
+      await this.q().put(Stores.coins, coin);
+      this.notifier.notify();
       return undefined;
     }
 
@@ -2007,6 +2056,7 @@ export class Wallet {
     query.put(Stores.refresh, refreshSession, "refreshKey")
          .mutate(Stores.coins, coin.coinPub, mutateCoin);
     await query.finish();
+    this.notifier.notify();
 
     const key = query.key("refreshKey");
     if (!key || typeof key !== "number") {
@@ -2026,7 +2076,15 @@ export class Wallet {
       console.log("got old session for", oldCoinPub, session);
       this.continueRefreshSession(session);
     }
-    let refreshSession = await this.createRefreshSession(oldCoinPub);
+    const coin = await this.q().get(Stores.coins, oldCoinPub);
+    if (!coin) {
+      console.warn("can't refresh, coin not in database");
+      return;
+    }
+    if (coin.status === CoinStatus.Useless || coin.status === 
CoinStatus.Fresh) {
+      return;
+    }
+    const refreshSession = await this.createRefreshSession(oldCoinPub);
     if (!refreshSession) {
       // refreshing not necessary
       console.log("not refreshing", oldCoinPub);
@@ -2106,6 +2164,7 @@ export class Wallet {
     refreshSession.norevealIndex = norevealIndex;
 
     await this.q().put(Stores.refresh, refreshSession).finish();
+    this.notifier.notify();
   }
 
 
@@ -2186,6 +2245,7 @@ export class Wallet {
               .putAll(Stores.coins, coins)
               .put(Stores.refresh, refreshSession)
               .finish();
+    this.notifier.notify();
   }
 
 
@@ -2344,6 +2404,7 @@ export class Wallet {
     // from the reserve for the payback request.
     reserve.hasPayback = true;
     await this.q().put(Stores.coins, coin).put(Stores.reserves, reserve);
+    this.notifier.notify();
 
     const paybackRequest = await this.cryptoApi.createPaybackRequest(coin);
     const reqUrl = new URI("payback").absoluteTo(coin.exchangeBaseUrl);
@@ -2361,6 +2422,7 @@ export class Wallet {
     }
     coin.status = CoinStatus.PaybackDone;
     await this.q().put(Stores.coins, coin);
+    this.notifier.notify();
     await this.updateReserve(reservePub!);
   }
 
@@ -2502,6 +2564,7 @@ export class Wallet {
               .put(Stores.coinsReturns, coinsReturnRecord)
               .putAll(Stores.coins, payCoinInfo.map((pci) => pci.updatedCoin))
               .finish();
+    this.notifier.notify();
 
     this.depositReturnedCoins(coinsReturnRecord);
   }
@@ -2558,6 +2621,7 @@ export class Wallet {
         }
       }
       await this.q().put(Stores.coinsReturns, currentCrr);
+      this.notifier.notify();
     }
   }
 
@@ -2666,4 +2730,34 @@ export class Wallet {
   async getPurchase(contractTermsHash: string): 
Promise<PurchaseRecord|undefined> {
     return this.q().get(Stores.purchases, contractTermsHash);
   }
+
+  async getFullRefundFees(refundPermissions: RefundPermission[]): 
Promise<AmountJson> {
+    if (refundPermissions.length === 0) {
+      throw Error("no refunds given");
+    }
+    const coin0 = await this.q().get(Stores.coins, 
refundPermissions[0].coin_pub)
+    if (!coin0) {
+      throw Error("coin not found");
+    }
+    let feeAcc = Amounts.getZero(refundPermissions[0].refund_amount.currency);
+
+    const denoms = await 
this.q().iterIndex(Stores.denominations.exchangeBaseUrlIndex, 
coin0.exchangeBaseUrl).toArray();
+    for (const rp of refundPermissions) {
+      const coin = await this.q().get(Stores.coins, rp.coin_pub);
+      if (!coin) {
+        throw Error("coin not found");
+      }
+      const denom = await this.q().get(Stores.denominations, 
[coin0.exchangeBaseUrl, coin.denomPub]);
+      if (!denom) {
+        throw Error(`denom not found (${coin.denomPub})`);
+      }
+      // FIXME:  this assumes that the refund already happened.
+      // When it hasn't, the refresh cost is inaccurate.  To fix this,
+      // we need introduce a flag to tell if a coin was refunded or
+      // refreshed normally (and what about incremental refunds?)
+      const refreshCost = getTotalRefreshCost(denoms, denom, 
Amounts.sub(rp.refund_amount, rp.refund_fee).amount);
+      feeAcc = Amounts.add(feeAcc, refreshCost, rp.refund_fee).amount;
+    }
+    return feeAcc;
+  }
 }
diff --git a/src/webex/messages.ts b/src/webex/messages.ts
index 7de28b9e..122bd8fe 100644
--- a/src/webex/messages.ts
+++ b/src/webex/messages.ts
@@ -191,7 +191,11 @@ export interface MessageMap {
   "get-purchase": {
     request: any;
     response: void;
-  }
+  };
+  "get-full-refund-fees": {
+    request: { refundPermissions: types.RefundPermission[] };
+    response: void;
+  };
 }
 
 /**
diff --git a/src/webex/pages/confirm-contract.html 
b/src/webex/pages/confirm-contract.html
index 394de582..223d413d 100644
--- a/src/webex/pages/confirm-contract.html
+++ b/src/webex/pages/confirm-contract.html
@@ -5,6 +5,7 @@
   <meta charset="UTF-8">
   <title>Taler Wallet: Confirm Reserve Creation</title>
 
+  <link rel="stylesheet" type="text/css" href="../style/pure.css">
   <link rel="stylesheet" type="text/css" href="../style/wallet.css">
 
   <link rel="icon" href="/img/icon.png">
diff --git a/src/webex/pages/confirm-contract.tsx 
b/src/webex/pages/confirm-contract.tsx
index fa71b102..5436cb5a 100644
--- a/src/webex/pages/confirm-contract.tsx
+++ b/src/webex/pages/confirm-contract.tsx
@@ -25,12 +25,13 @@
  */
 import * as i18n from "../../i18n";
 import {
+  CheckPayResult,
   ContractTerms,
   ExchangeRecord,
   ProposalRecord,
 } from "../../types";
 
-import { renderContractTerms } from "../renderHtml";
+import { renderAmount } from "../renderHtml";
 import * as wxApi from "../wxApi";
 
 import * as React from "react";
@@ -113,6 +114,7 @@ interface ContractPromptState {
    * when pressing pay.
    */
   holdCheck: boolean;
+  payStatus?: CheckPayResult;
 }
 
 class ContractPrompt extends React.Component<ContractPromptProps, 
ContractPromptState> {
@@ -150,7 +152,7 @@ class ContractPrompt extends 
React.Component<ContractPromptProps, ContractPrompt
       return;
     }
     const payStatus = await wxApi.checkPay(this.props.proposalId);
-    if (payStatus === "insufficient-balance") {
+    if (payStatus.status === "insufficient-balance") {
       const msgInsufficient = i18n.str`You have insufficient funds of the 
requested currency in your wallet.`;
       // tslint:disable-next-line:max-line-length
       const msgNoMatch = i18n.str`You do not have any funds from an exchange 
that is accepted by this merchant. None of the exchanges accepted by the 
merchant is known to your wallet.`;
@@ -166,10 +168,10 @@ class ContractPrompt extends 
React.Component<ContractPromptProps, ContractPrompt
         this.setState({error: msgInsufficient});
       }
       this.setState({payDisabled: true});
-    } else if (payStatus === "paid") {
-      this.setState({alreadyPaid: true, payDisabled: false, error: null});
+    } else if (payStatus.status === "paid") {
+      this.setState({alreadyPaid: true, payDisabled: false, error: null, 
payStatus});
     } else {
-      this.setState({payDisabled: false, error: null});
+      this.setState({payDisabled: false, error: null, payStatus});
     }
   }
 
@@ -189,7 +191,7 @@ class ContractPrompt extends 
React.Component<ContractPromptProps, ContractPrompt
         document.location.href = proposal.contractTerms.fulfillment_url;
         break;
     }
-    this.setState({holdCheck: false});
+    this.setState({holdCheck: true});
   }
 
 
@@ -198,15 +200,36 @@ class ContractPrompt extends 
React.Component<ContractPromptProps, ContractPrompt
       return <span>...</span>;
     }
     const c = this.state.proposal.contractTerms;
+    let merchantName;
+    if (c.merchant && c.merchant.name) {
+      merchantName = <strong>{c.merchant.name}</strong>;
+    } else {
+      merchantName = <strong>(pub: {c.merchant_pub})</strong>;
+    }
+    const amount = <strong>{renderAmount(c.amount)}</strong>;
+    console.log("payStatus", this.state.payStatus);
     return (
       <div>
         <div>
-          {renderContractTerms(c)}
+          <i18n.Translate wrap="p">
+            The merchant <span>{merchantName}</span> {" "}
+            offers you to purchase:
+          </i18n.Translate>
+          <ul>
+            {c.products.map(
+              (p: any, i: number) => (<li key={i}>{p.description}: 
{renderAmount(p.price)}</li>))
+            }
+          </ul>
+            {(this.state.payStatus && this.state.payStatus.coinSelection) ?
+              <p>The total price is <span>{amount}</span> (plus 
<span>{renderAmount(this.state.payStatus.coinSelection.totalFees)}</span> 
fees).</p>
+              :
+              <p>The total price is <span>{amount}</span>.</p>
+            }
         </div>
-        <button onClick={() => this.doPayment()}
+        <button className="pure-button button-success"
                 disabled={this.state.payDisabled}
-                className="accept">
-          Confirm payment
+                onClick={() => this.doPayment()}>
+          {i18n.str`Confirm payment`}
         </button>
         <div>
           {(this.state.alreadyPaid ? <p className="okaybox">You already paid 
for this, clicking "Confirm payment" will not cost money again.</p> : <p />)}
diff --git a/src/webex/pages/refund.tsx b/src/webex/pages/refund.tsx
index b9506bf2..d2c21c2f 100644
--- a/src/webex/pages/refund.tsx
+++ b/src/webex/pages/refund.tsx
@@ -37,11 +37,12 @@ interface RefundStatusViewProps {
 
 interface RefundStatusViewState {
   purchase?: types.PurchaseRecord;
+  refundFees?: types.AmountJson;
   gotResult: boolean;
 }
 
 
-const RefundDetail = ({purchase}: {purchase: types.PurchaseRecord}) => {
+const RefundDetail = ({purchase, fullRefundFees}: {purchase: 
types.PurchaseRecord, fullRefundFees: types.AmountJson}) => {
   const pendingKeys = Object.keys(purchase.refundsPending);
   const doneKeys = Object.keys(purchase.refundsDone);
   if (pendingKeys.length == 0 && doneKeys.length == 0) {
@@ -54,22 +55,18 @@ const RefundDetail = ({purchase}: {purchase: 
types.PurchaseRecord}) => {
   }
 
   let amountPending = types.Amounts.getZero(currency);
-  let feesPending = types.Amounts.getZero(currency)
   for (let k of pendingKeys) {
     amountPending = types.Amounts.add(amountPending, 
purchase.refundsPending[k].refund_amount).amount;
-    feesPending = types.Amounts.add(feesPending, 
purchase.refundsPending[k].refund_fee).amount;
   }
   let amountDone = types.Amounts.getZero(currency);
-  let feesDone = types.Amounts.getZero(currency);
   for (let k of doneKeys) {
     amountDone = types.Amounts.add(amountDone, 
purchase.refundsDone[k].refund_amount).amount;
-    feesDone = types.Amounts.add(feesDone, 
purchase.refundsDone[k].refund_fee).amount;
   }
 
   return (
     <div>
-      <p>Refund fully received: <AmountDisplay amount={amountDone} /> (refund 
fees: <AmountDisplay amount={feesDone} />)</p>
-      <p>Refund incoming: <AmountDisplay amount={amountPending} /> (refund 
fees: <AmountDisplay amount={feesPending} />)</p>
+      <p>Refund fully received: <AmountDisplay amount={amountDone} /> (refund 
fees: <AmountDisplay amount={fullRefundFees} />)</p>
+      <p>Refund incoming: <AmountDisplay amount={amountPending} /></p>
     </div>
   );
 };
@@ -108,7 +105,7 @@ class RefundStatusView extends 
React.Component<RefundStatusViewProps, RefundStat
         <h1>Refund Status</h1>
         <p>Status of purchase <strong>{summary}</strong> from merchant 
<strong>{merchantName}</strong> (order id 
{purchase.contractTerms.order_id}).</p>
         <p>Total amount: <AmountDisplay amount={purchase.contractTerms.amount} 
/></p>
-        {purchase.finished ? <RefundDetail purchase={purchase} /> : 
<p>Purchase not completed.</p>}
+        {purchase.finished ? <RefundDetail purchase={purchase} 
fullRefundFees={this.state.refundFees!} /> : <p>Purchase not completed.</p>}
       </div>
     );
   }
@@ -116,7 +113,9 @@ class RefundStatusView extends 
React.Component<RefundStatusViewProps, RefundStat
   async update() {
     const purchase = await wxApi.getPurchase(this.props.contractTermsHash);
     console.log("got purchase", purchase);
-    this.setState({ purchase, gotResult: true });
+    const refundsDone = Object.keys(purchase.refundsDone).map((x) => 
purchase.refundsDone[x]);
+    const refundFees = await wxApi.getFullRefundFees( {refundPermissions: 
refundsDone });
+    this.setState({ purchase, gotResult: true, refundFees });
   }
 }
 
diff --git a/src/webex/renderHtml.tsx b/src/webex/renderHtml.tsx
index 2a5b5053..d26f726a 100644
--- a/src/webex/renderHtml.tsx
+++ b/src/webex/renderHtml.tsx
@@ -24,45 +24,13 @@
 /**
  * Imports.
  */
-import { amountToPretty } from "../helpers";
-import * as i18n from "../i18n";
 import {
   AmountJson,
   Amounts,
-  ContractTerms,
 } from "../types";
 
 import * as React from "react";
 
-/**
- * Render contract terms for the end user to view.
- */
-export function renderContractTerms(contractTerms: ContractTerms): JSX.Element 
{
-  let merchantName;
-  if (contractTerms.merchant && contractTerms.merchant.name) {
-    merchantName = <strong>{contractTerms.merchant.name}</strong>;
-  } else {
-    merchantName = <strong>(pub: {contractTerms.merchant_pub})</strong>;
-  }
-  const amount = <strong>{amountToPretty(contractTerms.amount)}</strong>;
-
-  return (
-    <div>
-      <i18n.Translate wrap="p">
-        The merchant <span>{merchantName}</span>
-        wants to enter a contract over <span>{amount}</span>{" "}
-        with you.
-      </i18n.Translate>
-      <p>{i18n.str`You are about to purchase:`}</p>
-      <ul>
-        {contractTerms.products.map(
-          (p: any, i: number) => (<li key={i}>{`${p.description}: 
${amountToPretty(p.price)}`}</li>))
-        }
-      </ul>
-    </div>
-  );
-}
-
 
 /**
  * Render amount as HTML, which non-breaking space between
diff --git a/src/webex/wxApi.ts b/src/webex/wxApi.ts
index 1423da53..096d855e 100644
--- a/src/webex/wxApi.ts
+++ b/src/webex/wxApi.ts
@@ -33,6 +33,7 @@ import {
   PreCoinRecord,
   PurchaseRecord,
   QueryPaymentResult,
+  RefundPermission,
   ReserveCreationInfo,
   ReserveRecord,
   SenderWireInfos,
@@ -345,3 +346,7 @@ export function acceptRefund(refundData: any): 
Promise<number> {
 export function getPurchase(contractTermsHash: string): 
Promise<PurchaseRecord> {
   return callBackend("get-purchase", { contractTermsHash });
 }
+
+export function getFullRefundFees(args: { refundPermissions: 
RefundPermission[] }): Promise<AmountJson> {
+  return callBackend("get-full-refund-fees", { refundPermissions: 
args.refundPermissions });
+}
diff --git a/src/webex/wxBackend.ts b/src/webex/wxBackend.ts
index db2ffbfb..16da3d97 100644
--- a/src/webex/wxBackend.ts
+++ b/src/webex/wxBackend.ts
@@ -323,6 +323,8 @@ function handleMessage(sender: MessageSender,
         throw Error("contractTermsHash missing");
       }
       return needsWallet().getPurchase(contractTermsHash);
+    case "get-full-refund-fees":
+      return needsWallet().getFullRefundFees(detail.refundPermissions);
     default:
       // Exhaustiveness check.
       // See https://www.typescriptlang.org/docs/handbook/advanced-types.html

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



reply via email to

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