gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [taler-merchant] branch stable updated (5e2e443 -> 417a952)


From: gnunet
Subject: [GNUnet-SVN] [taler-merchant] branch stable updated (5e2e443 -> 417a952)
Date: Wed, 18 Oct 2017 09:54:00 +0200

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

marcello pushed a change to branch stable
in repository merchant.

    from 5e2e443  moving a 'PS' struct into exchange codebase
     add fd6227f  payments generator does real timestamps
     add c1114ba  mega indent + parsing of GET /refund response in the multiple 
coins testcase fashion.
     add 5fbe9f3  Completing minimal multi-coin refund testcase.
     add 3fa209c  removing dead code
     add 35d6bda  fix Vim indent madness
     add 80ae19f  still on Vim madness: functions parameters messed up
     add d40fd6c  remove comments
     add 4fbf3a1  add UNIQUE constraint on BIGSERIAL columns as that is not 
automatic in Postgres
     add c391606  flagging proposal as paid (#5054)
     add 73e2e5a  making testcase pass to new "flagged as paid" policy
     add 468eed8  > half testcase gone over for "assert vs fail" issue
     add 71e9b21  indentating the code in order to avoid very long lines + #5092
     add 73dc17a  Still killing long lines
     add c9ed203  no key under [merchant], default instance takes care
     add eb71cb2  implementing backend logic to lookup wire fees (for #4943)
     add 7e05562  minor style fixes
     add f3918c1  fix timestamp issue in lib testcase
     add a755271  work for #4943 (incomplete)
     add c6cebe5  style fixes
     add 817d3ff  indentation and style fixes
     add b2b7d8b  indentation fixes
     add c2f95bf  indentation fixes, style fix on how to generate timestamp
     add 49885a0  removing bogus #include
     add 12b0ea3  implement mandatory rounding of timestamp
     add faaf295  init timestamp
     add c3b2fba  fix configuration to ensure exchange wires immediately
     add 759f073  fix merchant_api_track_transfer to actually pass wire method 
to service
     add ca73be0  more logging
     add 9626af4  /history issue testcase
     add 2d3fcf5  do not use uninitialized master_pub field from 'struct 
Exchange', but use the initialized master_pub from keys instead (when storing 
wire fee data in the database), should complete #4943 implementation
     add dbadf34  moving proposal mark-as-paid in the right place (= after 
exchange confirmation of all deposited coins)
     add 1a93081  do not use hugely futuristic time while testing /history
     add 5fc7324  Checking that a contract whose payment didn't get through 
doesn't belong to /history response.
     add b490670  comments
     add 77fd7e5  comment
     add fe3e7e8  Do not set timestamp in lib testcase, because the backend 
adds it by default if not found.
     add fb251bf  coverage for db test
     add 479bfd4  rounding /history date parameter
     add ca8f664  don't track version.texi, it's auto-generated
     add a57f3f0  gitignore
     add 20fa0cd  check for specific jansson version using pkgconfig
     add ee11673  use order_id as summary if contract doesn't have it
     add f0e6665  wrap refund permission in object
     add 4cfe3ac  fix refund generation (hopefully)
     add f795e36  fix clear logic error, likely related to #5127
     add 58bcfc4  fix #5127
     add 7d50fee  fix refund test and logic: if refund is smaller than refund 
that was previously awarded, that's not a hard error but simply 'no change 
required'
     add 149d75d  fix /pay transaction retry logic
     add 22f6e60  fix English in error message
     add 037be4b  fix testcase, refund array is boxed in a refund_permissions 
field of the main object
     add 791fa31  properly drop exchange_wire_fees table in test
     add baff321  fix bad nesting of transactions during /pay processing
     add 34ceb09  keep track of issues observed looking at /pay some more
     add 203ab2b  work on #5092: remove one of the asserts that can fail
     add 3118c34  work on #5092: be conservative, allow 
TALER_EXCHANGE_get_keys() to return NULL and treat as error properly
     add 155966b  work on #5092, do not assert if instance unknown
     add cd3071d  work on #5092, handle failure in easy case without asserting
     add 4bea239  handle a few more asserts more gracefully (#5092)
     add 0bddaaf  adjust to API change of exchange
     add 8a488d5  fix use of uninit vars
     add b237811  fix extra start of retry_exchange task
     add e6a8b18  check return value from TALER_JSON_hash
     add 1f67c7f  check return value from TALER_amount_get_zero
     add 11281ad  add CSS styling
     add f2feb5e  add CSS files
     add 7e8a685  fix css files in .gitignore
     add 417a952  add refund permissions to /pay

No new revisions were added by this update.

Summary of changes:
 .gitignore                                         |    2 +
 TODO                                               |   10 +
 configure.ac                                       |   23 +-
 doc/Makefile.am                                    |    6 +-
 doc/brown-paper.css                                |   63 +
 doc/docstyle.css                                   |   76 +
 doc/manual.texi                                    |    2 +-
 doc/version.texi                                   |    4 -
 src/backend/merchant.conf                          |    3 -
 src/backend/taler-merchant-httpd.c                 |   13 +-
 src/backend/taler-merchant-httpd_exchanges.c       |   66 +-
 src/backend/taler-merchant-httpd_history.c         |   70 +-
 src/backend/taler-merchant-httpd_pay.c             |  344 +++--
 src/backend/taler-merchant-httpd_proposal.c        |   19 +-
 src/backend/taler-merchant-httpd_refund.c          |   95 +-
 src/backend/taler-merchant-httpd_refund.h          |   17 +
 src/backend/taler-merchant-httpd_responses.c       |    8 +-
 .../taler-merchant-httpd_track-transaction.c       |   30 +-
 src/backend/taler-merchant-httpd_track-transfer.c  |  125 +-
 src/backenddb/Makefile.am                          |    5 +
 src/backenddb/plugin_merchantdb_postgres.c         |  469 ++++--
 src/backenddb/test_merchantdb.c                    |  178 ++-
 src/include/taler_merchant_service.h               |  112 +-
 src/include/taler_merchantdb_plugin.h              |   81 +-
 src/lib/merchant_api_pay.c                         |   20 +-
 src/lib/merchant_api_track_transfer.c              |   12 +-
 src/lib/test_merchant_api.c                        | 1595 ++++++++++----------
 src/lib/test_merchant_api.conf                     |    3 +-
 .../taler-merchant-generate-payments.c             |    9 +-
 29 files changed, 2247 insertions(+), 1213 deletions(-)
 create mode 100644 TODO
 create mode 100644 doc/brown-paper.css
 create mode 100644 doc/docstyle.css
 delete mode 100644 doc/version.texi

diff --git a/.gitignore b/.gitignore
index 06e6ce0..5c692c1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,6 +35,8 @@ taler_merchant_config.h
 taler_merchant_config.h.in
 doc/*
 !doc/*.texi
+!doc/*.css
+doc/version.texi
 !doc/*.am
 !doc/*.sh
 !doc/examples/
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..cffc334
--- /dev/null
+++ b/TODO
@@ -0,0 +1,10 @@
+Major issues with /pay:
+
+1) Why is there a 'paid' field in merchant_contract_terms DB table?
+
+2) If we do have the row_id of merchant_contract_terms, why do we store
+   the full h_contract_terms/merchant_pub again and again in the other tables?
+
+3) What happens if we store in merchant_transactions some timestamp/exchange
+   and then the deposits (partially) fail? Do we undo the deposits? Do we
+   allow a 2nd round of /pay? What happens if the exchange differs the 2nd 
time?
diff --git a/configure.ac b/configure.ac
index 11afa00..f3f7b23 100644
--- a/configure.ac
+++ b/configure.ac
@@ -152,27 +152,14 @@ AS_IF([test $microhttpd = 0],
 *** You need libmicrohttpd to build this program.
 *** ]])])
 
-
-# check for libjansson (Jansson JSON library)
 jansson=0
-AC_MSG_CHECKING([for jansson])
-AC_ARG_WITH([jansson],
-            [AS_HELP_STRING([--with-jansson=PFX], [base of jansson 
installation])],
-            [AC_MSG_RESULT([given as $with_jansson])],
-            [AC_MSG_RESULT([not given])
-             with_jansson=yes])
-AS_CASE([$with_jansson],
-        [yes], [],
-        [no], [AC_MSG_ERROR([--with-jansson is required])],
-        [LDFLAGS="-L$with_jansson/lib $LDFLAGS"
-         CPPFLAGS="-I$with_jansson/include $CPPFLAGS"])
-AC_CHECK_LIB(jansson,json_pack,
-  [AC_CHECK_HEADER([jansson.h],[jansson=1])])
-AS_IF([test $jansson = 0],
-  [AC_MSG_ERROR([[
+PKG_CHECK_MODULES([JANSSON], [jansson >= 2.3], 
+                  [LDFLAGS="$JANSSON_LIBS $LDFLAGS"
+                   CPPFLAGS="$JANSSON_CFLAGS $CPPFLAGS"],
+                  [AC_MSG_ERROR([[
 ***
 *** You need libjansson to build this program.
-*** ]])])
+***]])])
 
 # check for libgnurl
 # libgnurl
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 5155926..fdfea96 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -9,6 +9,8 @@ arch.pdf: arch.dot
 arch.jpg: arch.dot
        dot -Tjpg arch.dot > arch.jpg
 
+AM_MAKEINFOHTMLFLAGS = --no-split --css-ref=docstyle.css 
--css-ref=brown-paper.css
+
 info_TEXINFOS = manual.texi
 manual_TEXINFOS = version.texi
 
@@ -16,4 +18,6 @@ EXTRA_DIST = \
   arch.dot \
   lgpl.texi \
   agpl.texi \
-  fdl-1.3.texi
+  fdl-1.3.texi \
+  docstyle.css \
+  brown-paper.css
diff --git a/doc/brown-paper.css b/doc/brown-paper.css
new file mode 100644
index 0000000..65e2e79
--- /dev/null
+++ b/doc/brown-paper.css
@@ -0,0 +1,63 @@
+/*
+
+Brown Paper style from goldblog.com.ua (c) Zaripov Yura <address@hidden>
+
+*/
+
+.hljs {
+  display: block;
+  overflow-x: auto;
+  padding: 0.5em;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal {
+  color:#005599;
+  font-weight:bold;
+}
+
+.hljs,
+.hljs-subst {
+  color: #363c69;
+}
+
+.hljs-string,
+.hljs-title,
+.hljs-section,
+.hljs-type,
+.hljs-attribute,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-built_in,
+.hljs-addition,
+.hljs-variable,
+.hljs-template-tag,
+.hljs-template-variable,
+.hljs-link,
+.hljs-name {
+  color: #2c009f;
+}
+
+.hljs-comment,
+.hljs-quote,
+.hljs-meta,
+.hljs-deletion {
+  color: #802022;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-literal,
+.hljs-doctag,
+.hljs-title,
+.hljs-section,
+.hljs-type,
+.hljs-name,
+.hljs-strong {
+  font-weight: bold;
+}
+
+.hljs-emphasis {
+  font-style: italic;
+}
diff --git a/doc/docstyle.css b/doc/docstyle.css
new file mode 100644
index 0000000..c91d3f7
--- /dev/null
+++ b/doc/docstyle.css
@@ -0,0 +1,76 @@
+html, body {
+   font-size: 1em;
+   text-align: left;
+   text-decoration: none;
+}
+html { background-color: #e7e7e7; }
+
+body {
+   max-width: 74.92em;
+   margin: 0 auto;
+   padding: .5em 1em 1em 1em;
+   background-color: white;
+   border: .1em solid #c0c0c0;
+}
+
+h1, h2, h3, h4 { color: #333; }
+h5, h6, dt { color: #222; }
+
+
+a h3 {
+  color: #005090;
+}
+
+a[href] { color: #005090; }
+a[href]:visited { color: #100070; }
+a[href]:active, a[href]:hover {
+   color: #100070;
+   text-decoration: none;
+}
+
+.linkrow {
+  margin: 3em 0;
+}
+
+.linkrow {
+  text-align: center;
+}
+
+div.example { padding: .8em 1.2em .4em; }
+pre.example { padding: .8em 1.2em; }
+div.example, pre.example {
+   margin: 1em 0 1em 3% ;
+   -webkit-border-radius: .3em;
+   -moz-border-radius: .3em;
+   border-radius: .3em;
+   border: 1px solid #d4cbb6;
+   background-color: #f2efe4;
+}
+div.example > pre.example {
+   padding: 0 0 .4em;
+   margin: 0;
+   border: none;
+}
+
+
+/* This makes the very long tables of contents in Gnulib and other
+   manuals easier to read. */
+.contents ul, .shortcontents ul { font-weight: bold; }
+.contents ul ul, .shortcontents ul ul { font-weight: normal; }
+.contents ul { list-style: none; }
+
+/* For colored navigation bars (Emacs manual): make the bar extend
+   across the whole width of the page and give it a decent height. */
+.header, .node { margin: 0 -1em; padding: 0 1em; }
+.header p, .node p { line-height: 2em; }
+
+/* For navigation links */
+.node a, .header a { display: inline-block; line-height: 2em; }
+.node a:hover, .header a:hover { background: #f2efe4; }
+
+table.cartouche {
+  border-collapse: collapse;
+  border-color: darkred;
+  border-style: solid;
+  border-width: 3px;
+}
diff --git a/doc/manual.texi b/doc/manual.texi
index 9da4582..0893b8e 100644
--- a/doc/manual.texi
+++ b/doc/manual.texi
@@ -14,7 +14,7 @@
 @copying
 This manual is for the GNU Taler merchant backend (version @value{VERSION}, 
@value{UPDATED}),
 
-Copyright @copyright{} 2016 INRIA
+Copyright @copyright{} 2016, 2017 Taler Systems SA
 
 @quotation
 Permission is granted to copy, distribute and/or modify this document
diff --git a/doc/version.texi b/doc/version.texi
deleted file mode 100644
index fc2400a..0000000
--- a/doc/version.texi
+++ /dev/null
@@ -1,4 +0,0 @@
address@hidden UPDATED 7 June 2017
address@hidden UPDATED-MONTH June 2017
address@hidden EDITION 0.3.0
address@hidden VERSION 0.3.0
diff --git a/src/backend/merchant.conf b/src/backend/merchant.conf
index 5e16ef1..45a13cf 100644
--- a/src/backend/merchant.conf
+++ b/src/backend/merchant.conf
@@ -34,9 +34,6 @@ UNIXPATH_MODE = 660
 # always safe (financially speaking).
 DEFAULT_WIRE_FEE_AMORTIZATION = 1
 
-# Where does the backend store the merchant's private key?
-KEYFILE = ${TALER_DATA_HOME}/merchant/merchant.priv
-
 # Which database backend do we use?
 DB = postgres
 
diff --git a/src/backend/taler-merchant-httpd.c 
b/src/backend/taler-merchant-httpd.c
index 437537d..15086cc 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -234,7 +234,7 @@ url_handler (void *cls,
   for (unsigned int i=0;NULL != handlers[i].url;i++)
   {
     struct TMH_RequestHandler *rh = &handlers[i];
-    
+
     if ( (0 == strcasecmp (url,
                            rh->url)) &&
          ( (NULL == rh->method) ||
@@ -564,20 +564,21 @@ instances_iterator_cb (void *cls,
     iic->ret |= GNUNET_SYSERR;
   }
 
-  if (GNUNET_YES != TALER_JSON_hash (mi->j_wire,
-                                     &mi->h_wire))
+  if (GNUNET_OK !=
+      TALER_JSON_hash (mi->j_wire,
+                       &mi->h_wire))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Failed to hash wireformat\n");
     iic->ret |= GNUNET_SYSERR;
   }
-  #define EXTRADEBUG
-  #ifdef EXTRADEBUGG
+#define EXTRADEBUG
+#ifdef EXTRADEBUGG
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Found wireformat instance:\n");
               json_dumpf (mi->j_wire, stdout, 0);
               printf ("\n");
-  #endif
+#endif
 
   GNUNET_CRYPTO_hash (mi->id,
                       strlen (mi->id),
diff --git a/src/backend/taler-merchant-httpd_exchanges.c 
b/src/backend/taler-merchant-httpd_exchanges.c
index a011be4..9833181 100644
--- a/src/backend/taler-merchant-httpd_exchanges.c
+++ b/src/backend/taler-merchant-httpd_exchanges.c
@@ -312,7 +312,12 @@ process_wire_fees (void *cls,
   struct FeesByWireMethod *f;
   struct TALER_EXCHANGE_WireAggregateFees *endp;
   struct TALER_EXCHANGE_WireAggregateFees *af;
+  const struct TALER_EXCHANGE_Keys *keys;
+  const struct TALER_MasterPublicKeyP *master_pub;
 
+  keys = TALER_EXCHANGE_get_keys (exchange->conn);
+  GNUNET_assert (NULL != keys);
+  master_pub = &keys->master_pub;
   for (f = exchange->wire_fees_head; NULL != f; f = f->next)
     if (0 == strcasecmp (wire_method,
                          f->wire_method))
@@ -343,14 +348,28 @@ process_wire_fees (void *cls,
   {
     struct GNUNET_HashCode h_wire_method;
     enum GNUNET_DB_QueryStatus qs;
-    
+
     af = GNUNET_new (struct TALER_EXCHANGE_WireAggregateFees);
     *af = *fees;
     GNUNET_CRYPTO_hash (wire_method,
                        strlen (wire_method) + 1,
                        &h_wire_method);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "Storing wire fee for `%s' and method `%s' at %s in DB; the fee 
is %s\n",
+               TALER_B2S (master_pub),
+               wire_method,
+               GNUNET_STRINGS_absolute_time_to_string (af->start_date),
+               TALER_amount2s (&af->wire_fee));
+    if (GNUNET_OK !=
+        db->start (db->cls))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 "Failed to start database transaction!\n");
+      GNUNET_free (af);
+      break;
+    }
     qs = db->store_wire_fee_by_exchange (db->cls,
-                                        &exchange->master_pub,
+                                        master_pub,
                                         &h_wire_method,
                                         &af->wire_fee,
                                         &af->closing_fee,
@@ -363,8 +382,30 @@ process_wire_fees (void *cls,
                  "Failed to persist exchange wire fees in merchant DB!\n");
       GNUNET_free (af);
       fees = fees->next;
+      db->rollback (db->cls);
       continue;
     }
+    if (0 == qs)
+    {
+      /* Entry was already in DB, fine, continue as if we had succeeded */
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                 "Fees already in DB, rolling back transaction attempt!\n");
+      db->rollback (db->cls);
+    }
+    if (0 < qs)
+    {
+      /* Inserted into DB, make sure transaction completes */
+      qs = db->commit (db->cls);
+      if (0 > qs)
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                    "Failed to persist exchange wire fees in merchant DB!\n");
+        GNUNET_free (af);
+        fees = fees->next;
+        continue;
+      }
+    }
+
     af->next = NULL;
     if (NULL == endp)
       f->af = af;
@@ -517,6 +558,7 @@ handle_wire_data (void *cls,
                   const json_t *obj)
 {
   struct Exchange *exchange = cls;
+  const struct TALER_EXCHANGE_Keys *keys;
 
   exchange->wire_request = NULL;
   if (MHD_HTTP_OK != http_status)
@@ -527,11 +569,13 @@ handle_wire_data (void *cls,
                 ec);
     return;
   }
-  if (GNUNET_OK !=
-      TALER_EXCHANGE_wire_get_fees (&TALER_EXCHANGE_get_keys 
(exchange->conn)->master_pub,
-                                    obj,
-                                    &process_wire_fees,
-                                    exchange))
+  keys = TALER_EXCHANGE_get_keys (exchange->conn);
+  if ( (NULL == keys) ||
+       (GNUNET_OK !=
+        TALER_EXCHANGE_wire_get_fees (&keys->master_pub,
+                                      obj,
+                                      &process_wire_fees,
+                                      exchange)) )
   {
     /* Report hard failure to all callbacks! */
     struct TMH_EXCHANGES_FindOperation *fo;
@@ -650,6 +694,7 @@ keys_mgmt_cb (void *cls,
                 exchange->uri,
                 GNUNET_STRINGS_relative_time_to_string (exchange->retry_delay,
                                                         GNUNET_YES));
+    GNUNET_assert (NULL == exchange->retry_task);
     exchange->retry_task = GNUNET_SCHEDULER_add_delayed (exchange->retry_delay,
                                                          &retry_exchange,
                                                          exchange);
@@ -668,13 +713,16 @@ keys_mgmt_cb (void *cls,
                  exchange->uri);
     }
   }
-  expire = TALER_EXCHANGE_check_keys_current (exchange->conn);
+  expire = TALER_EXCHANGE_check_keys_current (exchange->conn,
+                                              GNUNET_NO);
   if (0 == expire.abs_value_us)
     delay = RELOAD_DELAY;
   else
     delay = GNUNET_TIME_absolute_get_remaining (expire);
   exchange->retry_delay
     = GNUNET_TIME_UNIT_ZERO;
+  if (NULL != exchange->retry_task)
+    GNUNET_SCHEDULER_cancel (exchange->retry_task);
   exchange->retry_task
     = GNUNET_SCHEDULER_add_delayed (delay,
                                     &retry_exchange,
@@ -813,6 +861,7 @@ TMH_EXCHANGES_find_exchange (const char *chosen_exchange,
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Do not have current key data. Will request /keys now\n");
+    GNUNET_assert (NULL == exchange->retry_task);
     exchange->retry_task = GNUNET_SCHEDULER_add_now (&retry_exchange,
                                                      exchange);
   }
@@ -919,6 +968,7 @@ accept_exchanges (void *cls,
                                exchange_tail,
                                exchange);
   exchange->pending = GNUNET_YES;
+  GNUNET_assert (NULL == exchange->retry_task);
   exchange->retry_task = GNUNET_SCHEDULER_add_now (&retry_exchange,
                                                    exchange);
 }
diff --git a/src/backend/taler-merchant-httpd_history.c 
b/src/backend/taler-merchant-httpd_history.c
index 9d6459e..99c71a4 100644
--- a/src/backend/taler-merchant-httpd_history.c
+++ b/src/backend/taler-merchant-httpd_history.c
@@ -27,9 +27,29 @@
 
 
 /**
+ * Closure for #pd_cb.
+ */
+struct ProcessContractClosure
+{
+
+  /**
+   * Updated by #pd_cb to build the response.
+   */
+  json_t *response;
+
+  /**
+   * Set to #GNUNET_SYSERR if the database returned a contract
+   * that was not well-formed.
+   */
+  int failure;
+
+};
+
+
+/**
  * Function called with information about a transaction.
  *
- * @param cls closure
+ * @param cls closure of type `struct ProcessContractClosure`
  * @param order_id transaction's order ID.
  * @param row_id serial numer of the transaction in the table,
  * used as index by the frontend to skip previous results.
@@ -40,7 +60,7 @@ pd_cb (void *cls,
        uint64_t row_id,
        const json_t *contract_terms)
 {
-  json_t *response = cls;
+  struct ProcessContractClosure *pcc = cls;
   json_t *entry;
   json_t *amount;
   json_t *timestamp;
@@ -50,13 +70,23 @@ pd_cb (void *cls,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "/history's row_id: %llu\n",
               (unsigned long long) row_id);
+  summary = NULL;
+  if (-1 == json_unpack ((json_t *) contract_terms,
+                         "{s:o, s:o, s:{s:o}, s?:o}",
+                         "amount", &amount,
+                         "timestamp", &timestamp,
+                         "merchant", "instance", &instance,
+                         "summary", &summary))
+  {
+    GNUNET_break (0);
+    pcc->failure = GNUNET_SYSERR;
+    return;
+  }
 
-  GNUNET_assert (-1 != json_unpack ((json_t *) contract_terms,
-                                    "{s:o, s:o, s:{s:o}, s:o}",
-                                    "amount", &amount,
-                                    "timestamp", &timestamp,
-                                    "merchant", "instance", &instance,
-                                    "summary", &summary));
+  /* summary is optional, but we need something, so we use
+     the order ID if it is not given. */
+  if (NULL == summary)
+    summary = json_string (order_id);
 
   GNUNET_break (NULL != (entry = json_pack ("{s:I, s:s, s:O, s:O, s:O, s:O}",
                                             "row_id", row_id,
@@ -66,8 +96,9 @@ pd_cb (void *cls,
                                             "instance", instance,
                                             "summary", summary)));
 
-  GNUNET_break (0 == json_array_append_new (response,
-                                            entry));
+  GNUNET_break (0 ==
+                json_array_append_new (pcc->response,
+                                       entry));
 }
 
 
@@ -99,6 +130,7 @@ MH_handler_history (struct TMH_RequestHandler *rh,
   int start = -1;
   unsigned int delta;
   enum GNUNET_DB_QueryStatus qs;
+  struct ProcessContractClosure pcc;
 
   response = json_array ();
   str = MHD_lookup_connection_value (connection,
@@ -147,20 +179,22 @@ MH_handler_history (struct TMH_RequestHandler *rh,
   str = MHD_lookup_connection_value (connection,
                                      MHD_GET_ARGUMENT_KIND,
                                      "order_id");
-
   if (NULL != str)
   {
+    pcc.response = response;
+    pcc.failure = GNUNET_NO;
     qs = db->find_contract_terms_history (db->cls,
                                          str,
                                          &mi->pubkey,
                                          &pd_cb,
-                                         response);
+                                         &pcc);
     /* single, read-only SQL statements should never cause
        serialization problems */
     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
     /* Always report on hard error as well to enable diagnostics */
     GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
-    if (0 > qs)
+    if ( (0 > qs) ||
+         (GNUNET_SYSERR == pcc.failure) )
     {
       json_decref (response);
       return TMH_RESPONSE_reply_internal_error (connection,
@@ -175,7 +209,6 @@ MH_handler_history (struct TMH_RequestHandler *rh,
   }
 
   delta = 20;
-
   str = MHD_lookup_connection_value (connection,
                                      MHD_GET_ARGUMENT_KIND,
                                      "start");
@@ -212,13 +245,15 @@ MH_handler_history (struct TMH_RequestHandler *rh,
               start,
               delta);
 
+  pcc.response = response;
+  pcc.failure = GNUNET_NO;
   if (0 > start)
     qs = db->find_contract_terms_by_date (db->cls,
                                          date,
                                          &mi->pubkey,
                                          delta,
                                          &pd_cb,
-                                         response);
+                                         &pcc);
   else
     qs = db->find_contract_terms_by_date_and_range (db->cls,
                                                    date,
@@ -227,8 +262,9 @@ MH_handler_history (struct TMH_RequestHandler *rh,
                                                    delta,
                                                    GNUNET_NO,
                                                    &pd_cb,
-                                                   response);
-  if (0 > qs)
+                                                   &pcc);
+  if ( (0 > qs) ||
+       (GNUNET_SYSERR == pcc.failure) )
   {
     /* single, read-only SQL statements should never cause
        serialization problems */
diff --git a/src/backend/taler-merchant-httpd_pay.c 
b/src/backend/taler-merchant-httpd_pay.c
index 2e3767b..7769ef2 100644
--- a/src/backend/taler-merchant-httpd_pay.c
+++ b/src/backend/taler-merchant-httpd_pay.c
@@ -31,6 +31,7 @@
 #include "taler-merchant-httpd_responses.h"
 #include "taler-merchant-httpd_auditors.h"
 #include "taler-merchant-httpd_exchanges.h"
+#include "taler-merchant-httpd_refund.h"
 
 
 /**
@@ -383,7 +384,7 @@ abort_deposit (struct PayContext *pc)
 {
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Aborting pending /deposit operations\n");
-  for (unsigned int i;i<pc->coins_cnt;i++)
+  for (unsigned int i=0;i<pc->coins_cnt;i++)
   {
     struct DepositConfirmation *dci = &pc->dc[i];
 
@@ -405,6 +406,16 @@ abort_deposit (struct PayContext *pc)
 struct MHD_Response *
 sign_success_response (struct PayContext *pc)
 {
+  json_t *refunds;
+  enum TALER_ErrorCode ec;
+  const char *errmsg;
+
+  refunds = TM_get_refund_json (pc->mi, &pc->h_contract_terms, &ec, &errmsg);
+
+  if (NULL == refunds) {
+    return TMH_RESPONSE_make_internal_error (ec, errmsg);
+  }
+
   struct GNUNET_CRYPTO_EddsaSignature sig;
   struct PaymentResponsePS mr;
 
@@ -416,14 +427,16 @@ sign_success_response (struct PayContext *pc)
                             &mr.purpose,
                            &sig);
 
-  return TMH_RESPONSE_make_json_pack ("{s:O, s:o, s:o}",
+  return TMH_RESPONSE_make_json_pack ("{s:O, s:o, s:o, s:o}",
                                       "contract_terms",
                                       pc->contract_terms,
                                       "sig",
                                       GNUNET_JSON_from_data_auto (&sig),
                                       "h_contract_terms",
                                       GNUNET_JSON_from_data 
(&pc->h_contract_terms,
-                                                             sizeof (struct 
GNUNET_HashCode)));
+                                                             sizeof (struct 
GNUNET_HashCode)),
+                                      "refund_permissions",
+                                      refunds);
 }
 
 
@@ -464,6 +477,7 @@ deposit_cb (void *cls,
                http_status);
     /* Transaction failed; stop all other ongoing deposits */
     abort_deposit (pc);
+    db->rollback (db->cls);
 
     if (NULL == proof)
     {
@@ -496,8 +510,9 @@ deposit_cb (void *cls,
   }
   /* store result to DB */
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Storing successful payment for h_contract_terms '%s'\n",
-              GNUNET_h2s (&pc->h_contract_terms));
+              "Storing successful payment for h_contract_terms `%s' and 
merchant `%s'\n",
+              GNUNET_h2s (&pc->h_contract_terms),
+              TALER_B2S (&pc->mi->pubkey));
   for (unsigned int i=0;i<MAX_RETRIES;i++)
   {
     qs = db->store_deposit (db->cls,
@@ -520,6 +535,7 @@ deposit_cb (void *cls,
     GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
     /* internal error */
     abort_deposit (pc);
+    db->rollback (db->cls);
     /* Forward error including 'proof' for the body */
     resume_pay_with_response (pc,
                               MHD_HTTP_INTERNAL_SERVER_ERROR,
@@ -530,6 +546,22 @@ deposit_cb (void *cls,
 
   if (0 != pc->pending)
     return; /* still more to do */
+
+  qs = db->mark_proposal_paid (db->cls,
+                               &pc->h_contract_terms,
+                               &pc->mi->pubkey);
+  if (0 > qs)
+    resume_pay_with_response (pc,
+                              MHD_HTTP_INTERNAL_SERVER_ERROR,
+                              TMH_RESPONSE_make_internal_error 
(TALER_EC_PAY_DB_STORE_PAYMENTS_ERROR,
+                                                                "Merchant 
database error: could not mark proposal as 'paid'"));
+  qs = db->commit (db->cls);
+  if (0 > qs)
+    resume_pay_with_response (pc,
+                              MHD_HTTP_INTERNAL_SERVER_ERROR,
+                              TMH_RESPONSE_make_internal_error 
(TALER_EC_PAY_DB_STORE_PAYMENTS_ERROR,
+                                                                "Merchant 
database error: could not commit"));
+
   resume_pay_with_response (pc,
                             MHD_HTTP_OK,
                             sign_success_response (pc));
@@ -601,6 +633,52 @@ pay_context_cleanup (struct TM_HandlerContext *hc)
 
 
 /**
+ * Check if the existing transaction matches our transaction.
+ * Update `transaction_exists` accordingly.
+ *
+ * @param cls closure with the `struct PayContext`
+ * @param merchant_pub merchant's public key
+ * @param exchange_uri URI of the exchange
+ * @param h_contract_terms hashed proposal data
+ * @param h_xwire hash of our wire details
+ * @param timestamp time of the confirmation
+ * @param refund refund deadline
+ * @param total_amount total amount we receive for the contract after fees
+ */
+static void
+check_transaction_exists (void *cls,
+                         const struct TALER_MerchantPublicKeyP *merchant_pub,
+                         const char *exchange_uri,
+                         const struct GNUNET_HashCode *h_contract_terms,
+                         const struct GNUNET_HashCode *h_xwire,
+                         struct GNUNET_TIME_Absolute timestamp,
+                         struct GNUNET_TIME_Absolute refund,
+                         const struct TALER_Amount *total_amount)
+{
+  struct PayContext *pc = cls;
+
+  if ( (0 == memcmp (h_contract_terms,
+                    &pc->h_contract_terms,
+                     sizeof (struct GNUNET_HashCode))) &&
+       (0 == memcmp (h_xwire,
+                    &pc->mi->h_wire,
+                    sizeof (struct GNUNET_HashCode))) &&
+       (timestamp.abs_value_us == pc->timestamp.abs_value_us) &&
+       (refund.abs_value_us == pc->refund_deadline.abs_value_us) &&
+       (0 == TALER_amount_cmp (total_amount,
+                              &pc->amount) ) )
+  {
+    pc->transaction_exists = GNUNET_YES;
+  }
+  else
+  {
+    GNUNET_break_op (0);
+    pc->transaction_exists = GNUNET_SYSERR;
+  }
+}
+
+
+/**
  * Function called with the result of our exchange lookup.
  *
  * @param cls the `struct PayContext`
@@ -620,6 +698,7 @@ process_pay_with_exchange (void *cls,
   struct TALER_Amount wire_fee_delta;
   struct TALER_Amount wire_fee_customer_contribution;
   const struct TALER_EXCHANGE_Keys *keys;
+  enum GNUNET_DB_QueryStatus qs;
 
   pc->fo = NULL;
   if (NULL == mh)
@@ -850,6 +929,135 @@ process_pay_with_exchange (void *cls,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Exchange and fee structure OK. Initiating deposit operation for 
coins\n");
 
+
+  if (GNUNET_OK != db->start (db->cls))
+  {
+    GNUNET_break (0);
+    resume_pay_with_response (pc,
+                              MHD_HTTP_INTERNAL_SERVER_ERROR,
+                              TMH_RESPONSE_make_json_pack ("{s:s, s:I}",
+                                                           "hint", "Merchant 
database error: could not start transaction",
+                                                           "code", 
(json_int_t) TALER_EC_PAY_DB_STORE_PAYMENTS_ERROR));
+    return;
+  }
+
+  /* Check if transaction is already known, if not store it. */
+  /* FIXME: What if transaction exists, with a failed payment at
+     a different exchange? */
+  qs = db->find_transaction (db->cls,
+                            &pc->h_contract_terms,
+                            &pc->mi->pubkey,
+                            &check_transaction_exists,
+                            pc);
+  if (0 > qs)
+  {
+    /* single, read-only SQL statements should never cause
+       serialization problems */
+    GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+    /* Always report on hard error as well to enable diagnostics */
+    GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
+    /* FIXME: factor common logic of these calls into a function! */
+    resume_pay_with_response (pc,
+                              MHD_HTTP_INTERNAL_SERVER_ERROR,
+                              TMH_RESPONSE_make_json_pack ("{s:I, s:s}",
+                                                           "code", 
(json_int_t) TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR,
+                                                           "hint", "Merchant 
database error"));
+    return;
+  }
+  if (GNUNET_SYSERR == pc->transaction_exists)
+  {
+    GNUNET_break (0);
+    /* FIXME: factor common logic of these calls into a function! */
+    resume_pay_with_response (pc,
+                              MHD_HTTP_BAD_REQUEST,
+                              TMH_RESPONSE_make_json_pack ("{s:I, s:s}",
+                                                           "code", 
(json_int_t) TALER_EC_PAY_DB_TRANSACTION_ID_CONFLICT,
+                                                           "hint", 
"Transaction ID reused with different transaction details"));
+    return;
+  }
+  if (GNUNET_NO == pc->transaction_exists)
+  {
+    struct GNUNET_TIME_Absolute now;
+    enum GNUNET_DB_QueryStatus qs_st;
+
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Dealing with new transaction `%s'\n",
+                GNUNET_h2s (&pc->h_contract_terms));
+
+    now = GNUNET_TIME_absolute_get ();
+    if (now.abs_value_us > pc->pay_deadline.abs_value_us)
+    {
+      /* Time expired, we don't accept this payment now! */
+      const char *pd_str;
+
+      pd_str = GNUNET_STRINGS_absolute_time_to_string (pc->pay_deadline);
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Attempt to pay coins for expired contract. Deadline: 
`%s'\n",
+                 pd_str);
+      resume_pay_with_response (pc,
+                                MHD_HTTP_BAD_REQUEST,
+                                TMH_RESPONSE_make_json_pack ("{s:I, s:s}",
+                                                             "code", 
(json_int_t) TALER_EC_PAY_OFFER_EXPIRED,
+                                                             "hint", "The time 
to pay for this contract has expired."));
+      return;
+    }
+
+    qs_st = db->store_transaction (db->cls,
+                                   &pc->h_contract_terms,
+                                   &pc->mi->pubkey,
+                                   pc->chosen_exchange,
+                                   &pc->mi->h_wire,
+                                   pc->timestamp,
+                                   pc->refund_deadline,
+                                   &pc->amount);
+    /* Only retry if SOFT error occurred.  Exit in case of OK or HARD failure 
*/
+    if (GNUNET_DB_STATUS_SOFT_ERROR == qs_st)
+    {
+      db->rollback (db->cls);
+      GNUNET_break (0);  // FIXME: implement proper retries!
+      resume_pay_with_response (pc,
+                                MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                TMH_RESPONSE_make_json_pack ("{s:I, s:s}",
+                                                             "code", 
(json_int_t) TALER_EC_PAY_DB_STORE_TRANSACTION_ERROR,
+                                                             "hint", "Soft 
merchant database error: retries not implemented"));
+      return;
+    }
+    /* Exit in case of HARD failure */
+    if (GNUNET_DB_STATUS_HARD_ERROR == qs_st)
+    {
+      GNUNET_break (0);
+      db->rollback (db->cls);
+      resume_pay_with_response (pc,
+                                MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                TMH_RESPONSE_make_json_pack ("{s:I, s:s}",
+                                                             "code", 
(json_int_t) TALER_EC_PAY_DB_STORE_TRANSACTION_ERROR,
+                                                             "hint", "Merchant 
database error: hard error while storing transaction"));
+    }
+
+    /**
+     * Break if we couldn't modify one, and only one line; this
+     * includes hard errors.
+     */
+    if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs_st)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Unexpected query status %d while storing /pay 
transaction!\n",
+                  (int) qs_st);
+      resume_pay_with_response (pc,
+                                MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                TMH_RESPONSE_make_json_pack ("{s:I, s:s}",
+                                                             "code", 
(json_int_t) TALER_EC_PAY_DB_STORE_TRANSACTION_ERROR,
+                                                             "hint", "Merchant 
database error: failed to store transaction"));
+      return;
+    }
+  } /* end of if (GNUNET_NO == pc->transaction_esists) */
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Found transaction data for proposal `%s' of merchant `%s', 
initiating deposits\n",
+              GNUNET_h2s (&pc->h_contract_terms),
+              TALER_B2S (&pc->mi->pubkey));
+
+
   /* Initiate /deposit operation for all coins */
   for (unsigned int i=0;i<pc->coins_cnt;i++)
   {
@@ -882,6 +1090,7 @@ process_pay_with_exchange (void *cls,
       /* Signature was invalid.  If the exchange was unavailable,
        * we'd get that information in the callback. */
       GNUNET_break_op (0);
+      db->rollback (db->cls);
       resume_pay_with_response (pc,
                                 MHD_HTTP_UNAUTHORIZED,
                                 TMH_RESPONSE_make_json_pack ("{s:s, s:I, s:i}",
@@ -975,52 +1184,6 @@ check_coin_paid (void *cls,
 
 
 /**
- * Check if the existing transaction matches our transaction.
- * Update `transaction_exists` accordingly.
- *
- * @param cls closure with the `struct PayContext`
- * @param merchant_pub merchant's public key
- * @param exchange_uri URI of the exchange
- * @param h_contract_terms hashed proposal data
- * @param h_xwire hash of our wire details
- * @param timestamp time of the confirmation
- * @param refund refund deadline
- * @param total_amount total amount we receive for the contract after fees
- */
-static void
-check_transaction_exists (void *cls,
-                         const struct TALER_MerchantPublicKeyP *merchant_pub,
-                         const char *exchange_uri,
-                         const struct GNUNET_HashCode *h_contract_terms,
-                         const struct GNUNET_HashCode *h_xwire,
-                         struct GNUNET_TIME_Absolute timestamp,
-                         struct GNUNET_TIME_Absolute refund,
-                         const struct TALER_Amount *total_amount)
-{
-  struct PayContext *pc = cls;
-
-  if ( (0 == memcmp (h_contract_terms,
-                    &pc->h_contract_terms,
-                     sizeof (struct GNUNET_HashCode))) &&
-       (0 == memcmp (h_xwire,
-                    &pc->mi->h_wire,
-                    sizeof (struct GNUNET_HashCode))) &&
-       (timestamp.abs_value_us == pc->timestamp.abs_value_us) &&
-       (refund.abs_value_us == pc->refund_deadline.abs_value_us) &&
-       (0 == TALER_amount_cmp (total_amount,
-                              &pc->amount) ) )
-  {
-    pc->transaction_exists = GNUNET_YES;
-  }
-  else
-  {
-    GNUNET_break_op (0);
-    pc->transaction_exists = GNUNET_SYSERR;
-  }
-}
-
-
-/**
  * Try to parse the pay request into the given pay context.
  * Schedules an error response in the connection on failure.
  *
@@ -1096,6 +1259,7 @@ parse_pay (struct MHD_Connection *connection,
       TALER_JSON_hash (pc->contract_terms,
                        &pc->h_contract_terms))
   {
+    GNUNET_break (0);
     GNUNET_JSON_parse_free (spec);
     if (MHD_YES !=
         TMH_RESPONSE_reply_internal_error (connection,
@@ -1357,80 +1521,6 @@ handler_pay_json (struct MHD_Connection *connection,
     MHD_destroy_response (resp);
     return ret;
   }
-  /* Check if transaction is already known, if not store it. */
-  qs = db->find_transaction (db->cls,
-                            &pc->h_contract_terms,
-                            &pc->mi->pubkey,
-                            &check_transaction_exists,
-                            pc);
-  if (0 > qs)
-  {
-    /* single, read-only SQL statements should never cause
-       serialization problems */
-    GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
-    /* Always report on hard error as well to enable diagnostics */
-    GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
-    return TMH_RESPONSE_reply_internal_error (connection,
-                                             
TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR,
-                                               "Merchant database error");
-  }
-  if (GNUNET_SYSERR == pc->transaction_exists)
-  {
-    GNUNET_break (0);
-    return TMH_RESPONSE_reply_external_error (connection,
-                                              
TALER_EC_PAY_DB_TRANSACTION_ID_CONFLICT,
-                                             "Transaction ID reused with 
different transaction details");
-  }
-  if (GNUNET_NO == pc->transaction_exists)
-  {
-    struct GNUNET_TIME_Absolute now;
-
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Dealing with new transaction '%s'\n",
-                GNUNET_h2s (&pc->h_contract_terms));
-
-    now = GNUNET_TIME_absolute_get ();
-    if (now.abs_value_us > pc->pay_deadline.abs_value_us)
-    {
-      /* Time expired, we don't accept this payment now! */
-      const char *pd_str;
-
-      pd_str = GNUNET_STRINGS_absolute_time_to_string (pc->pay_deadline);
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  "Attempt to get coins for expired contract. Deadline: 
'%s'\n",
-                 pd_str);
-      return TMH_RESPONSE_reply_bad_request (connection,
-                                            TALER_EC_PAY_OFFER_EXPIRED,
-                                             "The time to pay for this 
contract has expired.");
-    }
-
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Storing transaction '%s'\n",
-                GNUNET_h2s (&pc->h_contract_terms));
-    for (unsigned int i=0;i<MAX_RETRIES;i++)
-    {
-      qs = db->store_transaction (db->cls,
-                                 &pc->h_contract_terms,
-                                 &pc->mi->pubkey,
-                                 pc->chosen_exchange,
-                                 &pc->mi->h_wire,
-                                 pc->timestamp,
-                                 pc->refund_deadline,
-                                 &pc->amount);
-      if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
-       break;
-    }
-    if (0 > qs)
-    {
-      /* Special report if retries insufficient */
-      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
-      /* Always report on hard error as well to enable diagnostics */
-      GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
-      return TMH_RESPONSE_reply_internal_error (connection,
-                                               
TALER_EC_PAY_DB_STORE_TRANSACTION_ERROR,
-                                               "Merchant database error");
-    }
-  }
 
   MHD_suspend_connection (connection);
   pc->suspended = GNUNET_YES;
@@ -1455,8 +1545,8 @@ handler_pay_json (struct MHD_Connection *connection,
 
 
 /**
- * Process a payment for a proposal.
- * Takes data from the given MHD connection.
+ * Process a payment for a proposal.  Takes data from the given MHD
+ * connection.
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
diff --git a/src/backend/taler-merchant-httpd_proposal.c 
b/src/backend/taler-merchant-httpd_proposal.c
index ae0c3dc..59bd62a 100644
--- a/src/backend/taler-merchant-httpd_proposal.c
+++ b/src/backend/taler-merchant-httpd_proposal.c
@@ -293,9 +293,16 @@ proposal_put (struct MHD_Connection *connection,
   /* create proposal signature */
   pdps.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT);
   pdps.purpose.size = htonl (sizeof (pdps));
-  GNUNET_assert (GNUNET_OK ==
-                 TALER_JSON_hash (order,
-                                  &pdps.hash));
+  if (GNUNET_OK !=
+      TALER_JSON_hash (order,
+                       &pdps.hash))
+  {
+    GNUNET_break (0);
+    GNUNET_JSON_parse_free (spec);
+    return TMH_RESPONSE_reply_internal_error (connection,
+                                              TALER_EC_INTERNAL_LOGIC_ERROR,
+                                              "Could not hash order");
+  }
 
   GNUNET_CRYPTO_eddsa_sign (&mi->privkey.eddsa_priv,
                             &pdps.purpose,
@@ -434,8 +441,10 @@ MH_handler_proposal_lookup (struct TMH_RequestHandler *rh,
                                            "instance");
 
   mi = TMH_lookup_instance (instance);
-  GNUNET_assert (NULL != mi);
-
+  if (NULL == mi)
+    return TMH_RESPONSE_reply_not_found (connection,
+                                         TALER_EC_CONTRACT_INSTANCE_UNKNOWN,
+                                         "instance");
   order_id = MHD_lookup_connection_value (connection,
                                           MHD_GET_ARGUMENT_KIND,
                                           "order_id");
diff --git a/src/backend/taler-merchant-httpd_refund.c 
b/src/backend/taler-merchant-httpd_refund.c
index 509235e..9c5df27 100644
--- a/src/backend/taler-merchant-httpd_refund.c
+++ b/src/backend/taler-merchant-httpd_refund.c
@@ -44,12 +44,12 @@ struct ProcessRefundData
    * Hashed version of contract terms; needed by the callback
    * to pack the response.
    */
-  struct GNUNET_HashCode *h_contract_terms;
+  const struct GNUNET_HashCode *h_contract_terms;
 
   /**
    * Both public and private key are needed by the callback
    */
-   struct MerchantInstance *merchant;
+   const struct MerchantInstance *merchant;
 
   /**
    * Return code: #TALER_EC_NONE if successful.
@@ -127,7 +127,7 @@ MH_handler_refund_increase (struct TMH_RequestHandler *rh,
     GNUNET_JSON_spec_string ("reason", &reason),
     GNUNET_JSON_spec_string ("instance", &merchant),
     GNUNET_JSON_spec_end ()
-  }; 
+  };
   enum GNUNET_DB_QueryStatus qs;
 
   if (NULL == *connection_cls)
@@ -179,7 +179,7 @@ MH_handler_refund_increase (struct TMH_RequestHandler *rh,
                                          TALER_EC_REFUND_INSTANCE_UNKNOWN,
                                         "Unknown instance given");
   }
-  
+
   /* Convert order id to h_contract_terms */
   qs = db->find_contract_terms (db->cls,
                                &contract_terms,
@@ -198,7 +198,7 @@ MH_handler_refund_increase (struct TMH_RequestHandler *rh,
   }
   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Unknown order id given: %s\n",
                 order_id);
     return TMH_RESPONSE_reply_not_found (connection,
@@ -210,6 +210,7 @@ MH_handler_refund_increase (struct TMH_RequestHandler *rh,
       TALER_JSON_hash (contract_terms,
                        &h_contract_terms))
   {
+    GNUNET_break (0);
     GNUNET_JSON_parse_free (spec);
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Could not hash contract terms\n");
@@ -276,10 +277,10 @@ MH_handler_refund_increase (struct TMH_RequestHandler *rh,
     return TMH_RESPONSE_reply_internal_error (connection,
                                               TALER_EC_NONE,
                                               "Refund done, but failed to sign 
confirmation");
-  
+
   }
 
-  return TMH_RESPONSE_reply_json_pack (connection, 
+  return TMH_RESPONSE_reply_json_pack (connection,
                                        MHD_HTTP_OK,
                                        "{s:o}",
                                        "sig", GNUNET_JSON_from_data_auto 
(&sig));
@@ -310,6 +311,11 @@ process_refunds_cb (void *cls,
   struct GNUNET_CRYPTO_EddsaSignature sig;
   json_t *element;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Found refund of %s for coin %s with reason `%s' in database\n",
+              TALER_B2S (coin_pub),
+              TALER_amount2s (refund_amount),
+              reason);
   rr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND);
   rr.purpose.size = htonl (sizeof (struct TALER_RefundRequestPS));
   rr.h_contract_terms = *prd->h_contract_terms;
@@ -354,10 +360,11 @@ process_refunds_cb (void *cls,
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Could not append a response's element\n");
     prd->ec = TALER_EC_PARSER_OUT_OF_MEMORY;
-    return; 
+    return;
   }
 }
 
+
 /**
  * Return refund situation about a contract.
  *
@@ -381,7 +388,6 @@ MH_handler_refund_lookup (struct TMH_RequestHandler *rh,
   json_t *contract_terms;
   struct MerchantInstance *mi;
   enum GNUNET_DB_QueryStatus qs;
-  struct ProcessRefundData prd;
 
   instance = MHD_lookup_connection_value (connection,
                                           MHD_GET_ARGUMENT_KIND,
@@ -411,8 +417,8 @@ MH_handler_refund_lookup (struct TMH_RequestHandler *rh,
                                           MHD_GET_ARGUMENT_KIND,
                                           "order_id");
   if (NULL == order_id)
-  { 
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Argument 'order_id' not given\n");
     return TMH_RESPONSE_reply_arg_missing (connection,
                                           TALER_EC_PARAMETER_MISSING,
@@ -438,7 +444,7 @@ MH_handler_refund_lookup (struct TMH_RequestHandler *rh,
 
   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Unknown order id given: %s\n",
                 order_id);
     return TMH_RESPONSE_reply_not_found (connection,
@@ -450,21 +456,58 @@ MH_handler_refund_lookup (struct TMH_RequestHandler *rh,
       TALER_JSON_hash (contract_terms,
                        &h_contract_terms))
   {
+    GNUNET_break (0);
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Could not hash contract terms\n");
     return TMH_RESPONSE_reply_internal_error (connection,
                                               TALER_EC_INTERNAL_LOGIC_ERROR,
                                               "Could not hash contract terms");
   }
+
+  json_t *response;
+  enum TALER_ErrorCode ec;
+  const char *errmsg;
+
+  response = TM_get_refund_json (mi, &h_contract_terms, &ec, &errmsg);
+
+  if (NULL == response) {
+    return TMH_RESPONSE_reply_internal_error (connection, ec, errmsg);
+  }
+
+  return TMH_RESPONSE_reply_json_pack (connection,
+                                       MHD_HTTP_OK,
+                                       "{s:o}",
+                                       "refund_permissions", response);
+}
+
+
+/**
+ * Get the JSON representation of a refund.
+ *
+ * @param merchant_pub the merchant's public key
+ * @param mi merchant instance
+ * @param ret_ec where to store error code
+ * @param ret_errmsg where to store error message
+ * @return NULL on error, JSON array with refunds on success
+ */
+json_t *
+TM_get_refund_json (const struct MerchantInstance *mi,
+                    const struct GNUNET_HashCode *h_contract_terms,
+                    enum TALER_ErrorCode *ret_ec,
+                    const char **ret_errmsg)
+{
+  enum GNUNET_DB_QueryStatus qs;
+  struct ProcessRefundData prd;
+
   prd.response = json_array ();
-  prd.h_contract_terms = &h_contract_terms;
+  prd.h_contract_terms = h_contract_terms;
   prd.merchant = mi;
   prd.ec = TALER_EC_NONE;
   for (unsigned int i=0;i<MAX_RETRIES;i++)
-  {  
+  {
     qs = db->get_refunds_from_contract_terms_hash (db->cls,
                                                   &mi->pubkey,
-                                                  &h_contract_terms,
+                                                  h_contract_terms,
                                                   &process_refunds_cb,
                                                   &prd);
     if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
@@ -472,26 +515,22 @@ MH_handler_refund_lookup (struct TMH_RequestHandler *rh,
   }
   if (0 > qs)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
-                "database hard error on order_id lookup: %s\n",
-                order_id);
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Database hard error on refunds_from_contract_terms_hash 
lookup: %s\n",
+                GNUNET_h2s (h_contract_terms));
     json_decref (prd.response);
-    return TMH_RESPONSE_reply_internal_error (connection,
-                                              TALER_EC_REFUND_LOOKUP_DB_ERROR,
-                                              "database hard error: looking 
for "
-                                              "h_contract_terms in 
merchant_refunds table");
+    *ret_ec = TALER_EC_REFUND_LOOKUP_DB_ERROR;
+    *ret_errmsg = ("database hard error: looking for "
+                  "h_contract_terms in merchant_refunds table");
   }
   if (TALER_EC_NONE != prd.ec)
   {
     json_decref (prd.response);
     /* NOTE: error already logged by the callback */
-    return TMH_RESPONSE_reply_internal_error (connection,
-                                              prd.ec,
-                                              "Could not generate a 
response"); 
+    *ret_ec = prd.ec;
+    *ret_errmsg = "Could not generate a response";
   }
-   return TMH_RESPONSE_reply_json (connection,
-                                  prd.response,
-                                  MHD_HTTP_OK);
+  return prd.response;
 }
 
 
diff --git a/src/backend/taler-merchant-httpd_refund.h 
b/src/backend/taler-merchant-httpd_refund.h
index 64da3f9..3208327 100644
--- a/src/backend/taler-merchant-httpd_refund.h
+++ b/src/backend/taler-merchant-httpd_refund.h
@@ -25,6 +25,7 @@
 #include <microhttpd.h>
 #include "taler-merchant-httpd.h"
 
+
 /**
  * Handle request for increasing the refund associated with
  * a contract.
@@ -59,4 +60,20 @@ MH_handler_refund_lookup (struct TMH_RequestHandler *rh,
                           void **connection_cls,
                           const char *upload_data,
                           size_t *upload_data_size);
+
+/**
+ * Get the JSON representation of a refund.
+ *
+ * @param merchant_pub the merchant's public key
+ * @param mi merchant instance
+ * @param ret_ec where to store error code
+ * @param ret_errmsg where to store error message
+ * @return NULL on error, JSON array with refunds on success
+ */
+json_t *
+TM_get_refund_json (const struct MerchantInstance *mi,
+                    const struct GNUNET_HashCode *h_contract_terms,
+                    enum TALER_ErrorCode *ret_ec,
+                    const char **ret_errmsg);
+
 #endif                          
diff --git a/src/backend/taler-merchant-httpd_responses.c 
b/src/backend/taler-merchant-httpd_responses.c
index 1ea2600..f5f994e 100644
--- a/src/backend/taler-merchant-httpd_responses.c
+++ b/src/backend/taler-merchant-httpd_responses.c
@@ -44,7 +44,11 @@ TMH_RESPONSE_make_json (const json_t *json)
 
   json_str = json_dumps (json,
                         JSON_INDENT(2));
-  GNUNET_assert (NULL != json_str);
+  if (NULL == json_str)
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
   resp = MHD_create_response_from_buffer (strlen (json_str),
                                          json_str,
                                           MHD_RESPMEM_MUST_FREE);
@@ -268,7 +272,7 @@ TMH_RESPONSE_reply_not_found (struct MHD_Connection 
*connection,
   return TMH_RESPONSE_reply_json_pack (connection,
                                        MHD_HTTP_NOT_FOUND,
                                        "{s:I, s:s}",
-                                      "code", (json_int_t) ec,       
+                                      "code", (json_int_t) ec,
                                        "error", object);
 }
 
diff --git a/src/backend/taler-merchant-httpd_track-transaction.c 
b/src/backend/taler-merchant-httpd_track-transaction.c
index 2848bc7..7a4d0c0 100644
--- a/src/backend/taler-merchant-httpd_track-transaction.c
+++ b/src/backend/taler-merchant-httpd_track-transaction.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  (C) 2014, 2015, 2016 INRIA
+  (C) 2014-2017 INRIA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Affero General Public License as published by the Free 
Software
@@ -75,9 +75,10 @@ make_track_transaction_ok (unsigned int num_transfers,
     {
       const struct TALER_MERCHANT_CoinWireTransfer *coin = &transfer->coins[j];
 
-      GNUNET_assert (GNUNET_SYSERR != TALER_amount_add (&sum,
-                                                        &sum,
-                                                        
&coin->amount_with_fee));
+      GNUNET_assert (GNUNET_SYSERR !=
+                    TALER_amount_add (&sum,
+                                      &sum,
+                                      &coin->amount_with_fee));
     }
 
     GNUNET_assert (0 ==
@@ -94,7 +95,6 @@ make_track_transaction_ok (unsigned int num_transfers,
 }
 
 
-
 /**
  * Context for a /track/transaction operation.
  */
@@ -481,7 +481,7 @@ wire_deposits_cb (void *cls,
          break;
       }
       if (0 > qs)
-      { 
+      {
        /* Not good, but not fatal either, log error and continue */
        /* Special report if retries insufficient */
        GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
@@ -812,7 +812,8 @@ handle_track_transaction_timeout (void *cls)
 
 /**
  * Function called with information about a transaction.
- * Its duty is to fill up the "context" for the whole operation.
+ * Responsible to fill up the "context" for the whole
+ * tracking operation.
  *
  * @param cls closure
  * @param transaction_id of the contract
@@ -1039,8 +1040,15 @@ MH_handler_track_transaction (struct TMH_RequestHandler 
*rh,
     return TMH_RESPONSE_reply_not_found (connection,
                                         TALER_EC_PROPOSAL_LOOKUP_NOT_FOUND,
                                         "Given order_id doesn't map to any 
proposal");
-  TALER_JSON_hash (contract_terms,
-                   &h_contract_terms);
+  if (GNUNET_OK !=
+      TALER_JSON_hash (contract_terms,
+                       &h_contract_terms))
+  {
+    json_decref (contract_terms);
+    return TMH_RESPONSE_reply_internal_error (connection,
+                                             TALER_EC_INTERNAL_LOGIC_ERROR,
+                                              "Failed to hash contract terms");
+  }
   json_decref (contract_terms);
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1058,7 +1066,7 @@ MH_handler_track_transaction (struct TMH_RequestHandler 
*rh,
     return TMH_RESPONSE_reply_internal_error (connection,
                                              
TALER_EC_TRACK_TRANSACTION_DB_FETCH_TRANSACTION_ERROR,
                                               "Database error finding 
transaction");
-  }  
+  }
   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
@@ -1090,7 +1098,7 @@ MH_handler_track_transaction (struct TMH_RequestHandler 
*rh,
     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != tctx->qs);
     return TMH_RESPONSE_reply_internal_error (connection,
                                               
TALER_EC_TRACK_TRANSACTION_DB_FETCH_PAYMENT_ERROR,
-                                             "Database error: failed in find 
payment data");
+                                             "Database error: failed to find 
payment data");
   }
   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
   {
diff --git a/src/backend/taler-merchant-httpd_track-transfer.c 
b/src/backend/taler-merchant-httpd_track-transfer.c
index d38cb66..f66457a 100644
--- a/src/backend/taler-merchant-httpd_track-transfer.c
+++ b/src/backend/taler-merchant-httpd_track-transfer.c
@@ -96,6 +96,11 @@ struct TrackTransferContext
   char *uri;
 
   /**
+   * Wire method used for the transfer.
+   */
+  char *wire_method;
+
+  /**
    * Pointer to the detail that we are currently
    * checking in #check_transfer().
    */
@@ -183,6 +188,11 @@ free_transfer_track_context (struct TrackTransferContext 
*rctx)
     GNUNET_free (rctx->uri);
     rctx->uri = NULL;
   }
+  if (NULL != rctx->wire_method)
+  {
+    GNUNET_free (rctx->wire_method);
+    rctx->wire_method = NULL;
+  }
   GNUNET_free (rctx);
 }
 
@@ -459,7 +469,7 @@ check_transfer (void *cls,
                                      "exchange_deposit_proof", exchange_proof,
                                      "conflict_offset", (json_int_t) 
rctx->current_offset,
                                      "exchange_transfer_proof", 
rctx->original_response,
-                                     "coin_pub", GNUNET_JSON_from_data_auto 
(coin_pub),
+                                     "coin_pub", GNUNET_JSON_from_data_auto 
(coin_pub), 
                                      "h_contract_terms", 
GNUNET_JSON_from_data_auto (&ttd->h_contract_terms),
                                      "amount_with_fee", TALER_JSON_from_amount 
(amount_with_fee),
                                      "deposit_fee", TALER_JSON_from_amount 
(deposit_fee));
@@ -470,6 +480,90 @@ check_transfer (void *cls,
 
 
 /**
+ * Check that the given @a wire_fee is what the 
+ * @a exchange_pub should charge at the @a execution_time.
+ * If the fee is correct (according to our database),
+ * return #GNUNET_OK.  If we do not have the fee structure
+ * in our DB, we just accept it and return #GNUNET_NO;
+ * if we have proof that the fee is bogus, we respond with
+ * the proof to the client and return #GNUNET_SYSERR.
+ *
+ * @param rctx context of the transfer to respond to
+ * @param json response from the exchange
+ * @param execution_time time of the wire transfer
+ * @param wire_fee fee claimed by the exchange
+ * @return #GNUNET_SYSERR if we returned hard proof of
+ *   missbehavior from the exchange to the client
+ */
+static int
+check_wire_fee (struct TrackTransferContext *rctx,
+               const json_t *json,
+               struct GNUNET_TIME_Absolute execution_time,
+               const struct TALER_Amount *wire_fee)
+{
+  const struct TALER_MasterPublicKeyP *master_pub;
+  struct GNUNET_HashCode h_wire_method;
+  struct TALER_Amount expected_fee;
+  struct TALER_Amount closing_fee;
+  struct TALER_MasterSignatureP master_sig;
+  struct GNUNET_TIME_Absolute start_date;
+  struct GNUNET_TIME_Absolute end_date;
+  enum GNUNET_DB_QueryStatus qs;
+  const struct TALER_EXCHANGE_Keys *keys;
+
+  keys = TALER_EXCHANGE_get_keys (rctx->eh);
+  if (NULL == keys)
+  {
+    GNUNET_break (0);
+    return GNUNET_NO;
+  }
+  master_pub = &keys->master_pub;
+  GNUNET_CRYPTO_hash (rctx->wire_method,
+                     strlen (rctx->wire_method) + 1,
+                     &h_wire_method);
+  qs = db->lookup_wire_fee (db->cls,
+                           master_pub,
+                           &h_wire_method,
+                           execution_time,
+                           &expected_fee,
+                           &closing_fee,
+                           &start_date,
+                           &end_date,
+                           &master_sig);
+  if (0 >= qs)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+               "Failed to find wire fee for `%s' and method `%s' at %s in DB, 
accepting blindly that the fee is %s\n",
+               TALER_B2S (master_pub),
+               rctx->wire_method,
+               GNUNET_STRINGS_absolute_time_to_string (execution_time),
+               TALER_amount2s (wire_fee));
+    return GNUNET_NO;
+  }
+  if (0 <= TALER_amount_cmp (&expected_fee,
+                            wire_fee))
+    return GNUNET_OK; /* expected_fee >= wire_fee */
+  
+  /* Wire fee check failed, export proof to client */
+  resume_track_transfer_with_response
+    (rctx,
+     MHD_HTTP_INTERNAL_SERVER_ERROR,
+     TMH_RESPONSE_make_json_pack ("{s:I, s:o, s:o, s:o, s:o, s:o, s:o, s:o, 
s:o, s:O}",
+                                 "code", (json_int_t) 
TALER_EC_TRACK_TRANSFER_JSON_BAD_WIRE_FEE,
+                                 "wire_fee", TALER_JSON_from_amount (wire_fee),
+                                 "execution_time", GNUNET_JSON_from_time_abs 
(execution_time),
+                                 "expected_wire_fee", TALER_JSON_from_amount 
(&expected_fee),
+                                 "expected_closing_fee", 
TALER_JSON_from_amount (&closing_fee),
+                                 "start_date", GNUNET_JSON_from_time_abs 
(start_date),
+                                 "end_date", GNUNET_JSON_from_time_abs 
(end_date),
+                                 "master_sig", GNUNET_JSON_from_data_auto 
(&master_sig),
+                                 "master_pub", GNUNET_JSON_from_data_auto 
(master_pub),
+                                 "json", json));
+  return GNUNET_SYSERR;
+}
+
+
+/**
  * Function called with detailed wire transfer data, including all
  * of the coin transactions that were combined into the wire transfer.
  *
@@ -546,6 +640,14 @@ wire_transfer_cb (void *cls,
     return;
   }
   rctx->original_response = json;
+
+  if (GNUNET_SYSERR ==
+      check_wire_fee (rctx,
+                     json,
+                     execution_time,
+                     wire_fee))
+    return;
+
   for (unsigned int i=0;i<details_length;i++)
   {
     rctx->current_offset = i;
@@ -775,6 +877,7 @@ MH_handler_track_transfer (struct TMH_RequestHandler *rh,
   const char *str;
   const char *uri;
   const char *instance_str;
+  const char *wire_method;
   int ret;
   enum GNUNET_DB_QueryStatus qs;
 
@@ -831,6 +934,26 @@ MH_handler_track_transfer (struct TMH_RequestHandler *rh,
                                            "exchange");
   rctx->uri = GNUNET_strdup (uri);
 
+  wire_method = MHD_lookup_connection_value (connection,
+                                            MHD_GET_ARGUMENT_KIND,
+                                            "wire_method");
+  if (NULL == wire_method)
+  {
+    if (1)
+    {
+      /* temporary work-around until demo is adjusted... */
+      GNUNET_break (0);
+      wire_method = "test";
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 "Client needs fixing, see API change for #4943!\n");
+    }
+    else
+      return TMH_RESPONSE_reply_arg_missing (connection,
+                                            TALER_EC_PARAMETER_MISSING,
+                                            "wire_method");
+  }
+  rctx->wire_method = GNUNET_strdup (wire_method);
+
   instance_str = MHD_lookup_connection_value (connection,
                                               MHD_GET_ARGUMENT_KIND,
                                               "instance");
diff --git a/src/backenddb/Makefile.am b/src/backenddb/Makefile.am
index b38863c..a33ced8 100644
--- a/src/backenddb/Makefile.am
+++ b/src/backenddb/Makefile.am
@@ -10,6 +10,11 @@ plugin_LTLIBRARIES = \
 endif
 endif
 
+if USE_COVERAGE
+  AM_CFLAGS = --coverage -O0
+  XLIB = -lgcov
+endif
+
 lib_LTLIBRARIES = \
   libtalermerchantdb.la
 
diff --git a/src/backenddb/plugin_merchantdb_postgres.c 
b/src/backenddb/plugin_merchantdb_postgres.c
index 45ecab5..d0265d5 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -41,6 +41,11 @@ struct PostgresClosure
    */
   PGconn *conn;
 
+  /**
+   * Underlying configuration.
+   */
+  const struct GNUNET_CONFIGURATION_Handle *cfg;
+
 };
 
 
@@ -55,12 +60,13 @@ postgres_drop_tables (void *cls)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_ExecuteStatement es[] = {
-    GNUNET_PQ_make_try_execute ("DROP TABLE merchant_transfers;"),
-    GNUNET_PQ_make_try_execute ("DROP TABLE merchant_deposits;"),
-    GNUNET_PQ_make_try_execute ("DROP TABLE merchant_transactions;"),
-    GNUNET_PQ_make_try_execute ("DROP TABLE merchant_proofs;"),
-    GNUNET_PQ_make_try_execute ("DROP TABLE merchant_contract_terms;"),
-    GNUNET_PQ_make_try_execute ("DROP TABLE merchant_refunds;"),
+    GNUNET_PQ_make_try_execute ("DROP TABLE IF EXISTS merchant_transfers 
CASCADE;"),
+    GNUNET_PQ_make_try_execute ("DROP TABLE IF EXISTS merchant_deposits 
CASCADE;"),
+    GNUNET_PQ_make_try_execute ("DROP TABLE IF EXISTS merchant_transactions 
CASCADE;"),
+    GNUNET_PQ_make_try_execute ("DROP TABLE IF EXISTS merchant_proofs 
CASCADE;"),
+    GNUNET_PQ_make_try_execute ("DROP TABLE IF EXISTS merchant_contract_terms 
CASCADE;"),
+    GNUNET_PQ_make_try_execute ("DROP TABLE IF EXISTS merchant_refunds 
CASCADE;"),
+    GNUNET_PQ_make_try_execute ("DROP TABLE IF EXISTS exchange_wire_fees 
CASCADE;"),
     GNUNET_PQ_EXECUTE_STATEMENT_END
   };
 
@@ -80,31 +86,21 @@ postgres_initialize (void *cls)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_ExecuteStatement es[] = {
+    /* Offers we made to customers */
     GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS 
merchant_contract_terms ("
                             "order_id VARCHAR NOT NULL"
-                            ",merchant_pub BYTEA NOT NULL"
+                            ",merchant_pub BYTEA NOT NULL CHECK 
(LENGTH(merchant_pub)=32)"
                             ",contract_terms BYTEA NOT NULL"
-                            ",h_contract_terms BYTEA NOT NULL"
+                            ",h_contract_terms BYTEA NOT NULL CHECK 
(LENGTH(h_contract_terms)=64)"
                             ",timestamp INT8 NOT NULL"
-                            ",row_id BIGSERIAL"
+                            ",row_id BIGSERIAL UNIQUE"
+                            ",paid BYTEA NOT NULL " /* WHY is this a BYTEA!? 
Why does this EXIST!? */
                             ",PRIMARY KEY (order_id, merchant_pub)"
                            ",UNIQUE (h_contract_terms, merchant_pub)"
                             ");"),
-    GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_refunds ("
-                            " rtransaction_id BIGSERIAL"
-                            ",merchant_pub BYTEA NOT NULL CHECK 
(LENGTH(merchant_pub)=32)"
-                            ",h_contract_terms BYTEA NOT NULL"
-                            ",coin_pub BYTEA NOT NULL CHECK 
(LENGTH(coin_pub)=32)"
-                            ",reason VARCHAR NOT NULL"
-                            ",refund_amount_val INT8 NOT NULL"
-                            ",refund_amount_frac INT4 NOT NULL"
-                            ",refund_amount_curr VARCHAR(" 
TALER_CURRENCY_LEN_STR ") NOT NULL"
-                            ",refund_fee_val INT8 NOT NULL"
-                            ",refund_fee_frac INT4 NOT NULL"
-                            ",refund_fee_curr VARCHAR(" TALER_CURRENCY_LEN_STR 
") NOT NULL"
-                            ");"),
+    /* Contracts that were paid via some exchange (or attempted to be paid???) 
*/
     GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_transactions 
("
-                            " h_contract_terms BYTEA NOT NULL"
+                            " h_contract_terms BYTEA NOT NULL CHECK 
(LENGTH(h_contract_terms)=64)"
                             ",exchange_uri VARCHAR NOT NULL"
                             ",merchant_pub BYTEA NOT NULL CHECK 
(LENGTH(merchant_pub)=32)"
                             ",h_wire BYTEA NOT NULL CHECK (LENGTH(h_wire)=64)"
@@ -114,11 +110,12 @@ postgres_initialize (void *cls)
                             ",total_amount_frac INT4 NOT NULL"
                             ",total_amount_curr VARCHAR(" 
TALER_CURRENCY_LEN_STR ") NOT NULL"
                             ",PRIMARY KEY (h_contract_terms, merchant_pub)"
+                            ",FOREIGN KEY (h_contract_terms, merchant_pub) 
REFERENCES merchant_contract_terms (h_contract_terms, merchant_pub)"
                             ");"),
+    /* Table with the proofs for each coin we deposited at the exchange */
     GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_deposits ("
                             " h_contract_terms BYTEA NOT NULL"
                             ",merchant_pub BYTEA NOT NULL CHECK 
(LENGTH(merchant_pub)=32)"
-                            ",FOREIGN KEY (h_contract_terms, merchant_pub) 
REFERENCES merchant_transactions (h_contract_terms, merchant_pub)"
                             ",coin_pub BYTEA NOT NULL CHECK 
(LENGTH(coin_pub)=32)"
                             ",amount_with_fee_val INT8 NOT NULL"
                             ",amount_with_fee_frac INT4 NOT NULL"
@@ -132,15 +129,16 @@ postgres_initialize (void *cls)
                             ",signkey_pub BYTEA NOT NULL CHECK 
(LENGTH(signkey_pub)=32)"
                             ",exchange_proof BYTEA NOT NULL"
                             ",PRIMARY KEY (h_contract_terms, coin_pub)"
+                            ",FOREIGN KEY (h_contract_terms, merchant_pub) 
REFERENCES merchant_transactions (h_contract_terms, merchant_pub)"
                             ");"),
     GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_proofs ("
-                          " exchange_uri VARCHAR NOT NULL"
-                          ",wtid BYTEA CHECK (LENGTH(wtid)=32)"
-                          ",execution_time INT8 NOT NULL"
-                          ",signkey_pub BYTEA NOT NULL CHECK 
(LENGTH(signkey_pub)=32)"
-                          ",proof BYTEA NOT NULL"
-                          ",PRIMARY KEY (wtid, exchange_uri)"
-                          ");"),
+                            " exchange_uri VARCHAR NOT NULL"
+                            ",wtid BYTEA CHECK (LENGTH(wtid)=32)"
+                            ",execution_time INT8 NOT NULL"
+                            ",signkey_pub BYTEA NOT NULL CHECK 
(LENGTH(signkey_pub)=32)"
+                            ",proof BYTEA NOT NULL"
+                            ",PRIMARY KEY (wtid, exchange_uri)"
+                            ");"),
     /* Note that h_contract_terms + coin_pub may actually be unknown to
        us, e.g. someone else deposits something for us at the exchange.
        Hence those cannot be foreign keys into deposits/transactions! */
@@ -168,6 +166,19 @@ postgres_initialize (void *cls)
                            ",exchange_sig BYTEA NOT NULL CHECK 
(length(exchange_sig)=64)"
                            ",PRIMARY KEY 
(exchange_pub,h_wire_method,start_date,end_date)"
                            ");"),
+    GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_refunds ("
+                            " rtransaction_id BIGSERIAL UNIQUE"
+                            ",merchant_pub BYTEA NOT NULL CHECK 
(LENGTH(merchant_pub)=32)"
+                            ",h_contract_terms BYTEA NOT NULL"
+                            ",coin_pub BYTEA NOT NULL CHECK 
(LENGTH(coin_pub)=32)"
+                            ",reason VARCHAR NOT NULL"
+                            ",refund_amount_val INT8 NOT NULL"
+                            ",refund_amount_frac INT4 NOT NULL"
+                            ",refund_amount_curr VARCHAR(" 
TALER_CURRENCY_LEN_STR ") NOT NULL"
+                            ",refund_fee_val INT8 NOT NULL"
+                            ",refund_fee_frac INT4 NOT NULL"
+                            ",refund_fee_curr VARCHAR(" TALER_CURRENCY_LEN_STR 
") NOT NULL"
+                            ");"),
     GNUNET_PQ_EXECUTE_STATEMENT_END
   };
   struct GNUNET_PQ_PreparedStatement ps[] = {
@@ -239,11 +250,17 @@ postgres_initialize (void *cls)
                             "(order_id"
                             ",merchant_pub"
                             ",timestamp"
+                            ",paid"
                             ",contract_terms"
                             ",h_contract_terms)"
                             " VALUES "
-                            "($1, $2, $3, $4, $5)",
-                            4),
+                            "($1, $2, $3, $4, $5, $6)",
+                            6),
+    GNUNET_PQ_make_prepare ("mark_proposal_paid",
+                            "UPDATE merchant_contract_terms SET"
+                            " paid=$1 WHERE h_contract_terms=$2"
+                            " AND merchant_pub=$3",
+                            3),
     GNUNET_PQ_make_prepare ("insert_wire_fee",
                             "INSERT INTO exchange_wire_fees"
                             "(exchange_pub"
@@ -260,13 +277,29 @@ postgres_initialize (void *cls)
                             " VALUES "
                             "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)",
                             11),
+    GNUNET_PQ_make_prepare ("lookup_wire_fee",
+                            "SELECT"
+                            " wire_fee_val"
+                            ",wire_fee_frac"
+                            ",wire_fee_curr"
+                            ",closing_fee_val"
+                            ",closing_fee_frac"
+                            ",closing_fee_curr"
+                            ",start_date"
+                            ",end_date"
+                            ",exchange_sig"
+                            " FROM exchange_wire_fees"
+                            " WHERE exchange_pub=$1"
+                           "   AND h_wire_method=$2"
+                           "   AND start_date <= $3"
+                           "   AND end_date > $3",
+                            1),
     GNUNET_PQ_make_prepare ("find_contract_terms_from_hash",
                             "SELECT"
                             " contract_terms"
                             " FROM merchant_contract_terms"
-                            " WHERE"
-                            " h_contract_terms=$1"
-                            " AND merchant_pub=$2",
+                            " WHERE h_contract_terms=$1"
+                            "   AND merchant_pub=$2",
                             2),
     GNUNET_PQ_make_prepare ("end_transaction",
                             "COMMIT",
@@ -281,6 +314,15 @@ postgres_initialize (void *cls)
                             " FROM merchant_refunds"
                             " WHERE coin_pub=$1",
                             1),
+    GNUNET_PQ_make_prepare ("find_contract_terms_history",
+                            "SELECT"
+                            " contract_terms"
+                            " FROM merchant_contract_terms"
+                            " WHERE"
+                            " order_id=$1"
+                            " AND merchant_pub=$2"
+                            " AND paid=$3",
+                            3),
     GNUNET_PQ_make_prepare ("find_contract_terms",
                             "SELECT"
                             " contract_terms"
@@ -289,6 +331,7 @@ postgres_initialize (void *cls)
                             " order_id=$1"
                             " AND merchant_pub=$2",
                             2),
+
     GNUNET_PQ_make_prepare ("find_contract_terms_by_date",
                             "SELECT"
                             " contract_terms"
@@ -298,9 +341,10 @@ postgres_initialize (void *cls)
                             " WHERE"
                             " timestamp<$1"
                             " AND merchant_pub=$2"
+                            " AND paid=$4"
                             " ORDER BY row_id DESC, timestamp DESC"
                             " LIMIT $3",
-                            3),
+                            4),
     GNUNET_PQ_make_prepare ("find_refunds_from_contract_terms_hash",
                             "SELECT"
                            " coin_pub"
@@ -326,9 +370,10 @@ postgres_initialize (void *cls)
                             " timestamp<$1"
                             " AND merchant_pub=$2"
                             " AND row_id<$3"
+                            " AND paid=$5"
                             " ORDER BY row_id DESC, timestamp DESC"
                             " LIMIT $4",
-                            4),
+                            5),
     GNUNET_PQ_make_prepare ("find_contract_terms_by_date_and_range_future",
                             "SELECT"
                             " contract_terms"
@@ -339,9 +384,10 @@ postgres_initialize (void *cls)
                             " timestamp>$1"
                             " AND merchant_pub=$2"
                             " AND row_id>$3"
+                            " AND paid=$5"
                             " ORDER BY row_id DESC, timestamp DESC"
                             " LIMIT $4",
-                            4),
+                            5),
     GNUNET_PQ_make_prepare ("find_transaction",
                             "SELECT"
                             " exchange_uri"
@@ -460,6 +506,9 @@ check_connection (struct PostgresClosure *pg)
   if (CONNECTION_BAD != PQstatus (pg->conn))
     return;
   PQfinish (pg->conn);
+  pg->conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
+                                         "merchantdb-postgres");
+  GNUNET_break (NULL != pg->conn);
   GNUNET_break (GNUNET_OK ==
                postgres_initialize (pg));
 }
@@ -471,7 +520,7 @@ check_connection (struct PostgresClosure *pg)
  * @param cls the `struct PostgresClosure` with the plugin-specific state
  * @return #GNUNET_OK on success
  */
-static int
+int
 postgres_start (void *cls)
 {
   struct PostgresClosure *pg = cls;
@@ -479,6 +528,8 @@ postgres_start (void *cls)
   ExecStatusType ex;
 
   check_connection (pg);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Starting merchant DB transaction\n");
   result = PQexec (pg->conn,
                    "START TRANSACTION ISOLATION LEVEL SERIALIZABLE");
   if (PGRES_COMMAND_OK !=
@@ -502,12 +553,14 @@ postgres_start (void *cls)
  * @param cls the `struct PostgresClosure` with the plugin-specific state
  * @return #GNUNET_OK on success
  */
-static void
+void
 postgres_rollback (void *cls)
 {
   struct PostgresClosure *pg = cls;
   PGresult *result;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Rolling back merchant DB transaction\n");
   result = PQexec (pg->conn,
                    "ROLLBACK");
   GNUNET_break (PGRES_COMMAND_OK ==
@@ -530,6 +583,8 @@ postgres_commit (void *cls)
     GNUNET_PQ_query_param_end
   };
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Committing merchant DB transaction\n");
   return GNUNET_PQ_eval_prepared_non_select (pg->conn,
                                             "end_transaction",
                                             params);
@@ -572,7 +627,8 @@ postgres_find_contract_terms_from_hash (void *cls,
 
 
 /**
- * Retrieve proposal data given its order id.
+ * Retrieve proposal data given its order id.  Ignores if the
+ * proposal has been paid or not.
  *
  * @param cls closure
  * @param[out] contract_terms where to store the retrieved contract terms
@@ -586,6 +642,7 @@ postgres_find_contract_terms (void *cls,
                               const struct TALER_MerchantPublicKeyP 
*merchant_pub)
 {
   struct PostgresClosure *pg = cls;
+
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_string (order_id),
     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
@@ -627,19 +684,25 @@ postgres_insert_contract_terms (void *cls,
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_HashCode h_contract_terms;
+  unsigned int no = GNUNET_NO;
+
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_string (order_id),
     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
     GNUNET_PQ_query_param_absolute_time (&timestamp),
+    GNUNET_PQ_query_param_auto_from_type (&no),
     TALER_PQ_query_param_json (contract_terms),
     GNUNET_PQ_query_param_auto_from_type (&h_contract_terms),
     GNUNET_PQ_query_param_end
   };
-  
+
   if (GNUNET_OK !=
       TALER_JSON_hash (contract_terms,
                       &h_contract_terms))
+  {
+    GNUNET_break (0);
     return GNUNET_SYSERR;
+  }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "inserting contract_terms: order_id: %s, merchant_pub: %s, 
h_contract_terms: %s.\n",
               order_id,
@@ -653,6 +716,38 @@ postgres_insert_contract_terms (void *cls,
 
 
 /**
+ * Mark contract terms as payed.  Needed by /history as only payed
+ * contracts must be shown.  NOTE: we can't get the list of (payed)
+ * contracts from the transactions table because it lacks contract_terms
+ * plain JSON.  In facts, the protocol doesn't allow to store contract_terms
+ * in transactions table, as /pay handler doesn't receive this data
+ * (only /proposal does).
+ */
+enum GNUNET_DB_QueryStatus
+postgres_mark_proposal_paid (void *cls,
+                             const struct GNUNET_HashCode *h_contract_terms,
+                             const struct TALER_MerchantPublicKeyP 
*merchant_pub)
+{
+  unsigned int yes = GNUNET_YES;
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (&yes),
+    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+    GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+    GNUNET_PQ_query_param_end
+  };
+
+  TALER_LOG_DEBUG ("Marking proposal paid, h_contract_terms: '%s',"
+                   " merchant_pub: '%s'\n",
+                   GNUNET_h2s (h_contract_terms),
+                   TALER_B2S (merchant_pub));
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "mark_proposal_paid",
+                                             params);
+}
+
+
+/**
  * Insert transaction data into the database.
  *
  * @param cls closure
@@ -738,11 +833,12 @@ postgres_store_deposit (void *cls,
   };
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "storing payment for h_contract_terms '%s'"
-              ", coin_pub: %s, amount_with_fee: %s, merchant_pub: %s\n",
+              "Storing payment for h_contract_terms `%s', coin_pub: `%s', 
amount_with_fee: %s\n",
               GNUNET_h2s (h_contract_terms),
               TALER_B2S (coin_pub),
-              TALER_amount_to_string (amount_with_fee),
+              TALER_amount_to_string (amount_with_fee));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Merchant pub is `%s'\n",
               TALER_B2S (merchant_pub));
   check_connection (pg);
   return GNUNET_PQ_eval_prepared_non_select (pg->conn,
@@ -840,9 +936,12 @@ postgres_find_contract_terms_history (void *cls,
   struct PostgresClosure *pg = cls;
   json_t *contract_terms;
   enum GNUNET_DB_QueryStatus qs;
+  unsigned int yes = GNUNET_YES;
+
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_string (order_id),
     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+    GNUNET_PQ_query_param_auto_from_type (&yes),
     GNUNET_PQ_query_param_end
   };
   struct GNUNET_PQ_ResultSpec rs[] = {
@@ -852,7 +951,7 @@ postgres_find_contract_terms_history (void *cls,
   };
 
   qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                "find_contract_terms",
+                                                "find_contract_terms_history",
                                                 params,
                                                 rs);
   if (qs <= 0)
@@ -883,11 +982,11 @@ struct FindContractsContext
 
   /**
    * Transaction status code to set.
-   */ 
+   */
   enum GNUNET_DB_QueryStatus qs;
 };
 
-  
+
 /**
  * Function to be called with the results of a SELECT statement
  * that has returned @a num_results results.
@@ -902,7 +1001,7 @@ find_contracts_cb (void *cls,
                   unsigned int num_results)
 {
   struct FindContractsContext *fcctx = cls;
-  
+
   for (unsigned int i = 0; i < num_results; i++)
   {
     char *order_id;
@@ -973,11 +1072,14 @@ postgres_find_contract_terms_by_date_and_range (void 
*cls,
                                                void *cb_cls)
 {
   struct PostgresClosure *pg = cls;
+  unsigned int yes = GNUNET_YES;
+
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_absolute_time (&date),
     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
     GNUNET_PQ_query_param_uint64 (&start),
     GNUNET_PQ_query_param_uint64 (&nrows),
+    GNUNET_PQ_query_param_auto_from_type (&yes),
     GNUNET_PQ_query_param_end
   };
   const char *stmt;
@@ -986,7 +1088,9 @@ postgres_find_contract_terms_by_date_and_range (void *cls,
     .cb = cb,
     .cb_cls = cb_cls
   };
-
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "DB serving /history with date %s\n",
+              GNUNET_STRINGS_absolute_time_to_string (date));
   if (GNUNET_YES == future)
     stmt = "find_contract_terms_by_date_and_range_future";
   else
@@ -1025,10 +1129,13 @@ postgres_find_contract_terms_by_date (void *cls,
                                      void *cb_cls)
 {
   struct PostgresClosure *pg = cls;
+  unsigned int yes = GNUNET_YES;
+
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_absolute_time (&date),
     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
     GNUNET_PQ_query_param_uint64 (&nrows),
+    GNUNET_PQ_query_param_auto_from_type (&yes),
     GNUNET_PQ_query_param_end
   };
   enum GNUNET_DB_QueryStatus qs;
@@ -1127,17 +1234,17 @@ struct FindPaymentsContext
    * Function to call with results.
    */
   TALER_MERCHANTDB_CoinDepositCallback cb;
-  
+
   /**
    * Closure for @e cls.
    */
   void *cb_cls;
 
-  /** 
+  /**
    * Contract term hash used for the search.
    */
   const struct GNUNET_HashCode *h_contract_terms;
-  
+
   /**
    * Transaction status (set).
    */
@@ -1159,7 +1266,7 @@ find_payments_cb (void *cls,
                  unsigned int num_results)
 {
   struct FindPaymentsContext *fpc = cls;
-  
+
   for (unsigned int i=0;i<num_results;i++)
   {
     struct TALER_CoinSpendPublicKeyP coin_pub;
@@ -1233,7 +1340,7 @@ postgres_find_payments (void *cls,
     .cb_cls = cb_cls
   };
   enum GNUNET_DB_QueryStatus qs;
-  
+
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Finding payment for h_contract_terms '%s'\n",
               GNUNET_h2s (h_contract_terms));
@@ -1258,7 +1365,7 @@ struct FindPaymentsByCoinContext
    * Function to call with results.
    */
   TALER_MERCHANTDB_CoinDepositCallback cb;
-  
+
   /**
    * Closure for @e cls.
    */
@@ -1266,14 +1373,14 @@ struct FindPaymentsByCoinContext
 
   /**
    * Coin we are looking for.
-   */ 
+   */
   const struct TALER_CoinSpendPublicKeyP *coin_pub;
 
   /**
    * Hash of the contract we are looking for.
-   */ 
+   */
   const struct GNUNET_HashCode *h_contract_terms;
-  
+
   /**
    * Transaction status (set).
    */
@@ -1295,7 +1402,7 @@ find_payments_by_coin_cb (void *cls,
                          unsigned int num_results)
 {
   struct FindPaymentsByCoinContext *fpc = cls;
-  
+
   for (unsigned int i=0;i<num_results;i++)
   {
     struct TALER_Amount amount_with_fee;
@@ -1397,11 +1504,11 @@ struct FindTransfersContext
    */
   void *cb_cls;
 
-  /** 
+  /**
    * Hash of the contract we are looking under.
    */
   const struct GNUNET_HashCode *h_contract_terms;
-  
+
   /**
    * Transaction status (set).
    */
@@ -1462,7 +1569,7 @@ find_transfers_cb (void *cls,
     GNUNET_PQ_cleanup_result (rs);
   }
 }
-  
+
 
 /**
  * Lookup information about a transfer by @a h_contract_terms.  Note
@@ -1494,7 +1601,7 @@ postgres_find_transfers_by_hash (void *cls,
     .cb_cls = cb_cls
   };
   enum GNUNET_DB_QueryStatus qs;
-  
+
   check_connection (pg);
   qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
                                             "find_transfers_by_hash",
@@ -1515,14 +1622,14 @@ struct FindDepositsContext
 
   /**
    * Function to call for each result.
-   */ 
+   */
   TALER_MERCHANTDB_CoinDepositCallback cb;
 
   /**
    * Closure for @e cb.
    */
   void *cb_cls;
-  
+
   /**
    * Transaction status (set).
    */
@@ -1641,7 +1748,7 @@ struct GetRefundsContext
 
   /**
    * Closure for @e rc.
-   */ 
+   */
   void *rc_cls;
 
   /**
@@ -1665,7 +1772,7 @@ get_refunds_cb (void *cls,
                unsigned int num_results)
 {
   struct GetRefundsContext *grc = cls;
-  
+
   for (unsigned int i=0;i<num_results;i++)
   {
     struct TALER_CoinSpendPublicKeyP coin_pub;
@@ -1748,8 +1855,8 @@ postgres_get_refunds_from_contract_terms_hash (void *cls,
                                             &get_refunds_cb,
                                             &grc);
   if (0 >= qs)
-    return qs; 
-  return grc.qs; 
+    return qs;
+  return grc.qs;
 }
 
 
@@ -1788,7 +1895,7 @@ insert_refund (void *cls,
   TALER_LOG_DEBUG ("Inserting refund %s + %s\n",
                    GNUNET_h2s (h_contract_terms),
                    TALER_B2S (merchant_pub));
-  
+
   check_connection (pg);
   return GNUNET_PQ_eval_prepared_non_select (pg->conn,
                                              "insert_refund",
@@ -1834,9 +1941,70 @@ postgres_store_wire_fee_by_exchange (void *cls,
   };
 
   check_connection (pg);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+             "Storing wire fee for %s starting at %s of %s\n",
+             TALER_B2S (exchange_pub),
+             GNUNET_STRINGS_absolute_time_to_string (start_date),
+             TALER_amount2s (wire_fee));
   return GNUNET_PQ_eval_prepared_non_select (pg->conn,
                                              "insert_wire_fee",
-                                             params);  
+                                             params);
+}
+
+
+/**
+ * Obtain information about wire fees charged by an exchange,
+ * including signature (so we have proof).
+ *
+ * @param cls closure
+ * @param exchange_pub public key of the exchange
+ * @param h_wire_method hash of wire method
+ * @param contract_date date of the contract to use for the lookup
+ * @param[out] wire_fee wire fee charged
+ * @param[out] closing_fee closing fee charged (irrelevant for us,
+ *              but needed to check signature)
+ * @param[out] start_date start of fee being used
+ * @param[out] end_date end of fee being used
+ * @param[out] exchange_sig signature of exchange over fee structure
+ * @return transaction status code
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_lookup_wire_fee (void *cls,
+                         const struct TALER_MasterPublicKeyP *exchange_pub,
+                         const struct GNUNET_HashCode *h_wire_method,
+                         struct GNUNET_TIME_Absolute contract_date,
+                         struct TALER_Amount *wire_fee,
+                         struct TALER_Amount *closing_fee,
+                         struct GNUNET_TIME_Absolute *start_date,
+                         struct GNUNET_TIME_Absolute *end_date,
+                         struct TALER_MasterSignatureP *exchange_sig)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (exchange_pub),
+    GNUNET_PQ_query_param_auto_from_type (h_wire_method),
+    GNUNET_PQ_query_param_absolute_time (&contract_date),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    TALER_PQ_result_spec_amount ("wire_fee",
+                                wire_fee),
+    TALER_PQ_result_spec_amount ("closing_fee",
+                                closing_fee),
+    GNUNET_PQ_result_spec_absolute_time ("start_date",
+                                        start_date),
+    GNUNET_PQ_result_spec_absolute_time ("end_date",
+                                        end_date),
+    GNUNET_PQ_result_spec_auto_from_type ("exchange_sig",
+                                         exchange_sig),
+    GNUNET_PQ_result_spec_end
+  };
+
+  check_connection (pg);
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                  "lookup_wire_fee",
+                                                  params,
+                                                  rs);
 }
 
 
@@ -1958,22 +2126,24 @@ process_deposits_for_refund_cb (void *cls,
                                unsigned int num_results)
 {
   struct InsertRefundContext *ctx = cls;
-  struct TALER_Amount previous_refund;
+  struct TALER_Amount current_refund;
+  struct TALER_Amount deposit_refund[num_results];
+  struct TALER_CoinSpendPublicKeyP deposit_coin_pubs[num_results];
+  struct TALER_Amount deposit_amount_with_fee[num_results];
+  struct TALER_Amount deposit_refund_fee[num_results];
 
-  TALER_amount_get_zero (ctx->refund->currency,
-                         &previous_refund);
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_amount_get_zero (ctx->refund->currency,
+                                        &current_refund));
 
-  for (unsigned int i=0;i<num_results;i++)
+  /* Pass 1:  Collect amount of existing refunds into current_refund.
+   * Also store existing refunded amount for each deposit in deposit_refund. */
+
+  for (unsigned int i=0; i<num_results; i++)
   {
     struct TALER_CoinSpendPublicKeyP coin_pub;
     struct TALER_Amount amount_with_fee;
     struct TALER_Amount refund_fee;
-    struct FindRefundContext ictx;
-    enum GNUNET_DB_QueryStatus ires;
-    struct GNUNET_PQ_QueryParam params[] = {
-      GNUNET_PQ_query_param_auto_from_type (&coin_pub),
-      GNUNET_PQ_query_param_end
-    };
     struct GNUNET_PQ_ResultSpec rs[] = {
       GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
                                             &coin_pub),
@@ -1983,9 +2153,6 @@ process_deposits_for_refund_cb (void *cls,
                                    &refund_fee),
       GNUNET_PQ_result_spec_end
     };
-    struct TALER_Amount left;
-    struct TALER_Amount remaining_refund;
-    const struct TALER_Amount *increment;
 
     if (GNUNET_OK !=
         GNUNET_PQ_extract_result (result,
@@ -1997,12 +2164,16 @@ process_deposits_for_refund_cb (void *cls,
       return;
     }
 
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Processing refund for coin %s, deposit value was %s\n",
-                TALER_B2S (&coin_pub),
-                TALER_amount2s (&amount_with_fee));
-    TALER_amount_get_zero (amount_with_fee.currency,
-                           &ictx.refunded_amount);
+    struct FindRefundContext ictx;
+    enum GNUNET_DB_QueryStatus ires;
+    struct GNUNET_PQ_QueryParam params[] = {
+      GNUNET_PQ_query_param_auto_from_type (&coin_pub),
+      GNUNET_PQ_query_param_end
+    };
+
+    GNUNET_assert (GNUNET_OK ==
+                   TALER_amount_get_zero (ctx->refund->currency,
+                                          &ictx.refunded_amount));
     ictx.err = GNUNET_OK; /* no error so far */
     ires = GNUNET_PQ_eval_prepared_multi_select (ctx->pg->conn,
                                                  "find_refunds",
@@ -2011,7 +2182,7 @@ process_deposits_for_refund_cb (void *cls,
                                                  &ictx);
     if ( (GNUNET_OK != ictx.err) ||
          (GNUNET_DB_STATUS_HARD_ERROR == ires) )
-    { 
+    {
       GNUNET_break (0);
       ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
       return;
@@ -2021,39 +2192,49 @@ process_deposits_for_refund_cb (void *cls,
       ctx->qs = GNUNET_DB_STATUS_SOFT_ERROR;
       return;
     }
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Processing refund for coin %s total up to %s\n",
-                TALER_B2S (&coin_pub),
-                TALER_amount2s (&ictx.refunded_amount));
-    
-    /**
-     * Sum coin's contribution for refunding to the total (previously
-     * awarded) refund.  If this value will exceed the current awarded
-     * refund, we'll return #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS.
-     */
+    deposit_refund[i] = ictx.refunded_amount;
+    deposit_amount_with_fee[i] = amount_with_fee;
+    deposit_coin_pubs[i] = coin_pub;
+    deposit_refund_fee[i] = refund_fee;
     if (GNUNET_SYSERR ==
-       TALER_amount_add (&previous_refund,
-                         &previous_refund,
+       TALER_amount_add (&current_refund,
+                         &current_refund,
                          &ictx.refunded_amount))
     {
       GNUNET_break (0);
       ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
       return;
     }
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Existing refund for coin %s is %s\n",
+                TALER_B2S (&coin_pub),
+                TALER_amount2s (&ictx.refunded_amount));
+  }
 
-    if (0 >= TALER_amount_cmp (ctx->refund,
-                              &previous_refund))
-    {
-      /* refund <= refunded_amount; nothing to do! */ 
-      ctx->qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
-      return;
-    }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Total existing refund is %s\n",
+              TALER_amount2s (&current_refund));
+
+  /* stop immediately if we are done */
+  if (0 >= TALER_amount_cmp (ctx->refund,
+                             &current_refund))
+  {
+    ctx->qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
+    return;
+  }
+
+  /* Phase 2:  Try to increase current refund until it matches desired refund 
*/
+
+  for (unsigned int i=0;i<num_results; i++)
+  {
+    const struct TALER_Amount *increment;
+    struct TALER_Amount left;
 
     /* How much of the coin is left after the existing refunds? */
     if (GNUNET_SYSERR ==
-       TALER_amount_subtract (&left, 
-                              &amount_with_fee,
-                              &ictx.refunded_amount))
+       TALER_amount_subtract (&left,
+                              &deposit_amount_with_fee[i],
+                              &deposit_refund[i]))
     {
       GNUNET_break (0);
       ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
@@ -2066,15 +2247,17 @@ process_deposits_for_refund_cb (void *cls,
       /* coin was fully refunded, move to next coin */
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "Coin %s fully refunded, moving to next coin\n",
-                 TALER_B2S (&coin_pub));
+                 TALER_B2S (&deposit_coin_pubs[i]));
       continue;
     }
 
+    struct TALER_Amount remaining_refund;
+
     /* How much of the refund is left? */
     if (GNUNET_SYSERR ==
-       TALER_amount_subtract (&remaining_refund, 
+       TALER_amount_subtract (&remaining_refund,
                               ctx->refund,
-                              &previous_refund))
+                              &current_refund))
     {
       GNUNET_break (0);
       ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
@@ -2092,55 +2275,47 @@ process_deposits_for_refund_cb (void *cls,
     {
       increment = &left;
     }
-    
+
     if (GNUNET_SYSERR ==
-       TALER_amount_add (&previous_refund,
-                         &previous_refund,
+       TALER_amount_add (&current_refund,
+                         &current_refund,
                          increment))
     {
       GNUNET_break (0);
       ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
       return;
     }
-    
-    /* Subtract from refund what has already been awarded */
-    if (GNUNET_SYSERR ==
-       TALER_amount_subtract (&remaining_refund,
-                              ctx->refund,
-                              &ictx.refunded_amount))
-    {
-      GNUNET_break (0);
-      ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
-      return;
-    }
 
     /* actually run the refund */
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "Coin %s deposit amount is %s\n",
+               TALER_B2S (&deposit_coin_pubs[i]),
+               TALER_amount2s (&deposit_amount_with_fee[i]));
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Coin %s refund will be incremented by %s\n",
-               TALER_B2S (&coin_pub),
+               TALER_B2S (&deposit_coin_pubs[i]),
                TALER_amount2s (increment));
     {
       enum GNUNET_DB_QueryStatus qs;
-      
+
       if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
          (qs = insert_refund (ctx->pg,
                               ctx->merchant_pub,
                               ctx->h_contract_terms,
-                              &coin_pub,
+                              &deposit_coin_pubs[i],
                               ctx->reason,
                               increment,
-                              &refund_fee)))
+                              &deposit_refund_fee[i])))
       {
        GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
        ctx->qs = qs;
-       return;    
-      }
-      
-      /* stop immediately if we are done */
-      if (0 == TALER_amount_cmp (ctx->refund,
-                                &previous_refund))
        return;
+      }
     }
+    /* stop immediately if we are done */
+    if (0 == TALER_amount_cmp (ctx->refund,
+                               &current_refund))
+      return;
   }
 
   /**
@@ -2188,6 +2363,10 @@ postgres_increase_refund_for_contract (void *cls,
     GNUNET_PQ_query_param_end
   };
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Asked to refund %s on contract %s\n",
+              TALER_amount2s (refund),
+              GNUNET_h2s (h_contract_terms));
   if (GNUNET_OK !=
       postgres_start (cls))
   {
@@ -2321,6 +2500,7 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
       return NULL;
     }
   }
+  pg->cfg = cfg;
   pg->conn = GNUNET_PQ_connect_with_cfg (cfg,
                                          "merchantdb-postgres");
   if (NULL == pg->conn)
@@ -2350,7 +2530,12 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
   plugin->find_contract_terms_by_date_and_range = 
&postgres_find_contract_terms_by_date_and_range;
   plugin->find_contract_terms_from_hash = 
&postgres_find_contract_terms_from_hash;
   plugin->get_refunds_from_contract_terms_hash = 
&postgres_get_refunds_from_contract_terms_hash;
+  plugin->lookup_wire_fee = &postgres_lookup_wire_fee;
   plugin->increase_refund_for_contract = postgres_increase_refund_for_contract;
+  plugin->mark_proposal_paid = postgres_mark_proposal_paid;
+  plugin->start = postgres_start;
+  plugin->commit = postgres_commit;
+  plugin->rollback = postgres_rollback;
 
   return plugin;
 }
diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c
index 9a12a1b..eb4fe14 100644
--- a/src/backenddb/test_merchantdb.c
+++ b/src/backenddb/test_merchantdb.c
@@ -84,7 +84,7 @@ struct GNUNET_HashCode h_contract_terms;
 /**
  * Proposal's hash.
  */
-struct GNUNET_HashCode h_contract_terms;
+struct GNUNET_HashCode h_contract_terms_future;
 
 /**
  * Time of the transaction.
@@ -363,6 +363,153 @@ proof_cb (void *cls,
 
 
 /**
+ * Test the wire fee storage.
+ *
+ * @return #GNUNET_OK on success
+ */
+static int
+test_wire_fee ()
+{
+  struct TALER_MasterPublicKeyP exchange_pub;
+  struct GNUNET_HashCode h_wire_method;
+  struct GNUNET_TIME_Absolute contract_date;
+  struct TALER_Amount wire_fee1;
+  struct TALER_Amount closing_fee1;
+  struct TALER_Amount wire_fee2;
+  struct TALER_Amount closing_fee2;
+  struct TALER_Amount wire_fee3;
+  struct TALER_Amount closing_fee3;
+  struct GNUNET_TIME_Absolute date1;
+  struct GNUNET_TIME_Absolute date2;
+  struct GNUNET_TIME_Absolute date3;
+  struct GNUNET_TIME_Absolute start_date;
+  struct GNUNET_TIME_Absolute end_date;
+  struct TALER_MasterSignatureP exchange_sig;
+  struct TALER_MasterSignatureP exchange_sig2;
+
+  RND_BLK (&exchange_pub);
+  RND_BLK (&h_wire_method);
+  RND_BLK (&exchange_sig);
+  date1 = GNUNET_TIME_absolute_get ();
+  date2 = GNUNET_TIME_absolute_add (date1,
+                                   GNUNET_TIME_UNIT_DAYS);
+  date3 = GNUNET_TIME_absolute_add (date2,
+                                   GNUNET_TIME_UNIT_DAYS);
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_string_to_amount (CURRENCY ":5",
+                                         &closing_fee1));
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_string_to_amount (CURRENCY ":4",
+                                         &wire_fee1));
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_string_to_amount (CURRENCY ":3",
+                                         &closing_fee2));
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_string_to_amount (CURRENCY ":2",
+                                         &wire_fee2));
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+      plugin->store_wire_fee_by_exchange (plugin->cls,
+                                         &exchange_pub,
+                                         &h_wire_method,
+                                         &wire_fee1,
+                                         &closing_fee1,
+                                         date1,
+                                         date2,
+                                         &exchange_sig))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+      plugin->store_wire_fee_by_exchange (plugin->cls,
+                                         &exchange_pub,
+                                         &h_wire_method,
+                                         &wire_fee2,
+                                         &closing_fee2,
+                                         date2,
+                                         date3,
+                                         &exchange_sig))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  contract_date = date2; /* test inclusive/exclusive range */
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+      plugin->lookup_wire_fee (plugin->cls,
+                              &exchange_pub,
+                              &h_wire_method,
+                              contract_date,
+                              &wire_fee3,
+                              &closing_fee3,
+                              &start_date,
+                              &end_date,
+                              &exchange_sig2))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if ( (start_date.abs_value_us != date2.abs_value_us) ||
+       (end_date.abs_value_us != date3.abs_value_us) ||
+       (0 != memcmp (&exchange_sig,
+                    &exchange_sig2,
+                    sizeof (exchange_sig))) ||
+       (0 != TALER_amount_cmp (&wire_fee2,
+                              &wire_fee3)) ||
+       (0 != TALER_amount_cmp (&closing_fee2,
+                              &closing_fee3)) )
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  contract_date = GNUNET_TIME_absolute_add (date1,
+                                           GNUNET_TIME_UNIT_SECONDS);
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+      plugin->lookup_wire_fee (plugin->cls,
+                              &exchange_pub,
+                              &h_wire_method,
+                              contract_date,
+                              &wire_fee3,
+                              &closing_fee3,
+                              &start_date,
+                              &end_date,
+                              &exchange_sig2))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if ( (start_date.abs_value_us != date1.abs_value_us) ||
+       (end_date.abs_value_us != date2.abs_value_us) ||
+       (0 != memcmp (&exchange_sig,
+                    &exchange_sig2,
+                    sizeof (exchange_sig))) ||
+       (0 != TALER_amount_cmp (&wire_fee1,
+                              &wire_fee3)) ||
+       (0 != TALER_amount_cmp (&closing_fee1,
+                              &closing_fee3)) )
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  contract_date = date3; /* outside of valid range! */
+  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
+      plugin->lookup_wire_fee (plugin->cls,
+                              &exchange_pub,
+                              &h_wire_method,
+                              contract_date,
+                              &wire_fee3,
+                              &closing_fee3,
+                              &start_date,
+                              &end_date,
+                              &exchange_sig2))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
  * Main function that will be run by the scheduler.
  *
  * @param cls closure with config
@@ -445,15 +592,16 @@ run (void *cls)
                  json_object_set_new (contract_terms,
                                       "order",
                                       json_string ("1")));
-  
+
   contract_terms_future = json_object ();
   GNUNET_assert (0 ==
                  json_object_set_new (contract_terms_future,
                                       "order",
                                       json_string ("2")));
 
-  TALER_JSON_hash (contract_terms,
-                   &h_contract_terms);
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_JSON_hash (contract_terms,
+                                  &h_contract_terms));
 
   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->insert_contract_terms (plugin->cls,
@@ -462,6 +610,11 @@ run (void *cls)
                                         timestamp,
                                         contract_terms));
 
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+          plugin->mark_proposal_paid (plugin->cls,
+                                      &h_contract_terms,
+                                      &merchant_pub));
+
   json_t *out;
 
   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
@@ -503,6 +656,14 @@ run (void *cls)
 
   fake_now = GNUNET_TIME_absolute_subtract (timestamp, delta);
 
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_JSON_hash (contract_terms_future,
+                                  &h_contract_terms_future));
+
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+          plugin->mark_proposal_paid (plugin->cls,
+                                      &h_contract_terms_future,
+                                      &merchant_pub));
   FAILIF (2 !=
           plugin->find_contract_terms_by_date_and_range (plugin->cls,
                                                         fake_now,
@@ -600,7 +761,7 @@ run (void *cls)
                                                 &merchant_pub,
                                                 &refund_amount,
                                                 "same refund amount as "
-                                                "the previous one, should 
fail"));
+                                                "the previous one, should 
succeed without changes (0)"));
 
   /*Should fail as this refund a lesser amount respect to the previous one*/
   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
@@ -608,7 +769,7 @@ run (void *cls)
                                                 &h_contract_terms,
                                                 &merchant_pub,
                                                 &little_refund_amount,
-                                                "make refund testing fail"));
+                                                "lower refund amount as the 
previous one, should succeed without changes (0)"));
   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->increase_refund_for_contract (plugin->cls,
                                                 &h_contract_terms,
@@ -616,7 +777,7 @@ run (void *cls)
                                                 &right_second_refund_amount,
                                                 "right refund increase"));
 
-  FAILIF (GNUNET_DB_STATUS_HARD_ERROR != 
+  FAILIF (GNUNET_DB_STATUS_HARD_ERROR !=
           plugin->increase_refund_for_contract (plugin->cls,
                                                 &h_contract_terms,
                                                 &merchant_pub,
@@ -624,6 +785,9 @@ run (void *cls)
                                                 "make refund testing fail due"
                                                 " to too big refund amount"));
 
+  FAILIF (GNUNET_OK !=
+         test_wire_fee ());
+
   if (-1 == result)
     result = 0;
 
diff --git a/src/include/taler_merchant_service.h 
b/src/include/taler_merchant_service.h
index 8a2343a..ab31701 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014, 2015, 2016 INRIA
+  Copyright (C) 2014-2017 INRIA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Affero General Public License as published by the Free 
Software
@@ -30,23 +30,11 @@
 
 /* ********************* /refund ************************** */
 
-struct TALER_MERCHANT_RefundIncreaseOperation;
-
-struct TALER_MERCHANT_RefundLookupOperation;
-
 /**
- * Callback to process a POST /refund request
- *
- * @param cls closure
- * @param http_status HTTP status code for this request
- * @param ec taler-specific error code
- * @param obj the response body
+ * Handle for a GET /refund operation.
  */
-typedef void
-(*TALER_MERCHANT_RefundIncreaseCallback) (void *cls,
-                                          unsigned int http_status,
-                                          enum TALER_ErrorCode ec,
-                                          const json_t *obj);
+struct TALER_MERCHANT_RefundLookupOperation;
+
 
 /**
  * Callback to process a GET /refund request
@@ -58,9 +46,9 @@ typedef void
  */
 typedef void
 (*TALER_MERCHANT_RefundLookupCallback) (void *cls,
-                                                 unsigned int http_status,
-                                                 enum TALER_ErrorCode ec,
-                                                 const json_t *obj);
+                                       unsigned int http_status,
+                                       enum TALER_ErrorCode ec,
+                                       const json_t *obj);
 
 /**
  * Does a GET /refund.
@@ -81,6 +69,36 @@ TALER_MERCHANT_refund_lookup (struct GNUNET_CURL_Context 
*ctx,
                               void *cb_cls);
 
 /**
+ * Cancel a GET /refund request.
+ *
+ * @param rlo the refund increasing operation to cancel
+ */
+void
+TALER_MERCHANT_refund_lookup_cancel (struct 
TALER_MERCHANT_RefundLookupOperation *rlo);
+
+
+/**
+ * Handle for a POST /refund operation.
+ */
+struct TALER_MERCHANT_RefundIncreaseOperation;
+
+
+/**
+ * Callback to process a POST /refund request
+ *
+ * @param cls closure
+ * @param http_status HTTP status code for this request
+ * @param ec taler-specific error code
+ * @param obj the response body
+ */
+typedef void
+(*TALER_MERCHANT_RefundIncreaseCallback) (void *cls,
+                                          unsigned int http_status,
+                                          enum TALER_ErrorCode ec,
+                                          const json_t *obj);
+
+
+/**
  * Increase the refund associated to a order
  *
  * @param ctx the CURL context used to connect to the backend
@@ -110,13 +128,6 @@ TALER_MERCHANT_refund_increase (struct GNUNET_CURL_Context 
*ctx,
 void
 TALER_MERCHANT_refund_increase_cancel (struct 
TALER_MERCHANT_RefundIncreaseOperation *rio);
 
-/**
- * Cancel a GET /refund request.
- *
- * @param rlo the refund increasing operation to cancel
- */
-void
-TALER_MERCHANT_refund_lookup_cancel (struct 
TALER_MERCHANT_RefundLookupOperation *rlo);
 
 /* *********************  /proposal *********************** */
 
@@ -127,11 +138,6 @@ TALER_MERCHANT_refund_lookup_cancel (struct 
TALER_MERCHANT_RefundLookupOperation
 struct TALER_MERCHANT_ProposalOperation;
 
 /**
- * Handle to a GET /proposal operation
- */
-struct TALER_MERCHANT_ProposalLookupOperation;
-
-/**
  * Callbacks of this type are used to serve the result of submitting a
  * /contract request to a merchant.
  *
@@ -155,19 +161,6 @@ typedef void
 
 
 /**
- * Callback called to work a GET /proposal response.
- *
- * @param cls closure
- * @param http_status HTTP status code of the request
- * @param body JSON containing the response's payload.
- * In case of errors, it contains the appropriate error encoding.
- */
-typedef void
-(*TALER_MERCHANT_ProposalLookupOperationCallback) (void *cls,
-                                                   unsigned int http_status,
-                                                   const json_t *body);
-
-/**
  * PUT an order to the backend and receives the related proposal.
  *
  * @param ctx execution context
@@ -197,6 +190,26 @@ TALER_MERCHANT_proposal_cancel (struct 
TALER_MERCHANT_ProposalOperation *po);
 
 
 /**
+ * Handle to a GET /proposal operation
+ */
+struct TALER_MERCHANT_ProposalLookupOperation;
+
+
+/**
+ * Callback called to work a GET /proposal response.
+ *
+ * @param cls closure
+ * @param http_status HTTP status code of the request
+ * @param body JSON containing the response's payload.
+ * In case of errors, it contains the appropriate error encoding.
+ */
+typedef void
+(*TALER_MERCHANT_ProposalLookupOperationCallback) (void *cls,
+                                                   unsigned int http_status,
+                                                   const json_t *body);
+
+
+/**
  * Calls the GET /proposal API at the backend.  That is,
  * retrieve a proposal data by providing its transaction id.
  *
@@ -295,6 +308,11 @@ struct TALER_MERCHANT_PayCoin
    * Amount this coin is to contribute (without fee).
    */
   struct TALER_Amount amount_without_fee;
+
+  /**
+   * Next coin used to pay
+   */
+  struct TALER_MERCHANT_PayCoin *next;
 };
 
 
@@ -451,7 +469,8 @@ struct TALER_MERCHANT_TrackTransferHandle;
  * by the exchange for a given h_contract_terms, by _one_ wire
  * transfer.
  */
-struct TALER_MERCHANT_TrackTransferDetails {
+struct TALER_MERCHANT_TrackTransferDetails
+{
 
   /**
    * Total amount paid back by the exchange.
@@ -496,12 +515,14 @@ typedef void
                                          unsigned int details_length,
                                          const struct 
TALER_MERCHANT_TrackTransferDetails *details);
 
+
 /**
  * Request backend to return deposits associated with a given wtid.
  *
  * @param ctx execution context
  * @param backend_uri base URI of the backend
  * @param instance which merchant instance is going to be tracked
+ * @param wire_method wire method used for the wire transfer
  * @param wtid base32 string indicating a wtid
  * @param exchange base URL of the exchange in charge of returning the wanted 
information
  * @param track_transfer_cb the callback to call when a reply for this request 
is available
@@ -512,6 +533,7 @@ struct TALER_MERCHANT_TrackTransferHandle *
 TALER_MERCHANT_track_transfer (struct GNUNET_CURL_Context *ctx,
                                const char *backend_uri,
                                const char *instance,
+                              const char *wire_method,
                                const struct TALER_WireTransferIdentifierRawP 
*wtid,
                                const char *exchange_uri,
                                TALER_MERCHANT_TrackTransferCallback 
track_transfer_cb,
diff --git a/src/include/taler_merchantdb_plugin.h 
b/src/include/taler_merchantdb_plugin.h
index efb03cb..a5e91f5 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -196,10 +196,23 @@ struct TALER_MERCHANTDB_Plugin
    */
   enum GNUNET_DB_QueryStatus
   (*insert_contract_terms) (void *cls,
-                           const char *order_id,
-                           const struct TALER_MerchantPublicKeyP *merchant_pub,
-                           struct GNUNET_TIME_Absolute timestamp,
-                           const json_t *contract_terms);
+                            const char *order_id,
+                            const struct TALER_MerchantPublicKeyP 
*merchant_pub,
+                            struct GNUNET_TIME_Absolute timestamp,
+                            const json_t *contract_terms);
+
+  /**
+   * Mark contract terms as payed.  Needed by /history as only payed
+   * contracts must be shown.  NOTE: we can't get the list of (payed)
+   * contracts from the transactions table because it lacks contract_terms
+   * plain JSON.  In facts, the protocol doesn't allow to store contract_terms
+   * in transactions table, as /pay handler doesn't receive this data
+   * (only /proposal does).
+   */
+  enum GNUNET_DB_QueryStatus
+  (*mark_proposal_paid) (void *cls,
+                         const struct GNUNET_HashCode *h_contract_terms,
+                         const struct TALER_MerchantPublicKeyP *merchant_pub);
 
   /**
    * Retrieve proposal data given its order ID.
@@ -395,7 +408,7 @@ struct TALER_MERCHANTDB_Plugin
    * including signature (so we have proof).
    *
    * @param cls closure
-   * @paramm exchange_pub public key of the exchange
+   * @param exchange_pub public key of the exchange
    * @param h_wire_method hash of wire method
    * @param wire_fee wire fee charged
    * @param closing_fee closing fee charged (irrelevant for us,
@@ -542,8 +555,36 @@ struct TALER_MERCHANTDB_Plugin
                          const struct TALER_WireTransferIdentifierRawP *wtid,
                          TALER_MERCHANTDB_ProofCallback cb,
                          void *cb_cls);
+  
 
+  /**
+   * Obtain information about wire fees charged by an exchange,
+   * including signature (so we have proof).
+   *
+   * @param cls closure
+   * @param exchange_pub public key of the exchange
+   * @param h_wire_method hash of wire method
+   * @param contract_date date of the contract to use for the lookup
+   * @param[out] wire_fee wire fee charged
+   * @param[out] closing_fee closing fee charged (irrelevant for us,
+   *              but needed to check signature)
+   * @param[out] start_date start of fee being used
+   * @param[out] end_date end of fee being used
+   * @param[out] exchange_sig signature of exchange over fee structure
+   * @return transaction status code
+   */
+  enum GNUNET_DB_QueryStatus
+  (*lookup_wire_fee) (void *cls,
+                     const struct TALER_MasterPublicKeyP *exchange_pub,
+                     const struct GNUNET_HashCode *h_wire_method,
+                     struct GNUNET_TIME_Absolute contract_date,
+                     struct TALER_Amount *wire_fee,
+                     struct TALER_Amount *closing_fee,
+                     struct GNUNET_TIME_Absolute *start_date,
+                     struct GNUNET_TIME_Absolute *end_date,
+                     struct TALER_MasterSignatureP *exchange_sig);
 
+  
   /**
    * Function called when some backoffice staff decides to award or
    * increase the refund on an existing contract.
@@ -581,6 +622,36 @@ struct TALER_MERCHANTDB_Plugin
                                           const struct GNUNET_HashCode 
*h_contract_terms,
                                           TALER_MERCHANTDB_RefundCallback rc,
                                           void *rc_cls);
+
+  /**
+   * Roll back the current transaction of a database connection.
+   *
+   * @param cls the `struct PostgresClosure` with the plugin-specific state
+   * @return #GNUNET_OK on success
+   */
+  void
+  (*rollback) (void *cls);
+
+
+  /**
+   * Start a transaction.
+   *
+   * @param cls the `struct PostgresClosure` with the plugin-specific state
+   * @return #GNUNET_OK on success
+   */
+  int
+  (*start) (void *cls);
+
+
+  /**
+   * Commit the current transaction of a database connection.
+   *
+   * @param cls the `struct PostgresClosure` with the plugin-specific state
+   * @return transaction status code
+   */
+  enum GNUNET_DB_QueryStatus
+  (*commit) (void *cls);
+
 };
 
 #endif
diff --git a/src/lib/merchant_api_pay.c b/src/lib/merchant_api_pay.c
index e65ecb4..a480061 100644
--- a/src/lib/merchant_api_pay.c
+++ b/src/lib/merchant_api_pay.c
@@ -401,7 +401,6 @@ TALER_MERCHANT_pay_frontend (struct GNUNET_CURL_Context 
*ctx,
   CURL *eh;
   struct TALER_Amount total_fee;
   struct TALER_Amount total_amount;
-  unsigned int i;
 
   if (0 == num_coins)
   {
@@ -409,7 +408,7 @@ TALER_MERCHANT_pay_frontend (struct GNUNET_CURL_Context 
*ctx,
     return NULL;
   }
   j_coins = json_array ();
-  for (i=0;i<num_coins;i++)
+  for (unsigned int i=0;i<num_coins;i++)
   {
     json_t *j_coin;
     const struct TALER_MERCHANT_PaidCoin *pc = &coins[i];
@@ -459,9 +458,14 @@ TALER_MERCHANT_pay_frontend (struct GNUNET_CURL_Context 
*ctx,
                        "ub_sig", GNUNET_JSON_from_rsa_signature 
(pc->denom_sig.rsa_signature),
                        "coin_sig", GNUNET_JSON_from_data_auto (&pc->coin_sig)
                        );
-    GNUNET_assert (0 ==
-                   json_array_append_new (j_coins,
-                                          j_coin));
+    if (0 !=
+        json_array_append_new (j_coins,
+                               j_coin))
+    {
+      GNUNET_break (0);
+      json_decref (j_coins);
+      return NULL;
+    }
   }
 
   pay_obj = json_pack ("{"
@@ -474,7 +478,11 @@ TALER_MERCHANT_pay_frontend (struct GNUNET_CURL_Context 
*ctx,
                       "coins", j_coins,
                        "order_id", order_id,
                        "merchant_pub", GNUNET_JSON_from_data_auto 
(merchant_pub));
-
+  if (NULL == pay_obj)
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
   ph = GNUNET_new (struct TALER_MERCHANT_Pay);
   ph->ctx = ctx;
   ph->cb = pay_cb;
diff --git a/src/lib/merchant_api_track_transfer.c 
b/src/lib/merchant_api_track_transfer.c
index f0b6590..660d4e1 100644
--- a/src/lib/merchant_api_track_transfer.c
+++ b/src/lib/merchant_api_track_transfer.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014, 2015, 2016 GNUnet e.V. and INRIA
+  Copyright (C) 2014-2017 GNUnet e.V. and INRIA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Lesser General Public License as published by the Free 
Software
@@ -112,9 +112,8 @@ check_track_transfer_response_ok (struct 
TALER_MERCHANT_TrackTransferHandle *wdh
   num_details = json_array_size (deposits);
   {
     struct TALER_MERCHANT_TrackTransferDetails details[num_details];
-    unsigned int i;
 
-    for (i=0;i<num_details;i++)
+    for (unsigned int i=0;i<num_details;i++)
     {
       struct TALER_MERCHANT_TrackTransferDetails *detail = &details[i];
       json_t *deposit = json_array_get (deposits, i);
@@ -217,6 +216,7 @@ handle_track_transfer_finished (void *cls,
  * @param ctx execution context
  * @param backend_uri base URI of the backend
  * @param instance which merchant instance is going to be tracked
+ * @param wire_method wire method used for the wire transfer
  * @param wtid base32 string indicating a wtid
  * @param exchange_uri base URL of the exchange in charge of returning the 
wanted information
  * @param track_transfer_cb the callback to call when a reply for this request 
is available
@@ -227,6 +227,7 @@ struct TALER_MERCHANT_TrackTransferHandle *
 TALER_MERCHANT_track_transfer (struct GNUNET_CURL_Context *ctx,
                                const char *backend_uri,
                                const char *instance,
+                              const char *wire_method,
                                const struct TALER_WireTransferIdentifierRawP 
*wtid,
                                const char *exchange_uri,
                                TALER_MERCHANT_TrackTransferCallback 
track_transfer_cb,
@@ -247,11 +248,12 @@ TALER_MERCHANT_track_transfer (struct GNUNET_CURL_Context 
*ctx,
   base = MAH_path_to_url_ (backend_uri,
                           "/track/transfer");
   GNUNET_asprintf (&tdo->url,
-                   "%s?wtid=%s&exchange=%s&instance=%s",
+                   "%s?wtid=%s&exchange=%s&instance=%s&wire_method=%s",
                    base,
                    wtid_str,
                    exchange_uri,
-                  instance);
+                  instance,
+                  wire_method);
   GNUNET_free (base);
   GNUNET_free (wtid_str);
   eh = curl_easy_init ();
diff --git a/src/lib/test_merchant_api.c b/src/lib/test_merchant_api.c
index f7fe943..dbc2d5c 100644
--- a/src/lib/test_merchant_api.c
+++ b/src/lib/test_merchant_api.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014, 2015, 2016 GNUnet e.V. and INRIA
+  Copyright (C) 2014-2017 GNUnet e.V. and INRIA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Lesser General Public License as published by the Free 
Software
@@ -26,7 +26,6 @@
 #include <taler/taler_util.h>
 #include <taler/taler_signatures.h>
 #include "taler_merchant_service.h"
-#include "taler-merchant-httpd_refund.h"
 #include "taler_merchantdb_lib.h"
 #include <gnunet/gnunet_util_lib.h>
 #include <gnunet/gnunet_curl_lib.h>
@@ -64,7 +63,7 @@
 /**
  * Handle to database.
  */
-struct TALER_MERCHANTDB_Plugin *db;
+static struct TALER_MERCHANTDB_Plugin *db;
 
 /**
  * Configuration handle.
@@ -89,7 +88,7 @@ static char **instances;
 /**
  * How many merchant instances this test runs
  */
-unsigned int ninstances = 0;
+static unsigned int ninstances = 0;
 
 /**
  * Current instance
@@ -99,12 +98,12 @@ static char *instance;
 /**
  * Current instance key
  */
-struct GNUNET_CRYPTO_EddsaPrivateKey *instance_priv;
+static struct GNUNET_CRYPTO_EddsaPrivateKey *instance_priv;
 
 /**
  * Current instance being tested
  */
-unsigned int instance_idx = 0;
+static unsigned int instance_idx = 0;
 
 /**
  * Task run on timeout.
@@ -206,7 +205,7 @@ enum OpCode
   /**
    * Test refund lookup
    */
-  OC_REFUND_LOOKUP 
+  OC_REFUND_LOOKUP
 
 };
 
@@ -312,7 +311,7 @@ struct Command
       /**
        * Transfer details (JSON)
        */
-       const char *transfer_details;
+      const char *transfer_details;
 
       /**
        * Set (by the interpreter) to the reserve's private key
@@ -464,16 +463,10 @@ struct Command
       const char *contract_ref;
 
       /**
-       * Reference to a reserve_withdraw operation for a coin to
-       * be used for the /deposit operation.
+       * ";"-separated list of references to withdrawn coins to be used
+       * in the payment.
        */
-      const char *coin_ref;
-
-      /**
-       * If this @e coin_ref refers to an operation that generated
-       * an array of coins, this value determines which coin to use.
-       */
-      unsigned int coin_idx;
+      char *coin_ref;
 
       /**
        * Amount to pay (from the coin, including fee).
@@ -593,6 +586,7 @@ struct Command
     } track_transaction;
 
     struct {
+
       /**
        * Date we want retrieved transactions younger than
        */
@@ -604,10 +598,6 @@ struct Command
       unsigned int nresult;
 
       /**
-       * Handle to the merchant
-       */
-
-      /**
        * Handle to /history request
        */
       struct TALER_MERCHANT_HistoryOperation *ho;
@@ -640,7 +630,7 @@ struct Command
        * Amount to refund
        */
       const char *refund_amount;
-      
+
       /**
        * Reason for refunding
        */
@@ -737,22 +727,22 @@ get_instance_priv (struct GNUNET_CONFIGURATION_Handle 
*config,
   char *config_section;
   char *filename;
   struct GNUNET_CRYPTO_EddsaPrivateKey *ret;
-  
+
   (void) GNUNET_asprintf (&config_section,
-                          "merchant-instance-%s",
-                          instance);
+                      "merchant-instance-%s",
+                      instance);
 
   if (GNUNET_OK !=
-        GNUNET_CONFIGURATION_get_value_filename (config,
-                                                 config_section,
-                                                 "KEYFILE",
-                                                 &filename))
+    GNUNET_CONFIGURATION_get_value_filename (config,
+                                             config_section,
+                                             "KEYFILE",
+                                             &filename))
   {
     GNUNET_break (0);
     return NULL;
   }
   if (NULL ==
-       (ret = GNUNET_CRYPTO_eddsa_key_create_from_file (filename)))
+   (ret = GNUNET_CRYPTO_eddsa_key_create_from_file (filename)))
     GNUNET_break (0);
 
   return ret;
@@ -767,9 +757,9 @@ static void
 fail (struct InterpreterState *is)
 {
   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-              "Interpreter failed at step %s (#%u)\n",
-              is->commands[is->ip].label,
-              is->ip);
+          "Interpreter failed at step %s (#%u)\n",
+          is->commands[is->ip].label,
+          is->ip);
   result = GNUNET_SYSERR;
   GNUNET_SCHEDULER_shutdown ();
 }
@@ -786,7 +776,6 @@ static const struct Command *
 find_command (const struct InterpreterState *is,
               const char *label)
 {
-  unsigned int i;
   const struct Command *cmd;
 
   if (NULL == label)
@@ -795,14 +784,16 @@ find_command (const struct InterpreterState *is,
                 "Attempt to lookup command for empty label\n");
     return NULL;
   }
-  for (i=0;OC_END != (cmd = &is->commands[i])->oc;i++)
+  for (unsigned int i=0;
+       OC_END != (cmd = &is->commands[i])->oc;
+       i++)
     if ( (NULL != cmd->label) &&
-         (0 == strcmp (cmd->label,
-                       label)) )
+       (0 == strcmp (cmd->label,
+                     label)) )
       return cmd;
   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-              "Command not found: %s\n",
-              label);
+          "Command not found: %s\n",
+          label);
   return NULL;
 }
 
@@ -919,10 +910,10 @@ compare_admin_add_incoming_history (const struct 
TALER_EXCHANGE_ReserveHistory *
     return GNUNET_SYSERR;
   }
   GNUNET_assert (GNUNET_OK ==
-                 TALER_string_to_amount 
(cmd->details.admin_add_incoming.amount,
-                                         &amount));
+    TALER_string_to_amount (cmd->details.admin_add_incoming.amount,
+                            &amount));
   if (0 != TALER_amount_cmp (&amount,
-                             &h->amount))
+                         &h->amount))
   {
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
@@ -952,14 +943,14 @@ compare_reserve_withdraw_history (const struct 
TALER_EXCHANGE_ReserveHistory *h,
     return GNUNET_SYSERR;
   }
   GNUNET_assert (GNUNET_OK ==
-                 TALER_string_to_amount (cmd->details.reserve_withdraw.amount,
-                                         &amount));
+    TALER_string_to_amount (cmd->details.reserve_withdraw.amount,
+                            &amount));
   GNUNET_assert (GNUNET_OK ==
-                 TALER_amount_add (&amount_with_fee,
-                                   &amount,
-                                   
&cmd->details.reserve_withdraw.pk->fee_withdraw));
+    TALER_amount_add (&amount_with_fee,
+                      &amount,
+                      &cmd->details.reserve_withdraw.pk->fee_withdraw));
   if (0 != TALER_amount_cmp (&amount_with_fee,
-                             &h->amount))
+      &h->amount))
   {
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
@@ -991,7 +982,6 @@ reserve_status_cb (void *cls,
   struct InterpreterState *is = cls;
   struct Command *cmd = &is->commands[is->ip];
   struct Command *rel;
-  unsigned int i;
   unsigned int j;
   struct TALER_Amount amount;
 
@@ -1011,21 +1001,29 @@ reserve_status_cb (void *cls,
   {
   case MHD_HTTP_OK:
     j = 0;
-    for (i=0;i<is->ip;i++)
+    for (unsigned int i=0;i<is->ip;i++)
     {
       switch ((rel = &is->commands[i])->oc)
       {
       case OC_ADMIN_ADD_INCOMING:
+        /**
+         * If the command being iterated over filled a reserve AND
+         * it is the one referenced by the current "history command"
+         * ...
+         */
         if ( ( (NULL != rel->label) &&
-               (0 == strcmp (cmd->details.reserve_status.reserve_reference,
-                             rel->label) ) ) ||
-             ( (NULL != rel->details.admin_add_incoming.reserve_reference) &&
-               (0 == strcmp (cmd->details.reserve_status.reserve_reference,
-                             
rel->details.admin_add_incoming.reserve_reference) ) ) )
+             (0 == strcmp (cmd->details.reserve_status.reserve_reference,
+                           rel->label) ) ) ||
+           ( (NULL != rel->details.admin_add_incoming.reserve_reference) &&
+             (0 == strcmp (cmd->details.reserve_status.reserve_reference,
+                         rel->details.admin_add_incoming.reserve_reference) ) 
) )
         {
-          if (GNUNET_OK !=
-              compare_admin_add_incoming_history (&history[j],
-                                                  rel))
+          /**
+           * ... then make sure the history element mentions a "deposit
+           * operation" on that reserve.
+           */
+          if (GNUNET_OK != compare_admin_add_incoming_history (&history[j],
+                                                               rel))
           {
             GNUNET_break (0);
             fail (is);
@@ -1035,12 +1033,20 @@ reserve_status_cb (void *cls,
         }
         break;
       case OC_WITHDRAW_SIGN:
+        /**
+         * If the command being iterated over emptied a reserve AND
+         * it is the one referenced by the current "history command"
+         * ...
+         */
         if (0 == strcmp (cmd->details.reserve_status.reserve_reference,
                          rel->details.reserve_withdraw.reserve_reference))
         {
-          if (GNUNET_OK !=
-              compare_reserve_withdraw_history (&history[j],
-                                             rel))
+          /**
+           * ... then make sure the history element mentions a "withdraw
+           * operation" on that reserve.
+           */
+          if (GNUNET_OK != compare_reserve_withdraw_history (&history[j],
+                                                             rel))
           {
             GNUNET_break (0);
             fail (is);
@@ -1050,7 +1056,7 @@ reserve_status_cb (void *cls,
         }
         break;
       default:
-        /* unreleated, just skip */
+      /* unreleated, just skip */
         break;
       }
     }
@@ -1110,8 +1116,6 @@ reserve_withdraw_cb (void *cls,
                 "Unexpected response code %u to command %s\n",
                 http_status,
                 cmd->label);
-    json_dumpf (full_response, stderr, 0);
-    GNUNET_break (0);
     fail (is);
     return;
   }
@@ -1124,6 +1128,10 @@ reserve_withdraw_cb (void *cls,
       fail (is);
       return;
     }
+    /**
+     * NOTE: this assert is OK on the second instance run because the
+     * interpreter is "cleaned" by cleanup_state()
+     */
     GNUNET_assert (NULL == cmd->details.reserve_withdraw.sig.rsa_signature);
     cmd->details.reserve_withdraw.sig.rsa_signature
       = GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature);
@@ -1141,7 +1149,7 @@ reserve_withdraw_cb (void *cls,
 
 
 /**
- * Callback that works PUT /proposal's output.
+ * Callback that works POST /proposal's output.
  *
  * @param cls closure
  * @param http_status HTTP response code, 200 indicates success;
@@ -1174,16 +1182,14 @@ proposal_cb (void *cls,
     cmd->details.proposal.merchant_sig = *sig;
     cmd->details.proposal.hash = *hash;
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Hashed proposal, '%s'\n",
+                "Hashed proposal is `%s'\n",
                 GNUNET_h2s (hash));
     break;
   default:
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "unexpected status code from /proposal: %u. Step %u\n",
+                "Unexpected status code from /proposal: %u. Step %u\n",
                 http_status,
                 is->ip);
-    json_dumpf (obj, stderr, 0);
-    GNUNET_break (0);
     fail (is);
     return;
   }
@@ -1208,10 +1214,6 @@ refund_increase_cb (void *cls,
   struct InterpreterState *is = cls;
   struct Command *cmd = &is->commands[is->ip];
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "/refund (increase) response object: %s\n",
-              json_dumps (obj, JSON_INDENT (2)));
-
   if (MHD_HTTP_OK != http_status)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -1223,8 +1225,28 @@ refund_increase_cb (void *cls,
   next_command (is);
 }
 
+
 /**
- * Process GET /refund (increase) response. 
+ * Callback that frees all the elements in the hashmap
+ *
+ * @param cls closure, NULL
+ * @param key current key
+ * @param value a `struct TALER_Amount`
+ */
+static int
+hashmap_free (void *cls,
+              const struct GNUNET_HashCode *key,
+              void *value)
+{
+  struct TALER_Amount *refund_amount = value;
+
+  GNUNET_free (refund_amount);
+  return GNUNET_YES;
+}
+
+
+/**
+ * Process GET /refund (increase) response.
  *
  * @param cls closure
  * @param http_status HTTP status code
@@ -1237,21 +1259,27 @@ refund_lookup_cb (void *cls,
                   enum TALER_ErrorCode ec,
                   const json_t *obj)
 {
+  struct GNUNET_CONTAINER_MultiHashMap *map;
   struct InterpreterState *is = cls;
   struct Command *cmd = &is->commands[is->ip];
-  const struct Command *pay_ref;
-  const struct Command *increase_ref;
-  const struct Command *coin_ref;
+  size_t index;
+  json_t *elem;
+  const char *error_name;
+  unsigned int error_line;
+  struct GNUNET_HashCode h_coin_pub;
+  char *icoin_ref;
+  char *icoin_refs;
+  const struct Command *icoin;
+  const struct Command *pay;
+  struct TALER_CoinSpendPublicKeyP icoin_pub;
+  struct GNUNET_HashCode h_icoin_pub;
+  struct TALER_Amount *iamount;
+  struct TALER_Amount acc;
+  const struct Command *increase;
   struct TALER_Amount refund_amount;
-  struct TALER_Amount refund_fee;
-  struct TALER_Amount coin_amount;
-  struct TALER_CoinSpendPublicKeyP coin_pub;
-  struct TALER_MerchantPublicKeyP merchant_pub;
-  struct json_t *resp_element;
-  struct json_t *mock_element;
-  struct TALER_RefundRequestPS rr;
-  struct GNUNET_CRYPTO_EddsaSignature sig;
+  const json_t *arr;
 
+  cmd->details.refund_lookup.rlo = NULL;
   if (MHD_HTTP_OK != http_status)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -1260,73 +1288,93 @@ refund_lookup_cb (void *cls,
     return;
   }
 
-  increase_ref = find_command (is, cmd->details.refund_lookup.increase_ref);
-  GNUNET_assert (NULL != increase_ref);
+  map = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
+  arr = json_object_get (obj,
+                         "refund_permissions");
+  if (NULL == arr)
+  {
+    GNUNET_break (0);
+    fail (is);
+    return;
+  }
+  json_array_foreach (arr, index, elem)
+  {
+    struct TALER_CoinSpendPublicKeyP coin_pub;
+    struct TALER_Amount *irefund_amount
+      = GNUNET_new (struct TALER_Amount);
+    struct GNUNET_JSON_Specification spec[] = {
+      GNUNET_JSON_spec_fixed_auto ("coin_pub", &coin_pub),
+      TALER_JSON_spec_amount ("refund_amount", irefund_amount),
+      GNUNET_JSON_spec_end ()
+    };
 
-  GNUNET_assert (GNUNET_OK ==
-    TALER_string_to_amount 
(increase_ref->details.refund_increase.refund_amount,
-                            &refund_amount));
-  GNUNET_assert (GNUNET_OK ==
-    TALER_string_to_amount (increase_ref->details.refund_increase.refund_fee,
-                            &refund_fee));
+    GNUNET_assert (GNUNET_OK ==
+                  GNUNET_JSON_parse (elem,
+                                     spec,
+                                     &error_name,
+                                     &error_line));
+    GNUNET_CRYPTO_hash (&coin_pub,
+                       sizeof (struct TALER_CoinSpendPublicKeyP),
+                       &h_coin_pub);
+    GNUNET_assert (GNUNET_OK ==
+                  GNUNET_CONTAINER_multihashmap_put (map,
+                                                     &h_coin_pub,
+                                                     irefund_amount,
+                                                     
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+  };
 
-  pay_ref = find_command (is, cmd->details.refund_lookup.pay_ref);
-  GNUNET_assert (NULL != pay_ref);
+  /* Retrieve coins used to pay, from #OC_PAY command */
+  GNUNET_assert (NULL != (pay =
+                         find_command (is,
+                                       cmd->details.refund_lookup.pay_ref)));
+  icoin_refs = GNUNET_strdup (pay->details.pay.coin_ref);
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_amount_get_zero ("EUR",
+                                        &acc));
+  for (icoin_ref = strtok (icoin_refs, ";");
+       NULL != icoin_ref;
+       icoin_ref = strtok (NULL, ";"))
+  {
+    GNUNET_assert (NULL != (icoin =
+                           find_command (is,
+                                         icoin_ref)));
+    GNUNET_CRYPTO_eddsa_key_get_public 
(&icoin->details.reserve_withdraw.coin_priv.eddsa_priv,
+                                        &icoin_pub.eddsa_pub);
+    GNUNET_CRYPTO_hash (&icoin_pub,
+                        sizeof (struct TALER_CoinSpendPublicKeyP),
+                        &h_icoin_pub);
+    /* Can be NULL: not all coins are involved in refund */
+    iamount = GNUNET_CONTAINER_multihashmap_get (map,
+                                                &h_icoin_pub);
+    if (NULL == iamount)
+      continue;
+    GNUNET_assert (GNUNET_OK ==
+                   TALER_amount_add (&acc,
+                                     &acc,
+                                     iamount));
+  }
 
+  /* Check if refund has been 100% covered */
+  GNUNET_assert (increase =
+                 find_command (is,
+                               cmd->details.refund_lookup.increase_ref));
   GNUNET_assert (GNUNET_OK ==
-    TALER_string_to_amount (pay_ref->details.pay.amount_without_fee,
-                            &coin_amount));
-
-  /* Get coin pub */
-  coin_ref = find_command (is, pay_ref->details.pay.coin_ref);
-  GNUNET_assert (NULL != coin_ref);
- 
-  GNUNET_CRYPTO_eddsa_key_get_public 
(&coin_ref->details.reserve_withdraw.coin_priv.eddsa_priv,
-                                      &coin_pub.eddsa_pub);
-
-  GNUNET_assert (NULL != (resp_element = json_array_get (obj, 0)));
-  
-  GNUNET_CRYPTO_eddsa_key_get_public (instance_priv,
-                                      &merchant_pub.eddsa_pub);
-
-  rr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND);
-  rr.purpose.size = htonl (sizeof (struct TALER_RefundRequestPS));
-
-  rr.h_contract_terms = pay_ref->details.pay.h_contract_terms;
-  rr.coin_pub = coin_pub;
-  rr.merchant = merchant_pub;
-  rr.rtransaction_id = GNUNET_htonll (instance_idx + 1);
-  TALER_amount_hton (&rr.refund_amount,
-                     &refund_amount);
-  TALER_amount_hton (&rr.refund_fee,
-                     &refund_fee);
-
-  GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (instance_priv,
-                                                        &rr.purpose,
-                                                        &sig));
-  GNUNET_assert (NULL != (mock_element = json_pack ("{s:o, s:o, s:o, s:o, s:o, 
s:I, s:o}",
-                  "coin_pub", GNUNET_JSON_from_data_auto (&coin_pub),
-                  "merchant_pub", GNUNET_JSON_from_data_auto (&merchant_pub),
-                  "refund_amount", TALER_JSON_from_amount (&refund_amount),
-                  "refund_fee", TALER_JSON_from_amount (&refund_fee),
-                  "h_contract_terms", GNUNET_JSON_from_data_auto 
(&pay_ref->details.pay.h_contract_terms),
-                  "rtransaction_id", (json_int_t) instance_idx + 1,
-                  "merchant_sig", GNUNET_JSON_from_data_auto (&sig))));
-
-  if (1 != json_equal (mock_element, resp_element))
+                 TALER_string_to_amount 
(increase->details.refund_increase.refund_amount,
+                                         &refund_amount));
+  GNUNET_CONTAINER_multihashmap_iterate (map,
+                                         &hashmap_free,
+                                         NULL);
+  GNUNET_CONTAINER_multihashmap_destroy (map);
+  if (0 != TALER_amount_cmp (&acc,
+                             &refund_amount))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Got unexpected refund\n");
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "resp: %s\n",
-                json_dumps (resp_element, JSON_INDENT (2)));
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "mock: %s\n",
-                json_dumps (mock_element, JSON_INDENT (2)));
+                "Incomplete refund: expected '%s', got '%s'\n",
+                TALER_amount_to_string (&refund_amount),
+                TALER_amount_to_string (&acc));
     fail (is);
+    return;
   }
-
-  cmd->details.refund_lookup.rlo = NULL;
   next_command (is);
 }
 
@@ -1344,7 +1392,7 @@ refund_lookup_cb (void *cls,
 static void
 pay_cb (void *cls,
         unsigned int http_status,
-       enum TALER_ErrorCode ec,
+        enum TALER_ErrorCode ec,
         const json_t *obj)
 {
   struct InterpreterState *is = cls;
@@ -1361,7 +1409,6 @@ pay_cb (void *cls,
                 "Unexpected response code %u to command %s\n",
                 http_status,
                 cmd->label);
-    json_dumpf (obj, stderr, 0);
     fail (is);
     return;
   }
@@ -1373,28 +1420,19 @@ pay_cb (void *cls,
       GNUNET_JSON_spec_fixed_auto ("h_contract_terms", 
&cmd->details.pay.h_contract_terms),
       GNUNET_JSON_spec_end ()
     };
-    if (GNUNET_OK !=
+    GNUNET_assert (GNUNET_OK ==
         GNUNET_JSON_parse (obj,
                            spec,
                            &error_name,
-                           &error_line))
-    {
-      GNUNET_break_op (0);
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Parser failed on %s:%u\n",
-                  error_name,
-                  error_line);
-      fail (is);
-      return;
-    }
+                           &error_line));
     mr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_PAYMENT_OK);
     mr.purpose.size = htonl (sizeof (mr));
     mr.h_contract_terms = cmd->details.pay.h_contract_terms;
     if (GNUNET_OK !=
         GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_PAYMENT_OK,
                                     &mr.purpose,
-                                   &sig,
-                                   &cmd->details.pay.merchant_pub.eddsa_pub))
+                                    &sig,
+                                    &cmd->details.pay.merchant_pub.eddsa_pub))
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   "Merchant signature given in response to /pay invalid\n");
@@ -1421,8 +1459,11 @@ maint_child_death (void *cls)
   char c[16];
 
   cmd->details.run_aggregator.child_death_task = NULL;
-  pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
-  GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
+  pr = GNUNET_DISK_pipe_handle (sigpipe,
+                               GNUNET_DISK_PIPE_END_READ);
+  GNUNET_break (0 < GNUNET_DISK_file_read (pr,
+                                          &c,
+                                          sizeof (c)));
   GNUNET_OS_process_wait (cmd->details.run_aggregator.aggregator_proc);
   GNUNET_OS_process_destroy (cmd->details.run_aggregator.aggregator_proc);
   cmd->details.run_aggregator.aggregator_proc = NULL;
@@ -1448,7 +1489,7 @@ maint_child_death (void *cls)
 static void
 track_transfer_cb (void *cls,
                    unsigned int http_status,
-                  enum TALER_ErrorCode ec,
+                   enum TALER_ErrorCode ec,
                    const struct TALER_ExchangePublicKeyP *sign_key,
                    const json_t *json,
                    const struct GNUNET_HashCode *h_wire,
@@ -1466,7 +1507,6 @@ track_transfer_cb (void *cls,
                 "Unexpected response code %u to command %s\n",
                 http_status,
                 cmd->label);
-    json_dumpf (json, stderr, 0);
     fail (is);
     return;
   }
@@ -1517,7 +1557,7 @@ proposal_lookup_cb (void *cls,
 static void
 track_transaction_cb (void *cls,
                       unsigned int http_status,
-                     enum TALER_ErrorCode ec,
+                      enum TALER_ErrorCode ec,
                       const json_t *json)
 {
   struct InterpreterState *is = cls;
@@ -1530,7 +1570,6 @@ track_transaction_cb (void *cls,
                 "Unexpected response code %u to command %s\n",
                 http_status,
                 cmd->label);
-    json_dumpf (json, stderr, 0);
     fail (is);
     return;
   }
@@ -1551,14 +1590,14 @@ static const struct TALER_EXCHANGE_DenomPublicKey *
 find_pk (const struct TALER_EXCHANGE_Keys *keys,
          const struct TALER_Amount *amount)
 {
-  unsigned int i;
   struct GNUNET_TIME_Absolute now;
-  struct TALER_EXCHANGE_DenomPublicKey *pk;
   char *str;
 
   now = GNUNET_TIME_absolute_get ();
-  for (i=0;i<keys->num_denom_keys;i++)
+  for (unsigned int i=0;i<keys->num_denom_keys;i++)
   {
+    const struct TALER_EXCHANGE_DenomPublicKey *pk;
+
     pk = &keys->denom_keys[i];
     if ( (0 == TALER_amount_cmp (amount,
                                  &pk->value)) &&
@@ -1568,8 +1607,10 @@ find_pk (const struct TALER_EXCHANGE_Keys *keys,
   }
   /* do 2nd pass to check if expiration times are to blame for failure */
   str = TALER_amount_to_string (amount);
-  for (i=0;i<keys->num_denom_keys;i++)
+  for (unsigned int i=0;i<keys->num_denom_keys;i++)
   {
+    const struct TALER_EXCHANGE_DenomPublicKey *pk;
+
     pk = &keys->denom_keys[i];
     if ( (0 == TALER_amount_cmp (amount,
                                  &pk->value)) &&
@@ -1741,7 +1782,7 @@ cleanup_state (struct InterpreterState *is)
     case OC_REFUND_LOOKUP:
       if (NULL != cmd->details.refund_lookup.rlo)
       {
-        TALER_MERCHANT_refund_lookup_cancel (cmd->details.refund_lookup.rlo); 
+        TALER_MERCHANT_refund_lookup_cancel (cmd->details.refund_lookup.rlo);
         cmd->details.refund_lookup.rlo = NULL;
       }
       break;
@@ -1759,7 +1800,6 @@ cleanup_state (struct InterpreterState *is)
 
 /**
  * Run the main interpreter loop that performs exchange operations.
- *
  * @param cls contains the `struct InterpreterState`
  */
 static void
@@ -1770,138 +1810,114 @@ interpreter_run (void *cls)
   struct Command *cmd = &is->commands[is->ip];
   const struct Command *ref;
   struct TALER_ReservePublicKeyP reserve_pub;
-      struct TALER_CoinSpendPublicKeyP coin_pub;
-      struct TALER_Amount amount;
-      struct GNUNET_TIME_Absolute execution_date;
-      json_t *sender_details;
-      json_t *transfer_details;
-
-      is->task = NULL;
-      tc = GNUNET_SCHEDULER_get_task_context ();
-      if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
-      {
-        fprintf (stderr,
-                 "Test aborted by shutdown request\n");
-        fail (is);
-        return;
-      }
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Interpreter runs command %u/%s(%u)\n",
-                  is->ip,
-                  cmd->label,
-                  cmd->oc);
-      switch (cmd->oc)
-      {
-        case OC_END:
-          result = GNUNET_OK;
-          if (instance_idx + 1 == ninstances)
-          {
-            GNUNET_SCHEDULER_shutdown ();
-            return;
-          }
-          cleanup_state (is);
-          is->ip = 0;
-          instance_idx++;
-          instance = instances[instance_idx];
-          instance_priv = get_instance_priv (cfg, instance);
-          GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                      "Switching instance: `%s'\n",
-                      instance);
-          is->task = GNUNET_SCHEDULER_add_now (interpreter_run,
-                                               is);
-          return;
-
-        case OC_PROPOSAL_LOOKUP:
-        {
-          const char *order_id;
-
-          GNUNET_assert (NULL != 
cmd->details.proposal_lookup.proposal_reference);
-          ref = find_command (is, 
cmd->details.proposal_lookup.proposal_reference);
-          GNUNET_assert (NULL != ref);
-
-          order_id =
-            json_string_value (json_object_get 
(ref->details.proposal.contract_terms,
-                                                "order_id"));
-          GNUNET_assert (NULL !=
-                          (cmd->details.proposal_lookup.plo
-                           = TALER_MERCHANT_proposal_lookup (ctx,
-                                                             MERCHANT_URI,
-                                                             order_id,
-                                                             instance,
-                                                             
proposal_lookup_cb,
-                                                             is)));
-        }
-
-        return;
+  struct TALER_CoinSpendPublicKeyP coin_pub;
+  struct TALER_Amount amount;
+  struct GNUNET_TIME_Absolute execution_date;
+  json_t *sender_details;
+  json_t *transfer_details;
 
-      case OC_ADMIN_ADD_INCOMING:
-        if (NULL !=
-            cmd->details.admin_add_incoming.reserve_reference)
-        {
-          ref = find_command (is,
-                              
cmd->details.admin_add_incoming.reserve_reference);
-          GNUNET_assert (NULL != ref);
-          GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc);
-          cmd->details.admin_add_incoming.reserve_priv
-            = ref->details.admin_add_incoming.reserve_priv;
-        }
-        else
-        {
-          struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
+  is->task = NULL;
+  tc = GNUNET_SCHEDULER_get_task_context ();
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Test aborted by shutdown request\n");
+    fail (is);
+    return;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Interpreter runs command %u/%s(%u)\n",
+              is->ip,
+              cmd->label,
+              cmd->oc);
+  switch (cmd->oc)
+  {
+  case OC_END:
+    result = GNUNET_OK;
+    if (instance_idx + 1 == ninstances)
+    {
+      GNUNET_SCHEDULER_shutdown ();
+      return;
+    }
+    cleanup_state (is);
+    is->ip = 0;
+    instance_idx++;
+    instance = instances[instance_idx];
+    instance_priv = get_instance_priv (cfg, instance);
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Switching instance: `%s'\n",
+                instance);
+    is->task = GNUNET_SCHEDULER_add_now (interpreter_run,
+                                         is);
 
-          priv = GNUNET_CRYPTO_eddsa_key_create ();
-          cmd->details.admin_add_incoming.reserve_priv.eddsa_priv = *priv;
-          GNUNET_free (priv);
-        }
-        GNUNET_CRYPTO_eddsa_key_get_public 
(&cmd->details.admin_add_incoming.reserve_priv.eddsa_priv,
-                                            &reserve_pub.eddsa_pub);
-        if (GNUNET_OK !=
-            TALER_string_to_amount (cmd->details.admin_add_incoming.amount,
-                                    &amount))
-        {
-          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                      "Failed to parse amount `%s' at %u\n",
-                      cmd->details.admin_add_incoming.amount,
-                      is->ip);
-          fail (is);
-          return;
-        }
+      break;
+    case OC_PROPOSAL_LOOKUP:
+    {
+      const char *order_id;
 
-        execution_date = GNUNET_TIME_absolute_get ();
-        GNUNET_TIME_round_abs (&execution_date);
-        sender_details = json_loads 
(cmd->details.admin_add_incoming.sender_details,
-                                     JSON_REJECT_DUPLICATES,
-                                     NULL);
-        if (NULL == sender_details)
-        {
-          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                      "Failed to parse sender details `%s' at %u\n",
-                      cmd->details.admin_add_incoming.sender_details,
-                      is->ip);
-          fail (is);
-          return;
-        }
-        transfer_details = json_loads 
(cmd->details.admin_add_incoming.transfer_details,
-                                       JSON_REJECT_DUPLICATES,
-                                       NULL);
+      GNUNET_assert (NULL != cmd->details.proposal_lookup.proposal_reference);
+      GNUNET_assert (NULL != (ref =
+                             find_command (is,
+                                           
cmd->details.proposal_lookup.proposal_reference)));
+
+      order_id = json_string_value (json_object_get 
(ref->details.proposal.contract_terms,
+                                    "order_id"));
+      if (NULL == (cmd->details.proposal_lookup.plo
+          = TALER_MERCHANT_proposal_lookup (ctx,
+                                            MERCHANT_URI,
+                                            order_id,
+                                            instance,
+                                            proposal_lookup_cb,
+                                            is)))
+      {
+        GNUNET_break (0);
+        fail (is);
+      }
+    }
+    break;
 
-        if (NULL == transfer_details)
-        {
-          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                      "Failed to parse transfer details `%s' at %u\n",
-                      cmd->details.admin_add_incoming.transfer_details,
-                      is->ip);
-          fail (is);
-          return;
-        }
+  case OC_ADMIN_ADD_INCOMING:
+    if (NULL !=
+        cmd->details.admin_add_incoming.reserve_reference)
+    {
+      GNUNET_assert (NULL != (ref
+        = find_command (is,
+                       cmd->details.admin_add_incoming.reserve_reference)));
+      GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc);
+      cmd->details.admin_add_incoming.reserve_priv
+        = ref->details.admin_add_incoming.reserve_priv;
+    }
+    else
+    {
+      struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
 
-        cmd->details.admin_add_incoming.aih
-          = TALER_EXCHANGE_admin_add_incoming (exchange,
-                                               "http://localhost:18080/";,
-                                               &reserve_pub,
-                                               &amount,
-                                               execution_date,
-                                               sender_details,
+      priv = GNUNET_CRYPTO_eddsa_key_create ();
+      cmd->details.admin_add_incoming.reserve_priv.eddsa_priv = *priv;
+      GNUNET_free (priv);
+    }
+    GNUNET_CRYPTO_eddsa_key_get_public 
(&cmd->details.admin_add_incoming.reserve_priv.eddsa_priv,
+                                        &reserve_pub.eddsa_pub);
+    GNUNET_assert (GNUNET_OK ==
+      TALER_string_to_amount (cmd->details.admin_add_incoming.amount,
+                              &amount));
+    execution_date = GNUNET_TIME_absolute_get ();
+    GNUNET_TIME_round_abs (&execution_date);
+    GNUNET_assert (NULL != (sender_details
+      = json_loads (cmd->details.admin_add_incoming.sender_details,
+                    JSON_REJECT_DUPLICATES,
+                    NULL)));
+    GNUNET_assert (NULL != (transfer_details
+      = json_loads (cmd->details.admin_add_incoming.transfer_details,
+                    JSON_REJECT_DUPLICATES,
+                    NULL)));
+
+    cmd->details.admin_add_incoming.aih
+      = TALER_EXCHANGE_admin_add_incoming (exchange,
+                                           "http://localhost:18080/";,
+                                           &reserve_pub,
+                                           &amount,
+                                           execution_date,
+                                           sender_details,
                                            transfer_details,
                                            &add_incoming_cb,
                                            is);
@@ -1911,56 +1927,40 @@ interpreter_run (void *cls)
     {
       GNUNET_break (0);
       fail (is);
-      return;
     }
-    return;
+    break;
   case OC_WITHDRAW_STATUS:
     GNUNET_assert (NULL !=
                    cmd->details.reserve_status.reserve_reference);
-    ref = find_command (is,
-                        cmd->details.reserve_status.reserve_reference);
-    GNUNET_assert (NULL != ref);
+    GNUNET_assert (NULL != (ref = find_command
+      (is,
+       cmd->details.reserve_status.reserve_reference)));
     GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc);
     GNUNET_CRYPTO_eddsa_key_get_public 
(&ref->details.admin_add_incoming.reserve_priv.eddsa_priv,
                                         &reserve_pub.eddsa_pub);
-    cmd->details.reserve_status.wsh
-      = TALER_EXCHANGE_reserve_status (exchange,
-                                       &reserve_pub,
-                                       &reserve_status_cb,
-                                       is);
-    return;
-  case OC_WITHDRAW_SIGN:
-    GNUNET_assert (NULL !=
-                   cmd->details.reserve_withdraw.reserve_reference);
-    ref = find_command (is,
-                        cmd->details.reserve_withdraw.reserve_reference);
-    GNUNET_assert (NULL != ref);
-    GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc);
-    if (NULL != cmd->details.reserve_withdraw.amount)
-    {
-      if (GNUNET_OK !=
-          TALER_string_to_amount (cmd->details.reserve_withdraw.amount,
-                                  &amount))
-      {
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                    "Failed to parse amount `%s' at %u\n",
-                    cmd->details.reserve_withdraw.amount,
-                    is->ip);
-        fail (is);
-        return;
-      }
-      cmd->details.reserve_withdraw.pk = find_pk (is->keys,
-                                                  &amount);
-    }
-    if (NULL == cmd->details.reserve_withdraw.pk)
+    if (NULL == (cmd->details.reserve_status.wsh
+        = TALER_EXCHANGE_reserve_status (exchange,
+                                         &reserve_pub,
+                                         &reserve_status_cb,
+                                         is)))
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Failed to determine denomination key at %u\n",
-                  is->ip);
+      GNUNET_break (0);
       fail (is);
-      return;
     }
-
+    break;
+  case OC_WITHDRAW_SIGN:
+    GNUNET_assert (NULL != cmd->details.reserve_withdraw.reserve_reference);
+    GNUNET_assert (NULL != (ref = find_command
+      (is,
+       cmd->details.reserve_withdraw.reserve_reference)));
+    GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc);
+    GNUNET_assert (NULL != cmd->details.reserve_withdraw.amount);
+    GNUNET_assert (GNUNET_OK ==
+      TALER_string_to_amount (cmd->details.reserve_withdraw.amount,
+                              &amount));
+    GNUNET_assert (NULL != (cmd->details.reserve_withdraw.pk
+      = find_pk (is->keys,
+                 &amount)));
     /* create coin's private key */
     {
       struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
@@ -1976,193 +1976,181 @@ interpreter_run (void *cls)
                                 sizeof 
(cmd->details.reserve_withdraw.blinding_key));
 
     cmd->details.reserve_withdraw.wsh
-      = TALER_EXCHANGE_reserve_withdraw (exchange,
-                                         cmd->details.reserve_withdraw.pk,
-                                         
&ref->details.admin_add_incoming.reserve_priv,
-                                         
&cmd->details.reserve_withdraw.coin_priv,
-                                         
&cmd->details.reserve_withdraw.blinding_key,
-                                         &reserve_withdraw_cb,
-                                         is);
+      = TALER_EXCHANGE_reserve_withdraw
+        (exchange,
+         cmd->details.reserve_withdraw.pk,
+         &ref->details.admin_add_incoming.reserve_priv,
+         &cmd->details.reserve_withdraw.coin_priv,
+         &cmd->details.reserve_withdraw.blinding_key,
+         &reserve_withdraw_cb,
+         is);
     if (NULL == cmd->details.reserve_withdraw.wsh)
     {
       GNUNET_break (0);
       fail (is);
-      return;
     }
-    return;
+    break;
   case OC_PROPOSAL:
+  {
+    json_t *order;
+    json_error_t error;
+
+    GNUNET_assert (NULL != (order = json_loads (cmd->details.proposal.order,
+                                                JSON_REJECT_DUPLICATES,
+                                                &error)));
+    if (NULL != instance)
+    {
+      json_t *merchant;
+
+      merchant = json_object ();
+      json_object_set_new (merchant,
+                           "instance",
+                           json_string (instance));
+      json_object_set_new (order,
+                           "merchant",
+                           merchant);
+    }
+    cmd->details.proposal.po = TALER_MERCHANT_order_put (ctx,
+                                                         MERCHANT_URI,
+                                                         order,
+                                                         &proposal_cb,
+                                                         is);
+    json_decref (order);
+    if (NULL == cmd->details.proposal.po)
+    {
+      GNUNET_break (0);
+      fail (is);
+    }
+    break;
+  }
+  case OC_PAY:
+  {
+    struct TALER_MERCHANT_PayCoin *pc;
+    struct TALER_MERCHANT_PayCoin *icoin;
+    char *coins;
+    unsigned int npc;
+    const char *order_id;
+    struct GNUNET_TIME_Absolute refund_deadline;
+    struct GNUNET_TIME_Absolute pay_deadline;
+    struct GNUNET_TIME_Absolute timestamp;
+    struct GNUNET_HashCode h_wire;
+    struct TALER_MerchantPublicKeyP merchant_pub;
+    struct TALER_MerchantSignatureP merchant_sig;
+    struct TALER_Amount total_amount;
+    struct TALER_Amount max_fee;
+    char *token;
+    const char *error_name;
+    unsigned int error_line;
+
+    /* get proposal */
+    GNUNET_assert (NULL != (ref = find_command
+      (is,
+       cmd->details.pay.contract_ref)));
+    merchant_sig = ref->details.proposal.merchant_sig;
+    GNUNET_assert (NULL != ref->details.proposal.contract_terms);
     {
-      json_t *order;
-      json_error_t error;
+      /* Get information that needs to be replied in the deposit permission */
+      struct GNUNET_JSON_Specification spec[] = {
+        GNUNET_JSON_spec_string ("order_id", &order_id),
+        GNUNET_JSON_spec_absolute_time ("refund_deadline", &refund_deadline),
+        GNUNET_JSON_spec_absolute_time ("pay_deadline", &pay_deadline),
+        GNUNET_JSON_spec_absolute_time ("timestamp", &timestamp),
+        GNUNET_JSON_spec_fixed_auto ("merchant_pub", &merchant_pub),
+        GNUNET_JSON_spec_fixed_auto ("H_wire", &h_wire),
+        TALER_JSON_spec_amount ("amount", &total_amount),
+        TALER_JSON_spec_amount ("max_fee", &max_fee),
+        GNUNET_JSON_spec_end()
+      };
 
-      order = json_loads (cmd->details.proposal.order,
-                          JSON_REJECT_DUPLICATES,
-                          &error);
-      if (NULL != instance)
-      {
-        json_t *merchant;
-
-        merchant = json_object ();
-        json_object_set_new (merchant,
-                             "instance",
-                             json_string (instance));
-        json_object_set_new (order,
-                             "merchant",
-                             merchant);
-      }
-      if (NULL == order)
-      {
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                    "Failed to parse the order `%s' at command #%u: %s at 
%u\n",
-                    cmd->details.proposal.order,
-                    is->ip,
-                    error.text,
-                    (unsigned int) error.column);
-        fail (is);
-        return;
-      }
-      cmd->details.proposal.po
-        = TALER_MERCHANT_order_put (ctx,
-                                    MERCHANT_URI,
-                                    order,
-                                    &proposal_cb,
-                                    is);
-      json_decref (order);
-      if (NULL == cmd->details.proposal.po)
-      {
-        GNUNET_break (0);
-        fail (is);
-        return;
-      }
+    if (GNUNET_OK !=
+        GNUNET_JSON_parse (ref->details.proposal.contract_terms,
+                           spec,
+                           &error_name,
+                           &error_line))
+    {
+      GNUNET_break_op (0);
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Parser failed on %s:%u\n",
+                  error_name,
+                  error_line);
+      /**
+       * Let's use fail() here, as the proposal might be broken
+       * because of backend's fault.
+       */
+      fail (is);
       return;
     }
-  case OC_PAY:
+    cmd->details.pay.merchant_pub = merchant_pub;
+    }
+    /* strtok loop here */
+    coins = GNUNET_strdup (cmd->details.pay.coin_ref);
+    GNUNET_assert (NULL != (token = strtok (coins, ";")));
+    pc = GNUNET_new (struct TALER_MERCHANT_PayCoin);
+    icoin = pc;
+    npc = 1;
+    do
     {
-      struct TALER_MERCHANT_PayCoin pc;
-      const char *order_id;
-      struct GNUNET_TIME_Absolute refund_deadline;
-      struct GNUNET_TIME_Absolute pay_deadline;
-      struct GNUNET_TIME_Absolute timestamp;
-      struct GNUNET_HashCode h_wire;
-      struct TALER_MerchantPublicKeyP merchant_pub;
-      struct TALER_MerchantSignatureP merchant_sig;
-      struct TALER_Amount total_amount;
-      struct TALER_Amount max_fee;
-      const char *error_name;
-      unsigned int error_line;
-
-      /* get proposal */
-      ref = find_command (is,
-                          cmd->details.pay.contract_ref);
-      GNUNET_assert (NULL != ref);
-      merchant_sig = ref->details.proposal.merchant_sig;
-      GNUNET_assert (NULL != ref->details.proposal.contract_terms);
-      {
-        /* Get information that need to be replied in the deposit permission */
-        struct GNUNET_JSON_Specification spec[] = {
-          GNUNET_JSON_spec_string ("order_id", &order_id),
-          GNUNET_JSON_spec_absolute_time ("refund_deadline", &refund_deadline),
-          GNUNET_JSON_spec_absolute_time ("pay_deadline", &pay_deadline),
-          GNUNET_JSON_spec_absolute_time ("timestamp", &timestamp),
-          GNUNET_JSON_spec_fixed_auto ("merchant_pub", &merchant_pub),
-          GNUNET_JSON_spec_fixed_auto ("H_wire", &h_wire),
-          TALER_JSON_spec_amount ("amount", &total_amount),
-          TALER_JSON_spec_amount ("max_fee", &max_fee),
-          GNUNET_JSON_spec_end()
-        };
-
-        if (GNUNET_OK !=
-            GNUNET_JSON_parse (ref->details.proposal.contract_terms,
-                               spec,
-                               &error_name,
-                               &error_line))
-        {
-          GNUNET_break_op (0);
-          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                      "Parser failed on %s:%u\n",
-                      error_name,
-                      error_line);
-          fail (is);
-          return;
-        }
-        cmd->details.pay.merchant_pub = merchant_pub;
-      }
+      const struct Command *coin_ref;
 
+      GNUNET_assert (coin_ref = find_command (is,
+                                              token));
+      switch (coin_ref->oc)
       {
-        const struct Command *coin_ref;
-       memset (&pc, 0, sizeof (pc));
-       coin_ref = find_command (is,
-                                cmd->details.pay.coin_ref);
-       GNUNET_assert (NULL != ref);
-       switch (coin_ref->oc)
-       {
-       case OC_WITHDRAW_SIGN:
-         pc.coin_priv = coin_ref->details.reserve_withdraw.coin_priv;
-         pc.denom_pub = coin_ref->details.reserve_withdraw.pk->key;
-         pc.denom_sig = coin_ref->details.reserve_withdraw.sig;
-          pc.denom_value = coin_ref->details.reserve_withdraw.pk->value;
-         break;
-       default:
-         GNUNET_assert (0);
-       }
-
-       if (GNUNET_OK !=
-           TALER_string_to_amount (cmd->details.pay.amount_without_fee,
-                                   &pc.amount_without_fee))
-       {
-         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                     "Failed to parse amount `%s' at %u\n",
-                     cmd->details.pay.amount_without_fee,
-                     is->ip);
-         fail (is);
-         return;
-       }
-
-       if (GNUNET_OK !=
-           TALER_string_to_amount (cmd->details.pay.amount_with_fee,
-                                   &pc.amount_with_fee))
-       {
-         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                     "Failed to parse amount `%s' at %u\n",
-                     cmd->details.pay.amount_with_fee,
-                     is->ip);
-         fail (is);
-         return;
-       }
+      case OC_WITHDRAW_SIGN:
+        icoin->coin_priv = coin_ref->details.reserve_withdraw.coin_priv;
+        icoin->denom_pub = coin_ref->details.reserve_withdraw.pk->key;
+        icoin->denom_sig = coin_ref->details.reserve_withdraw.sig;
+        icoin->denom_value = coin_ref->details.reserve_withdraw.pk->value;
+       break;
+      default:
+        GNUNET_assert (0);
       }
 
-      cmd->details.pay.ph
-       = TALER_MERCHANT_pay_wallet (ctx,
-                                    MERCHANT_URI,
-                                     instance,
-                                    &ref->details.proposal.hash,
-                                    &total_amount,
-                                    &max_fee,
-                                    &merchant_pub,
-                                     &merchant_sig,
-                                    timestamp,
-                                    refund_deadline,
-                                    pay_deadline,
-                                    &h_wire,
-                                    EXCHANGE_URI,
-                                     order_id,
-                                    1 /* num_coins */,
-                                    &pc /* coins */,
-                                    &pay_cb,
-                                    is);
-    }
+      GNUNET_assert (GNUNET_OK ==
+        TALER_string_to_amount (cmd->details.pay.amount_without_fee,
+                                &icoin->amount_without_fee));
+      GNUNET_assert (GNUNET_OK ==
+          TALER_string_to_amount (cmd->details.pay.amount_with_fee,
+                                  &icoin->amount_with_fee));
+      token = strtok (NULL, ";");
+      if (NULL == token)
+        break;
+      icoin->next = GNUNET_new (struct TALER_MERCHANT_PayCoin);
+      icoin = icoin->next;
+    } while (1);
+
+    icoin->next = NULL;
+    cmd->details.pay.ph = TALER_MERCHANT_pay_wallet
+      (ctx,
+       MERCHANT_URI,
+       instance,
+       &ref->details.proposal.hash,
+       &total_amount,
+       &max_fee,
+       &merchant_pub,
+       &merchant_sig,
+       timestamp,
+       refund_deadline,
+       pay_deadline,
+       &h_wire,
+       EXCHANGE_URI,
+       order_id,
+       npc /* num_coins */,
+       pc /* coins */,
+       &pay_cb,
+       is);
+  }
     if (NULL == cmd->details.pay.ph)
     {
       GNUNET_break (0);
       fail (is);
-      return;
     }
-    return;
+    break;
   case OC_RUN_AGGREGATOR:
     {
       const struct GNUNET_DISK_FileHandle *pr;
 
-      cmd->details.run_aggregator.aggregator_proc
+      GNUNET_assert (NULL != (cmd->details.run_aggregator.aggregator_proc
         = GNUNET_OS_start_process (GNUNET_NO,
                                    GNUNET_OS_INHERIT_STD_ALL,
                                    NULL, NULL, NULL,
@@ -2170,40 +2158,26 @@ interpreter_run (void *cls)
                                    "taler-exchange-aggregator",
                                    "-c", "test_merchant_api.conf",
                                    "-t", /* exit when done */
-                                   NULL);
-      if (NULL == cmd->details.run_aggregator.aggregator_proc)
-      {
-        GNUNET_break (0);
-        fail (is);
-        return;
-      }
+                                   NULL)));
       pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
       cmd->details.run_aggregator.child_death_task
         = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
                                           pr,
                                           &maint_child_death, is);
-      return;
     }
+    break;
   case OC_CHECK_BANK_TRANSFER:
     {
-      if (GNUNET_OK !=
-          TALER_string_to_amount (cmd->details.check_bank_transfer.amount,
-                                  &amount))
-      {
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                    "Failed to parse amount `%s' at %u\n",
-                    cmd->details.reserve_withdraw.amount,
-                    is->ip);
-        fail (is);
-        return;
-      }
-      if (GNUNET_OK !=
-          TALER_FAKEBANK_check (fakebank,
-                                &amount,
-                                cmd->details.check_bank_transfer.account_debit,
-                                
cmd->details.check_bank_transfer.account_credit,
-                                EXCHANGE_URI,
-                                &cmd->details.check_bank_transfer.subject))
+      GNUNET_assert (GNUNET_OK == TALER_string_to_amount
+        (cmd->details.check_bank_transfer.amount,
+         &amount));
+      if (GNUNET_OK != TALER_FAKEBANK_check
+           (fakebank,
+            &amount,
+            cmd->details.check_bank_transfer.account_debit,
+            cmd->details.check_bank_transfer.account_credit,
+            EXCHANGE_URI,
+            &cmd->details.check_bank_transfer.subject))
       {
         GNUNET_break (0);
         fail (is);
@@ -2229,102 +2203,115 @@ interpreter_run (void *cls)
       struct TALER_WireTransferIdentifierRawP wtid;
       const char *subject;
 
-      ref = find_command (is,
-                          cmd->details.track_transfer.check_bank_ref);
-      GNUNET_assert (NULL != ref);
+      GNUNET_assert (NULL != ( ref = find_command
+        (is,
+         cmd->details.track_transfer.check_bank_ref)));
       subject = ref->details.check_bank_transfer.subject;
-      GNUNET_assert (GNUNET_OK ==
-                     GNUNET_STRINGS_string_to_data (subject,
-                                                    strlen (subject),
-                                                    &wtid,
-                                                    sizeof (wtid)));
-      cmd->details.track_transfer.tdo
-        = TALER_MERCHANT_track_transfer (ctx,
-                                         MERCHANT_URI,
-                                         instance,
-                                         &wtid,
-                                         EXCHANGE_URI,
-                                         &track_transfer_cb,
-                                         is);
-      return;
+      GNUNET_assert (GNUNET_OK == GNUNET_STRINGS_string_to_data (subject,
+         strlen (subject),
+         &wtid,
+         sizeof (wtid)));
+      if (NULL == (cmd->details.track_transfer.tdo
+          = TALER_MERCHANT_track_transfer (ctx,
+                                           MERCHANT_URI,
+                                           instance,
+                                          "test",
+                                           &wtid,
+                                           EXCHANGE_URI,
+                                           &track_transfer_cb,
+                                           is)))
+      {
+        GNUNET_break (0);
+        fail (is);
+      }
     }
+    return;
   case OC_TRACK_TRANSACTION:
   {
     const struct Command *proposal_ref;
     const char *order_id;
 
-    ref = find_command (is,
-                        cmd->details.track_transaction.pay_ref);
-    GNUNET_assert (NULL != ref);
-    proposal_ref = find_command (is,
-                                 ref->details.pay.contract_ref);
-    order_id = json_string_value (json_object_get 
(proposal_ref->details.proposal.contract_terms,
-                                        "order_id"));
-    cmd->details.track_transaction.tth =
-      TALER_MERCHANT_track_transaction (ctx,
-                                        MERCHANT_URI,
-                                        instance,
-                                        order_id,
-                                        &track_transaction_cb,
-                                        is);
-  }
+    GNUNET_assert(NULL != (ref = find_command
+      (is,
+       cmd->details.track_transaction.pay_ref)));
+    GNUNET_assert (NULL != (proposal_ref = find_command
+      (is,
+       ref->details.pay.contract_ref)));
+    order_id = json_string_value
+      (json_object_get (proposal_ref->details.proposal.contract_terms,
+                        "order_id"));
+
+    if (NULL == (cmd->details.track_transaction.tth
+        = TALER_MERCHANT_track_transaction (ctx,
+                                            MERCHANT_URI,
+                                            instance,
+                                            order_id,
+                                            &track_transaction_cb,
+                                            is)))
+    {
+      GNUNET_break (0);
+      fail (is);
+    }
     return;
+  }
   case OC_HISTORY:
-
-    if (NULL ==
-       (cmd->details.history.ho = TALER_MERCHANT_history (ctx,
-                                                         MERCHANT_URI,
-                                                          instance,
-                                                          
cmd->details.history.start,
-                                                          
cmd->details.history.nrows,
-                                                         
cmd->details.history.date,
-                                                         &history_cb,
-                                                         is)))
+    if (0 == cmd->details.history.date.abs_value_us)
     {
+      cmd->details.history.date = GNUNET_TIME_absolute_add
+        (GNUNET_TIME_absolute_get (),
+         GNUNET_TIME_UNIT_HOURS);
+      GNUNET_TIME_round_abs (&cmd->details.history.date);
+    }
+    if (NULL == (cmd->details.history.ho
+        = TALER_MERCHANT_history (ctx,
+                                 MERCHANT_URI,
+                                  instance,
+                                  cmd->details.history.start,
+                                  cmd->details.history.nrows,
+                                 cmd->details.history.date,
+                                 &history_cb,
+                                 is)))
+    {
+      GNUNET_break (0);
       fail (is);
-      return;
     }
     break;
   case OC_REFUND_INCREASE:
   {
     struct TALER_Amount refund_amount;
 
-    GNUNET_assert (GNUNET_OK ==
-      TALER_string_to_amount (cmd->details.refund_increase.refund_amount,
-                              &refund_amount));
-    if (NULL ==
-       (cmd->details.refund_increase.rio =
-          TALER_MERCHANT_refund_increase (ctx,
-                                          MERCHANT_URI,
-                                          
cmd->details.refund_increase.order_id,
-                                          &refund_amount,
-                                          cmd->details.refund_increase.reason,
-                                          instance,
-                                          refund_increase_cb,
-                                          is)))
+    GNUNET_assert (GNUNET_OK == TALER_string_to_amount
+      (cmd->details.refund_increase.refund_amount,
+       &refund_amount));
+    if (NULL == (cmd->details.refund_increase.rio
+         = TALER_MERCHANT_refund_increase
+           (ctx,
+            MERCHANT_URI,
+            cmd->details.refund_increase.order_id,
+            &refund_amount,
+            cmd->details.refund_increase.reason,
+            instance,
+            refund_increase_cb,
+            is)))
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Could not issue a /refund increase request\n");
+      GNUNET_break (0);
       fail (is);
-      return; 
     }
     break;
   }
   case OC_REFUND_LOOKUP:
   {
-    if (NULL ==
-        (cmd->details.refund_lookup.rlo =
-           TALER_MERCHANT_refund_lookup (ctx,
-                                         MERCHANT_URI,
-                                         cmd->details.refund_lookup.order_id,
-                                         instance,
-                                         refund_lookup_cb,
-                                         is)))
+    if (NULL == (cmd->details.refund_lookup.rlo
+          = TALER_MERCHANT_refund_lookup
+            (ctx,
+             MERCHANT_URI,
+             cmd->details.refund_lookup.order_id,
+             instance,
+             refund_lookup_cb,
+             is)))
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Could not issue a /refund lookup request\n");
+      GNUNET_break (0);
       fail (is);
-      return;
     }
     break;
   }
@@ -2399,12 +2386,7 @@ do_shutdown (void *cls)
   }
   TALER_FAKEBANK_stop (fakebank);
   fakebank = NULL;
-
-  /**
-   * WARNING: hangs when attempting to drop tables.
-   */
   db->drop_tables (db->cls);
-
   TALER_MERCHANTDB_plugin_unload (db);
   GNUNET_CONFIGURATION_destroy (cfg);
 }
@@ -2431,12 +2413,12 @@ cert_cb (void *cls,
   ERR (NULL == keys);
   ERR (0 == keys->num_sign_keys);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Read %u signing keys\n",
-              keys->num_sign_keys);
+          "Read %u signing keys\n",
+          keys->num_sign_keys);
   ERR (0 == keys->num_denom_keys);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Read %u denomination keys\n",
-              keys->num_denom_keys);
+          "Read %u denomination keys\n",
+          keys->num_denom_keys);
 #undef ERR
 
   /* run actual tests via interpreter-loop */
@@ -2458,11 +2440,12 @@ sighandler_child_death ()
   static char c;
   int old_errno = errno;       /* back-up errno */
 
-  GNUNET_break (1 ==
-               GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
-                                       (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
-                                       &c, sizeof (c)));
-  errno = old_errno;           /* restore errno */
+  GNUNET_break (1 == GNUNET_DISK_file_write
+    (GNUNET_DISK_pipe_handle (sigpipe,
+                              GNUNET_DISK_PIPE_END_WRITE),
+                              &c,
+                              sizeof (c)));
+  errno = old_errno; /* restore errno */
 }
 
 /**
@@ -2476,48 +2459,70 @@ run (void *cls)
   struct InterpreterState *is;
   static struct Command commands[] =
   {
-    /* Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config */
+    /* Fill reserve with EUR:5.01, as withdraw fee is 1 ct per
+       config */
     { .oc = OC_ADMIN_ADD_INCOMING,
       .label = "create-reserve-1",
       .expected_response_code = MHD_HTTP_OK,
-      .details.admin_add_incoming.sender_details = "{ \"type\":\"test\", 
\"bank_uri\":\"" BANK_URI "\", \"account_number\":62, \"uuid\":1 }",
-      .details.admin_add_incoming.transfer_details = "{ \"uuid\": 1}",
-      .details.admin_add_incoming.amount = "EUR:5.01" },
+      .details.admin_add_incoming.sender_details
+      = "{ \"type\":\"test\", \"bank_uri\":\"" BANK_URI "\", \
+        \"account_number\":62, \"uuid\":1 }",
+      .details.admin_add_incoming.transfer_details
+        = "{ \"uuid\": 1}",
+      .details.admin_add_incoming.amount = "EUR:10.02" },
 
     /* Withdraw a 5 EUR coin, at fee of 1 ct */
     { .oc = OC_WITHDRAW_SIGN,
       .label = "withdraw-coin-1",
       .expected_response_code = MHD_HTTP_OK,
-      .details.reserve_withdraw.reserve_reference = "create-reserve-1",
+      .details.reserve_withdraw.reserve_reference
+        = "create-reserve-1",
       .details.reserve_withdraw.amount = "EUR:5" },
-    /* Check that deposit and withdraw operation are in history, and
-       that the balance is now at zero */
+
+    /* Withdraw a 5 EUR coin, at fee of 1 ct */
+    { .oc = OC_WITHDRAW_SIGN,
+      .label = "withdraw-coin-2",
+      .expected_response_code = MHD_HTTP_OK,
+      .details.reserve_withdraw.reserve_reference
+        = "create-reserve-1",
+      .details.reserve_withdraw.amount = "EUR:5" },
+
+    /* Check that deposit and withdraw operation are in history,
+       and that the balance is now at zero */
     { .oc = OC_WITHDRAW_STATUS,
       .label = "withdraw-status-1",
       .expected_response_code = MHD_HTTP_OK,
-      .details.reserve_status.reserve_reference = "create-reserve-1",
+      .details.reserve_status.reserve_reference
+        = "create-reserve-1",
       .details.reserve_status.expected_balance = "EUR:0" },
+
     /* Create proposal */
     { .oc = OC_PROPOSAL,
       .label = "create-proposal-1",
       .expected_response_code = MHD_HTTP_OK,
       .details.proposal.order = "{\
-                  \"max_fee\":\
-                     {\"currency\":\"EUR\", \"value\":0, 
\"fraction\":50000000},\
-                  \"order_id\":\"1\",\
-                  \"timestamp\":\"\\/Date(42)\\/\",\
-                  \"refund_deadline\":\"\\/Date(0)\\/\",\
-                  \"pay_deadline\":\"\\/Date(9999999999)\\/\",\
-                  \"amount\":{\"currency\":\"EUR\", \"value\":5, 
\"fraction\":0},\
-                 \"summary\": \"merchant-lib testcase\",\
-                  \"products\":\
-                     [ {\"description\":\"ice cream\", \"value\":\"{EUR:5}\"} 
] }"},
-
+        \"max_fee\":\
+          {\"currency\":\"EUR\",\
+           \"value\":0,\
+           \"fraction\":50000000},\
+        \"order_id\":\"1\",\
+        \"refund_deadline\":\"\\/Date(0)\\/\",\
+        \"pay_deadline\":\"\\/Date(99999999999)\\/\",\
+        \"amount\":\
+          {\"currency\":\"EUR\",\
+           \"value\":5,\
+           \"fraction\":0},\
+       \"summary\": \"merchant-lib testcase\",\
+        \"products\":\
+          [ {\"description\":\"ice cream\",\
+             \"value\":\"{EUR:5}\"} ] }"},
+
+    /* execute simple payment */
     { .oc = OC_PAY,
       .label = "deposit-simple",
       .expected_response_code = MHD_HTTP_OK,
       .details.pay.contract_ref = "create-proposal-1",
-      .details.pay.coin_ref = "withdraw-coin-1",
+      .details.pay.coin_ref = "withdraw-coin-1;withdraw-coin-2",
       .details.pay.amount_with_fee = "EUR:5",
       .details.pay.amount_without_fee = "EUR:4.99" },
 
@@ -2530,25 +2535,30 @@ run (void *cls)
       .details.pay.amount_with_fee = "EUR:5",
       .details.pay.amount_without_fee = "EUR:4.99" },
 
-
     /* Create another contract */
     { .oc = OC_PROPOSAL,
       .label = "create-proposal-2",
       .expected_response_code = MHD_HTTP_OK,
       .details.proposal.order = "{\
-                  \"max_fee\":\
-                     {\"currency\":\"EUR\", \"value\":0, 
\"fraction\":50000000},\
-                  \"order_id\":\"2\",\
-                  \"timestamp\":\"\\/Date(42)\\/\",\
-                  \"refund_deadline\":\"\\/Date(0)\\/\",\
-                  \"pay_deadline\":\"\\/Date(9999999999)\\/\",\
-                  \"amount\":{\"currency\":\"EUR\", \"value\":5, 
\"fraction\":0},\
-                  \"summary\":\"useful product\",\
-                  \"products\":\
-                     [ {\"description\":\"ice cream\", \"value\":\"{EUR:5}\"} 
] }" },
-
-    /* Try to double-spend the 5 EUR coin at the same merchant (but different
-       transaction ID) */
+        \"max_fee\":\
+          {\"currency\":\"EUR\",\
+           \"value\":0,\
+           \"fraction\":50000000},\
+        \"order_id\":\"2\",\
+        \"refund_deadline\":\"\\/Date(0)\\/\",\
+        \"pay_deadline\":\"\\/Date(9999999999)\\/\",\
+        \"amount\":\
+          {\"currency\":\"EUR\",\
+           \"value\":5,\
+           \"fraction\":0},\
+        \"summary\":\"useful product\",\
+        \"products\":\
+          [ {\"description\":\"ice cream\",\
+             \"value\":\"{EUR:5}\"} ] }" },
+    /**
+     * Try to double-spend the 5 EUR coin at the same
+     * merchant (but different transaction ID)
+     */
     { .oc = OC_PAY,
       .label = "deposit-double-2",
       .expected_response_code = MHD_HTTP_FORBIDDEN,
@@ -2557,28 +2567,59 @@ run (void *cls)
       .details.pay.amount_with_fee = "EUR:5",
       .details.pay.amount_without_fee = "EUR:4.99" },
 
+    { .oc = OC_HISTORY,
+      .label = "history-0",
+      .expected_response_code = MHD_HTTP_OK,
+      /**
+       * all records to be returned; setting date as 0 lets the
+       * interpreter set it as 'now' + one hour delta, just to
+       * make sure it surpasses the proposal's timestamp.
+       */
+      .details.history.date.abs_value_us = 0,
+      /**
+       * We only expect ONE result (create-proposal-1) to be
+       * included in /history response, because create-proposal-3
+       * did NOT go through because of double spending.
+       */
+      .details.history.nresult = 1,
+      .details.history.start = 10,
+      .details.history.nrows = 10
+    },
+
     /* Fill second reserve with EUR:1 */
     { .oc = OC_ADMIN_ADD_INCOMING,
       .label = "create-reserve-2",
       .expected_response_code = MHD_HTTP_OK,
-      .details.admin_add_incoming.sender_details = "{ \"type\":\"test\", 
\"bank_uri\":\"" BANK_URI "\", \"account_number\":63, \"uuid\":2 }",
-      .details.admin_add_incoming.transfer_details = "{ \"uuid\": 2}",
+      .details.admin_add_incoming.sender_details
+        = "{ \"type\":\"test\",\
+          \"bank_uri\":\"" BANK_URI "\",\
+          \"account_number\":63,\
+          \"uuid\":2 }",
+      .details.admin_add_incoming.transfer_details
+        = "{ \"uuid\": 2}",
       .details.admin_add_incoming.amount = "EUR:1" },
 
     /* Add another 4.01 EUR to reserve #2 */
     { .oc = OC_ADMIN_ADD_INCOMING,
       .label = "create-reserve-2b",
       .expected_response_code = MHD_HTTP_OK,
-      .details.admin_add_incoming.reserve_reference = "create-reserve-2",
-      .details.admin_add_incoming.sender_details = "{ \"type\":\"test\", 
\"bank_uri\":\"" BANK_URI "\", \"account_number\":63, \"uuid\":3  }",
-      .details.admin_add_incoming.transfer_details = "{ \"uuid\": 3}",
+      .details.admin_add_incoming.reserve_reference
+        = "create-reserve-2",
+      .details.admin_add_incoming.sender_details
+        = "{ \"type\":\"test\",\
+          \"bank_uri\":\"" BANK_URI "\",\
+          \"account_number\":63,\
+          \"uuid\":3  }",
+      .details.admin_add_incoming.transfer_details
+        = "{ \"uuid\": 3}",
       .details.admin_add_incoming.amount = "EUR:4.01" },
 
     /* Withdraw a 5 EUR coin, at fee of 1 ct */
     { .oc = OC_WITHDRAW_SIGN,
       .label = "withdraw-coin-2",
       .expected_response_code = MHD_HTTP_OK,
-      .details.reserve_withdraw.reserve_reference = "create-reserve-2",
+      .details.reserve_withdraw.reserve_reference
+        = "create-reserve-2",
       .details.reserve_withdraw.amount = "EUR:5" },
 
     /* Proposal lookup */
@@ -2586,23 +2627,25 @@ run (void *cls)
       .oc = OC_PROPOSAL_LOOKUP,
       .label = "fetch-proposal-2",
       .expected_response_code = MHD_HTTP_OK,
-      .details.proposal_lookup.proposal_reference = "create-proposal-2" },
+      .details.proposal_lookup.proposal_reference
+        = "create-proposal-2" },
 
     /* Check nothing happened on the bank side so far */
     { .oc = OC_CHECK_BANK_TRANSFERS_EMPTY,
       .label = "check_bank_empty" },
 
-
     /* Run transfers. */
     { .oc = OC_RUN_AGGREGATOR,
       .label = "run-aggregator" },
 
-    /* Obtain WTID of the transfer */
+    /* Obtain WTID of the transfer generated by "deposit-simple" */
     { .oc = OC_CHECK_BANK_TRANSFER,
       .label = "check_bank_transfer-498c",
       .details.check_bank_transfer.amount = "EUR:4.98",
-      .details.check_bank_transfer.account_debit = 2, /* exchange-outgoing */
-      .details.check_bank_transfer.account_credit = 62 /* merchant */
+      /* exchange-outgoing */
+      .details.check_bank_transfer.account_debit = 2,
+      /* merchant */
+      .details.check_bank_transfer.account_credit = 62
     },
 
     /* Check that there are no other unusual transfers */
@@ -2612,22 +2655,25 @@ run (void *cls)
     { .oc = OC_TRACK_TRANSACTION,
       .label = "track-transaction-1",
       .expected_response_code = MHD_HTTP_OK,
-      .details.track_transaction.expected_transfer_ref = 
"check_bank_transfer-498c",
+      .details.track_transaction.expected_transfer_ref
+        = "check_bank_transfer-498c",
       .details.track_transaction.pay_ref = "deposit-simple",
-      .details.track_transaction.wire_fee = "EUR:0.01",
+      .details.track_transaction.wire_fee = "EUR:0.01"
     },
 
     /* Trace the WTID back to the original transaction */
     { .oc = OC_TRACK_TRANSFER,
       .label = "track-transfer-1",
       .expected_response_code = MHD_HTTP_OK,
-      .details.track_transfer.check_bank_ref = "check_bank_transfer-498c",
+      .details.track_transfer.check_bank_ref
+        = "check_bank_transfer-498c",
       .details.track_transfer.expected_pay_ref = "deposit-simple"
     },
     { .oc = OC_TRACK_TRANSFER,
       .label = "track-transfer-1-again",
       .expected_response_code = MHD_HTTP_OK,
-      .details.track_transfer.check_bank_ref = "check_bank_transfer-498c",
+      .details.track_transfer.check_bank_ref
+        = "check_bank_transfer-498c",
       .details.track_transfer.expected_pay_ref = "deposit-simple"
     },
 
@@ -2648,8 +2694,10 @@ run (void *cls)
     { .oc = OC_CHECK_BANK_TRANSFER,
       .label = "check_bank_transfer-498c-2",
       .details.check_bank_transfer.amount = "EUR:4.98",
-      .details.check_bank_transfer.account_debit = 2, /* exchange-outgoing */
-      .details.check_bank_transfer.account_credit = 62 /* merchant */
+      /* exchange-outgoing */
+      .details.check_bank_transfer.account_debit = 2,
+      /* merchant */
+      .details.check_bank_transfer.account_credit = 62
     },
 
     /* Check that there are no other unusual transfers */
@@ -2660,20 +2708,25 @@ run (void *cls)
     { .oc = OC_TRACK_TRANSFER,
       .label = "track-transfer-2",
       .expected_response_code = MHD_HTTP_OK,
-      .details.track_transfer.check_bank_ref = "check_bank_transfer-498c-2",
-      .details.track_transfer.expected_pay_ref = "deposit-simple-2"
+      .details.track_transfer.check_bank_ref
+        = "check_bank_transfer-498c-2",
+      .details.track_transfer.expected_pay_ref
+        = "deposit-simple-2"
     },
     { .oc = OC_TRACK_TRANSFER,
       .label = "track-transfer-2-again",
       .expected_response_code = MHD_HTTP_OK,
-      .details.track_transfer.check_bank_ref = "check_bank_transfer-498c-2",
-      .details.track_transfer.expected_pay_ref = "deposit-simple-2"
+      .details.track_transfer.check_bank_ref
+        = "check_bank_transfer-498c-2",
+      .details.track_transfer.expected_pay_ref
+        = "deposit-simple-2"
     },
 
     { .oc = OC_TRACK_TRANSACTION,
       .label = "track-transaction-2",
       .expected_response_code = MHD_HTTP_OK,
-      .details.track_transaction.expected_transfer_ref = 
"check_bank_transfer-498c-2",
+      .details.track_transaction.expected_transfer_ref
+        = "check_bank_transfer-498c-2",
       .details.track_transaction.wire_fee = "EUR:0.01",
       .details.track_transaction.pay_ref = "deposit-simple-2"
     },
@@ -2681,27 +2734,33 @@ run (void *cls)
     { .oc = OC_HISTORY,
       .label = "history-1",
       .expected_response_code = MHD_HTTP_OK,
-      /*all records to be returned*/
-      .details.history.date.abs_value_us = 43 * 1000LL * 1000LL,
+      .details.history.date.abs_value_us = 0,
+      /**
+       * Now we expect BOTH contracts (create-proposal-{1,2})
+       * to be included in /history response, because
+       * create-proposal-2 has now been correctly paid.
+       */
       .details.history.nresult = 2,
       .details.history.start = 10,
       .details.history.nrows = 10
     },
+
     { .oc = OC_HISTORY,
       .label = "history-2",
       .expected_response_code = MHD_HTTP_OK,
       /*no records returned, time limit too ancient*/
-      .details.history.date.abs_value_us = 0,
+      .details.history.date.abs_value_us = 1,
       .details.history.nresult = 0,
       .details.history.start = 10,
       .details.history.nrows = 10
     },
+
     { .oc = OC_REFUND_INCREASE,
       .label = "refund-increase-1",
       .details.refund_increase.refund_amount = "EUR:0.1",
       .details.refund_increase.refund_fee = "EUR:0.01",
       .details.refund_increase.reason = "refund test",
-      .details.refund_increase.order_id = "1"    
+      .details.refund_increase.order_id = "1"
     },
     { .oc = OC_REFUND_LOOKUP,
       .label = "refund-lookup-1",
@@ -2712,7 +2771,6 @@ run (void *cls)
     /* end of testcase */
     { .oc = OC_END }
   };
-
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Interpreter initializing\n");
   fakebank = TALER_FAKEBANK_start (BANK_PORT);
@@ -2727,18 +2785,18 @@ run (void *cls)
   is = GNUNET_new (struct InterpreterState);
   is->commands = commands;
 
-  ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
-                          &rc);
-  GNUNET_assert (NULL != ctx);
+  GNUNET_assert (ctx = GNUNET_CURL_init
+    (&GNUNET_CURL_gnunet_scheduler_reschedule,
+     &rc));
   rc = GNUNET_CURL_gnunet_rc_create (ctx);
-  exchange = TALER_EXCHANGE_connect (ctx,
-                                     EXCHANGE_URI,
-                                     &cert_cb, is,
-                                     TALER_EXCHANGE_OPTION_END);
-  GNUNET_assert (NULL != exchange);
+  GNUNET_assert (NULL != (exchange
+    = TALER_EXCHANGE_connect (ctx,
+                              EXCHANGE_URI,
+                              &cert_cb, is,
+                              TALER_EXCHANGE_OPTION_END)));
   timeout_task
     = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
-                                    (GNUNET_TIME_UNIT_SECONDS, 150),
+                                   (GNUNET_TIME_UNIT_SECONDS, 150),
                                     &do_timeout, NULL);
   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, is);
 }
@@ -2772,13 +2830,13 @@ main (int argc,
                  GNUNET_CONFIGURATION_load (cfg,
                                             "test_merchant_api.conf"));
   GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CONFIGURATION_get_value_string (cfg,
-                                                        "merchant",
-                                                        "INSTANCES",
-                                                        &_instances));
-  fprintf (stderr,
-           "Found instances `%s'\n",
-           _instances);
+    GNUNET_CONFIGURATION_get_value_string (cfg,
+                                           "merchant",
+                                           "INSTANCES",
+                                           &_instances));
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Found instances `%s'\n",
+              _instances);
   GNUNET_break (NULL != (token = strtok (_instances, " ")));
   GNUNET_array_append (instances,
                        ninstances,
@@ -2803,84 +2861,84 @@ main (int argc,
     GNUNET_CONFIGURATION_destroy (cfg);
     return 77;
   }
-  proc = GNUNET_OS_start_process (GNUNET_NO,
-                                  GNUNET_OS_INHERIT_STD_ALL,
-                                  NULL, NULL, NULL,
-                                  "taler-exchange-keyup",
-                                  "taler-exchange-keyup",
-                                  "-c", "test_merchant_api.conf",
-                                  NULL);
-  if (NULL == proc)
+  if (NULL == (proc = GNUNET_OS_start_process
+       (GNUNET_NO,
+        GNUNET_OS_INHERIT_STD_ALL,
+        NULL, NULL, NULL,
+        "taler-exchange-keyup",
+        "taler-exchange-keyup",
+        "-c", "test_merchant_api.conf",
+        NULL)))
   {
-    fprintf (stderr,
-             "Failed to run taler-exchange-keyup. Check your PATH.\n");
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Failed to run taler-exchange-keyup. Check your PATH.\n");
     return 77;
   }
   GNUNET_OS_process_wait (proc);
   GNUNET_OS_process_destroy (proc);
-  proc = GNUNET_OS_start_process (GNUNET_NO,
-                                  GNUNET_OS_INHERIT_STD_ALL,
-                                  NULL, NULL, NULL,
-                                  "taler-exchange-dbinit",
-                                  "taler-exchange-dbinit",
-                                  "-c", "test_merchant_api.conf",
-                                  "-r",
-                                  NULL);
-  if (NULL == proc)
+  if (NULL == (proc = GNUNET_OS_start_process
+       (GNUNET_NO,
+        GNUNET_OS_INHERIT_STD_ALL,
+        NULL, NULL, NULL,
+        "taler-exchange-dbinit",
+        "taler-exchange-dbinit",
+        "-c", "test_merchant_api.conf",
+        "-r",
+        NULL)))
   {
-    fprintf (stderr,
-             "Failed to run taler-exchange-dbinit. Check your PATH.\n");
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Failed to run taler-exchange-dbinit. Check your PATH.\n");
     return 77;
   }
   GNUNET_OS_process_wait (proc);
   GNUNET_OS_process_destroy (proc);
-  exchanged = GNUNET_OS_start_process (GNUNET_NO,
-                                       GNUNET_OS_INHERIT_STD_ALL,
-                                       NULL, NULL, NULL,
-                                       "taler-exchange-httpd",
-                                       "taler-exchange-httpd",
-                                       "-c", "test_merchant_api.conf",
-                                       NULL);
-  if (NULL == exchanged)
+  if (NULL == (exchanged = GNUNET_OS_start_process
+       (GNUNET_NO,
+        GNUNET_OS_INHERIT_STD_ALL,
+        NULL, NULL, NULL,
+        "taler-exchange-httpd",
+        "taler-exchange-httpd",
+        "-c", "test_merchant_api.conf",
+        NULL)))
   {
-    fprintf (stderr,
-             "Failed to run taler-exchange-httpd. Check your PATH.\n");
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Failed to run taler-exchange-httpd. Check your PATH.\n");
     return 77;
   }
   /* give child time to start and bind against the socket */
-  fprintf (stderr,
-           "Waiting for taler-exchange-httpd to be ready\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Waiting for taler-exchange-httpd to be ready\n");
   cnt = 0;
   do
+  {
+    fprintf (stderr, ".");
+    sleep (1);
+    cnt++;
+    if (cnt > 60)
     {
-      fprintf (stderr, ".");
-      sleep (1);
-      cnt++;
-      if (cnt > 60)
-      {
-        fprintf (stderr,
-                 "\nFailed to start taler-exchange-httpd\n");
-        GNUNET_OS_process_kill (exchanged,
-                                SIGKILL);
-        GNUNET_OS_process_wait (exchanged);
-        GNUNET_OS_process_destroy (exchanged);
-        return 77;
-      }
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "\nFailed to start taler-exchange-httpd\n");
+      GNUNET_OS_process_kill (exchanged,
+                              SIGKILL);
+      GNUNET_OS_process_wait (exchanged);
+      GNUNET_OS_process_destroy (exchanged);
+      return 77;
     }
+  }
   while (0 != system ("wget -q -t 1 -T 1 " EXCHANGE_URI "keys -o /dev/null -O 
/dev/null"));
   fprintf (stderr, "\n");
-  merchantd = GNUNET_OS_start_process (GNUNET_NO,
-                                       GNUNET_OS_INHERIT_STD_ALL,
-                                       NULL, NULL, NULL,
-                                       "taler-merchant-httpd",
-                                       "taler-merchant-httpd",
-                                       "-c", "test_merchant_api.conf",
-                                       "-L", "DEBUG",
-                                       NULL);
-  if (NULL == merchantd)
+  if (NULL == (merchantd = GNUNET_OS_start_process
+       (GNUNET_NO,
+        GNUNET_OS_INHERIT_STD_ALL,
+        NULL, NULL, NULL,
+        "taler-merchant-httpd",
+        "taler-merchant-httpd",
+        "-c", "test_merchant_api.conf",
+        "-L", "DEBUG",
+        NULL)))
   {
-    fprintf (stderr,
-             "Failed to run taler-merchant-httpd. Check your PATH.\n");
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Failed to run taler-merchant-httpd. Check your PATH.\n");
     GNUNET_OS_process_kill (exchanged,
                             SIGKILL);
     GNUNET_OS_process_wait (exchanged);
@@ -2888,37 +2946,38 @@ main (int argc,
     return 77;
   }
   /* give child time to start and bind against the socket */
-  fprintf (stderr,
-           "Waiting for taler-merchant-httpd to be ready\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Waiting for taler-merchant-httpd to be ready\n");
   cnt = 0;
   do
+  {
+    fprintf (stderr, ".");
+    sleep (1);
+    cnt++;
+    if (cnt > 60)
     {
-      fprintf (stderr, ".");
-      sleep (1);
-      cnt++;
-      if (cnt > 60)
-      {
-        fprintf (stderr,
-                 "\nFailed to start taler-merchant-httpd\n");
-        GNUNET_OS_process_kill (merchantd,
-                                SIGKILL);
-        GNUNET_OS_process_wait (merchantd);
-        GNUNET_OS_process_destroy (merchantd);
-        GNUNET_OS_process_kill (exchanged,
-                                SIGKILL);
-        GNUNET_OS_process_wait (exchanged);
-        GNUNET_OS_process_destroy (exchanged);
-        return 77;
-      }
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "\nFailed to start taler-merchant-httpd\n");
+      GNUNET_OS_process_kill (merchantd,
+                              SIGKILL);
+      GNUNET_OS_process_wait (merchantd);
+      GNUNET_OS_process_destroy (merchantd);
+      GNUNET_OS_process_kill (exchanged,
+                              SIGKILL);
+      GNUNET_OS_process_wait (exchanged);
+      GNUNET_OS_process_destroy (exchanged);
+      return 77;
     }
+  }
   while (0 != system ("wget -q -t 1 -T 1 " MERCHANT_URI " -o /dev/null -O 
/dev/null"));
   fprintf (stderr, "\n");
 
   result = GNUNET_SYSERR;
-  sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
-  GNUNET_assert (NULL != sigpipe);
-  shc_chld = GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD,
-                                            &sighandler_child_death);
+  GNUNET_assert (NULL != (sigpipe = GNUNET_DISK_pipe
+    (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO)));
+  shc_chld = GNUNET_SIGNAL_handler_install
+    (GNUNET_SIGCHLD,
+     &sighandler_child_death);
   GNUNET_SCHEDULER_run (&run, NULL);
   GNUNET_SIGNAL_handler_uninstall (shc_chld);
   shc_chld = NULL;
diff --git a/src/lib/test_merchant_api.conf b/src/lib/test_merchant_api.conf
index 5e72ed0..a01c4e0 100644
--- a/src/lib/test_merchant_api.conf
+++ b/src/lib/test_merchant_api.conf
@@ -21,8 +21,7 @@ PORT = 8082
 
 # How quickly do we want the exchange to send us our money?
 # Used only if the frontend does not specify a value.
-# FIXME: EDATE is a bit short, 'execution_delay'?
-EDATE = 3 week
+WIRE_TRANSFER_DELAY = 0 s
 
 # Which plugin (backend) do we use for the DB.
 DB = postgres
diff --git a/src/merchant-tools/taler-merchant-generate-payments.c 
b/src/merchant-tools/taler-merchant-generate-payments.c
index 8ba3704..bf5ecad 100644
--- a/src/merchant-tools/taler-merchant-generate-payments.c
+++ b/src/merchant-tools/taler-merchant-generate-payments.c
@@ -781,11 +781,18 @@ make_order (char *maxfee,
   json_t *maxfee_j;
   json_t *ret;
   unsigned long long id;
+  struct GNUNET_TIME_Absolute now;
+  char *timestamp;
 
   TALER_string_to_amount (maxfee, &tmp_amount);
   maxfee_j = TALER_JSON_from_amount (&tmp_amount);
   TALER_string_to_amount (total, &tmp_amount);
   total_j = TALER_JSON_from_amount (&tmp_amount);
+  now = GNUNET_TIME_absolute_get ();
+
+  GNUNET_asprintf (&timestamp,
+                   "/Date(%u)/",
+                   now.abs_value_us / 1000LL / 1000LL);
 
   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
                               &id,
@@ -793,7 +800,7 @@ make_order (char *maxfee,
   ret = json_pack ("{s:o, s:s, s:s, s:s, s:s, s:o, s:s, s:[{s:s}]}",
                    "max_fee", maxfee_j,
                    "order_id", TALER_b2s (&id, sizeof (id)),
-                   "timestamp", "/Date(42)/",
+                   "timestamp", timestamp,
                    "refund_deadline", "/Date(0)/",
                    "pay_deadline", "/Date(9999999999)/",
                    "amount", total_j,

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



reply via email to

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