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 (ecaa766 -> 5e2e443)


From: gnunet
Subject: [GNUnet-SVN] [taler-merchant] branch stable updated (ecaa766 -> 5e2e443)
Date: Thu, 06 Jul 2017 15:07:43 +0200

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

marcello pushed a change to branch stable
in repository merchant.

    from ecaa766  fix sign issue of 'start'
     add d71e90c  ChangeLog
     add c0fdf51  bumping versions for 0.3.0 release
     add 3611f39  design considerations for /refund support
     add 88d6efd  adding function getting refund data
     add 190d229  comments + passing refund reason to refund cb
     add a1fc2db  fix refund cb call
     add 2aab5f3  refund fee stored along deposit
     add 55e0f37  fix "insufficient data left in message" from Postgresql
     add de160b1  get refunds from database, only testing for zero rows 
returned.
     add 3c04b2a  increase_refund_for_contract skeleton
     add ea11919  call increase_refund_for_contract skeleton from testcase, 
obviously failing.
     add 51add29  refund_fee is returned to the callback when fetching a 
deposit from the db.
     add d1f504a  add prepared statement to fetch per coin information about 
refund
     add 37d74d4  fix lib testcase
     add 05ccc45  Get testcase pass using ORDER BY
     add cac9a38  fix warnings
     add 1e2adf9  add loop over result of refunding information
     add 6cd589f  comment
     add dd678e5  add start, commit, rollback db transactions
     add d3d70ff  SELECT refunds + nested loops to fetch per-coin situation 
about refunds.
     add c139ab0  diagnostics
     add b43ad07  comment
     add b606c98  make db testcase fail, as a reminder of refund logic 
incomplete.
     add e90fc12  move code towards more modern PQ API
     add 101b493  match rename in GNUnet API
     add c08137c  make adjustments to fakebank API change
     add 03e99d9  math around refunds
     add 19a4be3  inserting refunds into their table, not tested
     add ceef3f9  SQL syntax
     add 98c381c  comments, plus invalidating testcase as reminder of 
unimplemented logic
     add b2a21b2  calling insert_refund, fail with "insufficient data left in 
message"
     add 5cbd6cb  fix table definition
     add 48064a2  fix check of db returned status (INSERT returns 1)
     add 3f550d5  drop refund table
     add d9180c8  fix detection of subsequent refunds lesser thatn previous 
ones.
     add 6efeffd  logging
     add bd79ca8  - only commit refund if amount refunded per coin is > zero - 
add valid second refund increasing
     add f432e22  Add error when coins are not sufficient to pay a refund back.
     add 6520fde  backend /refund handler skeleton, not in compilation
     add 4d16ae5  add refund header file
     add b98a6a4  refund table takes merchant public key too
     add e486247  add /refund route
     add 4432516  Implementing POST /refund logic.
     add b622a7f  ~70% of GET /refund
     add e5d817e  Completing GET /refund logic - NOT tested.
     add dd10181  ~25% of /refund lib
     add 8ef1f72  Getting /refund lib to compile
     add a6b996f  /refund lib, issuing the POST and defining cb skeleton
     add 80434f9  add /refund cancel function
     add 46dccc5  80% GET /refund logic
     add 6f0813a  handler for /GET refund
     add 99307c1  finishing with /refund handlers
     add 8bfff6a  defining /refund testcases data structs
     add 45b9b9a  /refund test op codes
     add 5a8bf79  get refund increase test compiled
     add 870ca3f  get /refund increase requested from the tests
     add f48df59  Return a signed confirmation of the refund
     add 141807f  fix non returning testcase
     add 480d1ea  Up to the point where /refund (increase) passes BUT db hangs 
upon dropping tables..
     add 3322051  fix hanging db
     add b80c3d7  refund fee columnt into refund table, breaks db tests
     add 37c253b  fix db
     add 01feaab  Fix /refund lookup response encoding
     add e35b364  diagnostics
     add f7a956b  diagnostics
     add 7612d3c  reject non increasing amounts
     add 81efb35  ChangeLog
     add 984e503  error message
     add 507eebd  caring about 'summary' field
     add a63f515  do use return value of iterate_instances()
     add 633a9b6  use default log level of WARNING
     add 2563686  handle '/' at end of URLs when composing http requests in 
libtalermerchant
     add a046360  ref bugnote
     add 90cf924  convert merchant postgres plugin (in large parts) to latest 
PQ API as part of #5010-fix
     add 7cbda83  remove dead macros
     add 9c9e6db  get rid of select *, remove fixme that is no longer needed
     add d1544d0  fix logical order of functions
     add 75187c5  more #5010-related work on backenddb
     add 34a76cc  more #5010-related work on backenddb testcase
     add 667763f  get backenddb tests to pass again
     add 735c6d7  no "hint" field in error
     add e92b10b  remove further occurrence of "hint"
     add 352d7a2  FIXME
     add c088c1d  fix fixme
     add bcd29d4  fixing misc. FIXMEs, some style issues, and mostly DB return 
value handling towards addressing #5010
     add 515e970  fix #5010 for /track/transfer
     add 5f211ad  fix last #5010 issues, including timeout of the generator
     add aa83a91  support VC checks (#5035)
     add d85a856  implement first part of #4943: persist wire transfer fees of 
exchange in DB
     add 4ea441b  fix two minor typos / build compatibiltiy issues
     add 909a9a2  fix #4955
     add e9ffab2  fix compiler warning
     add 8ef723b  First steps of #5087.
     add e01c68f  retrieve all data needed to test /refund response.
     add 430c95c  finally match /refund response data
     add aef6d79  testcase extracts merchant priv from config
     add 4fcf4d1  switch instance key too
     add 333ba7c  matching /refund response against merchant pub too
     add f9b77d3  comment
     add 3b2b43c  merge conflict resolution
     add 71d4d4c  moving definitions to header file
     add 15ff300  Finishing #5087.
     add 5e2e443  moving a 'PS' struct into exchange codebase

No new revisions were added by this update.

Summary of changes:
 ChangeLog                                          |   13 +
 configure.ac                                       |    2 +-
 doc/Makefile.am                                    |    6 +
 doc/version.texi                                   |    6 +-
 src/backend/Makefile.am                            |    4 +-
 src/backend/merchant.conf                          |    6 +
 src/backend/taler-merchant-httpd.c                 |  100 +-
 src/backend/taler-merchant-httpd.h                 |   23 +
 src/backend/taler-merchant-httpd_exchanges.c       |   66 +-
 src/backend/taler-merchant-httpd_history.c         |   79 +-
 src/backend/taler-merchant-httpd_mhd.c             |    8 +-
 src/backend/taler-merchant-httpd_parsing.c         |    8 +-
 src/backend/taler-merchant-httpd_pay.c             |  150 +-
 src/backend/taler-merchant-httpd_proposal.c        |   79 +-
 src/backend/taler-merchant-httpd_refund.c          |  498 +++++
 ...t-httpd_map.h => taler-merchant-httpd_refund.h} |   42 +-
 src/backend/taler-merchant-httpd_responses.c       |   50 +-
 src/backend/taler-merchant-httpd_responses.h       |   16 +-
 .../taler-merchant-httpd_track-transaction.c       |  247 ++-
 src/backend/taler-merchant-httpd_track-transfer.c  |  129 +-
 src/backenddb/Makefile.am                          |    2 +-
 src/backenddb/plugin_merchantdb_postgres.c         | 2041 +++++++++++++-------
 src/backenddb/test_merchantdb.c                    |  263 ++-
 src/include/taler_merchant_service.h               |   90 +-
 src/include/taler_merchantdb_plugin.h              |  196 +-
 src/lib/Makefile.am                                |    8 +-
 src/lib/merchant_api_common.c                      |   50 +
 src/lib/merchant_api_common.h                      |   36 +
 src/lib/merchant_api_history.c                     |   11 +-
 src/lib/merchant_api_pay.c                         |   13 +-
 src/lib/merchant_api_proposal.c                    |   30 +-
 src/lib/merchant_api_refund.c                      |  352 ++++
 src/lib/merchant_api_track_transaction.c           |    9 +-
 src/lib/merchant_api_track_transfer.c              |    9 +-
 src/lib/test_merchant_api.c                        |  643 ++++--
 .../taler-merchant-generate-payments.c             |   13 +-
 36 files changed, 3975 insertions(+), 1323 deletions(-)
 create mode 100644 src/backend/taler-merchant-httpd_refund.c
 rename src/backend/{taler-merchant-httpd_map.h => 
taler-merchant-httpd_refund.h} (60%)
 create mode 100644 src/lib/merchant_api_common.c
 create mode 100644 src/lib/merchant_api_common.h
 create mode 100644 src/lib/merchant_api_refund.c

diff --git a/ChangeLog b/ChangeLog
index 8ff267c..749eede 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+Thu Jun 22 15:12:37 CEST 2017
+        Implementing /refund
+
+Tue Jun  6 14:30:43 CEST 2017
+        Abstracting the response gotten from the exchange's tracking
+        API and relying it to the frontend.
+        A payment generator has been implemented so that the db can
+        easily be populated for testing purposes.
+        /history API now has the way to query from a starting base date
+        ahead into the future.
+        Memory leak fixes. -CG/MS
+       Releasing taler-merchant 0.3.0. -CG
+
 Mon Mar  6 17:57:51 CET 2017
        Add support for wire fee calculations to /pay handling (#4935),
        and adding setting "max_wire_fee" and "wire_fee_amortization"
diff --git a/configure.ac b/configure.ac
index 5378a99..11afa00 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@
 # This configure file is in the public domain
 
 AC_PREREQ([2.69])
-AC_INIT([taler-merchant], [0.2.0], address@hidden)
+AC_INIT([taler-merchant], [0.3.0], address@hidden)
 AC_CONFIG_SRCDIR([src/backend/taler-merchant-httpd.c])
 AC_CONFIG_HEADERS([taler_merchant_config.h])
 # support for non-recursive builds
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 86e8e65..5155926 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -11,3 +11,9 @@ arch.jpg: arch.dot
 
 info_TEXINFOS = manual.texi
 manual_TEXINFOS = version.texi
+
+EXTRA_DIST = \
+  arch.dot \
+  lgpl.texi \
+  agpl.texi \
+  fdl-1.3.texi
diff --git a/doc/version.texi b/doc/version.texi
index b4f9054..fc2400a 100644
--- a/doc/version.texi
+++ b/doc/version.texi
@@ -1,4 +1,4 @@
address@hidden UPDATED 3 June 2017
address@hidden UPDATED 7 June 2017
 @set UPDATED-MONTH June 2017
address@hidden EDITION 0.2.0
address@hidden VERSION 0.2.0
address@hidden EDITION 0.3.0
address@hidden VERSION 0.3.0
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am
index c635ef0..1233ba8 100644
--- a/src/backend/Makefile.am
+++ b/src/backend/Makefile.am
@@ -13,6 +13,7 @@ bin_PROGRAMS = \
   taler-merchant-httpd
 
 taler_merchant_httpd_SOURCES = \
+  taler-merchant-httpd_map.h \
   taler-merchant-httpd.c taler-merchant-httpd.h \
   taler-merchant-httpd_parsing.c taler-merchant-httpd_parsing.h \
   taler-merchant-httpd_responses.c taler-merchant-httpd_responses.h \
@@ -23,7 +24,8 @@ taler_merchant_httpd_SOURCES = \
   taler-merchant-httpd_pay.c taler-merchant-httpd_pay.h \
   taler-merchant-httpd_history.c taler-merchant-httpd_history.h \
   taler-merchant-httpd_track-transaction.c 
taler-merchant-httpd_track-transaction.h \
-  taler-merchant-httpd_track-transfer.c taler-merchant-httpd_track-transfer.h
+  taler-merchant-httpd_track-transfer.c taler-merchant-httpd_track-transfer.h \
+  taler-merchant-httpd_refund.c taler-merchant-httpd_refund.h
 
 
 taler_merchant_httpd_LDADD = \
diff --git a/src/backend/merchant.conf b/src/backend/merchant.conf
index 5511787..5e16ef1 100644
--- a/src/backend/merchant.conf
+++ b/src/backend/merchant.conf
@@ -45,8 +45,14 @@ WIREFORMAT = test
 # Determines which wire plugin will be used. We currently only
 # support one wire plugin at a time!
 
+# How long do we want the exchange to sit on wire transfers
+# for aggregation?
 WIRE_TRANSFER_DELAY = 3 week
 
+# How fast do we want customers to pay, i.e. how long will our
+# proposal be valid?
+DEFAULT_PAY_DEADLINE = 1 day
+
 # Configuration for postgres database.
 [merchantdb-postgres]
 CONFIG = postgres:///talermerchant
diff --git a/src/backend/taler-merchant-httpd.c 
b/src/backend/taler-merchant-httpd.c
index 0efa7eb..437537d 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -40,7 +40,7 @@
 #include "taler-merchant-httpd_track-transaction.h"
 #include "taler-merchant-httpd_track-transfer.h"
 #include "taler-merchant-httpd_history.h"
-#include "taler-merchant-httpd_map.h"
+#include "taler-merchant-httpd_refund.h"
 
 /**
  * Backlog for listen operation on unix-domain sockets.
@@ -73,6 +73,12 @@ static long long unsigned port;
 struct GNUNET_TIME_Relative wire_transfer_delay;
 
 /**
+ * If the frontend does NOT specify a payment deadline, how long should
+ * offers we make be valid by default?
+ */
+struct GNUNET_TIME_Relative default_pay_deadline;
+
+/**
  * Default maximum wire fee to assume, unless stated differently in the 
proposal
  * already.
  */
@@ -175,9 +181,6 @@ url_handler (void *cls,
       { "/", MHD_HTTP_METHOD_GET, "text/plain",
         "Hello, I'm a merchant's Taler backend. This HTTP server is not for 
humans.\n", 0,
         &TMH_MHD_handler_static_response, MHD_HTTP_OK },
-      { "/proposal", MHD_HTTP_METHOD_POST, "application/json",
-        NULL, 0,
-        &MH_handler_proposal_put, MHD_HTTP_OK },
       { "/pay", MHD_HTTP_METHOD_POST, "application/json",
         NULL, 0,
         &MH_handler_pay, MHD_HTTP_OK },
@@ -199,13 +202,24 @@ url_handler (void *cls,
       { "/history", MHD_HTTP_METHOD_GET, "text/plain",
         "Only GET is allowed", 0,
         &MH_handler_history, MHD_HTTP_OK},
+      { "/proposal", MHD_HTTP_METHOD_POST, "application/json",
+        NULL, 0,
+        &MH_handler_proposal_put, MHD_HTTP_OK },
       { "/proposal", MHD_HTTP_METHOD_GET, "text/plain",
-        "Only GET is allowed", 0,
+        NULL, 0,
         &MH_handler_proposal_lookup, MHD_HTTP_OK},
       { "/proposal", NULL, "text/plain",
         "Only GET/POST are allowed", 0,
         &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
+      { "/refund", MHD_HTTP_METHOD_POST, "application/json",
+        NULL, 0,
+        &MH_handler_refund_increase, MHD_HTTP_OK},
+      { "/refund", MHD_HTTP_METHOD_GET, "text/plain",
+        NULL, 0,
+        &MH_handler_refund_lookup, MHD_HTTP_OK},
+      { "/refund", NULL, "application/json",
+        "Only POST/GET are allowed", 0,
+        &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED},
       {NULL, NULL, NULL, NULL, 0, 0 }
     };
   static struct TMH_RequestHandler h404 =
@@ -214,28 +228,27 @@ url_handler (void *cls,
       "<html><title>404: not found</title></html>", 0,
       &TMH_MHD_handler_static_response, MHD_HTTP_NOT_FOUND
     };
-  struct TM_HandlerContext *hc;
-  struct TMH_RequestHandler *rh;
-  unsigned int i;
-  int ret;
-
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Handling request for URL `%s'\n",
               url);
-  for (i=0;NULL != handlers[i].url;i++)
+  for (unsigned int i=0;NULL != handlers[i].url;i++)
   {
-    rh = &handlers[i];
+    struct TMH_RequestHandler *rh = &handlers[i];
+    
     if ( (0 == strcasecmp (url,
                            rh->url)) &&
          ( (NULL == rh->method) ||
            (0 == strcasecmp (method,
                              rh->method)) ) )
     {
+      struct TM_HandlerContext *hc;
+      int ret;
+
       ret = rh->handler (rh,
-                         connection,
-                         con_cls,
-                         upload_data,
-                         upload_data_size);
+                        connection,
+                        con_cls,
+                        upload_data,
+                        upload_data_size);
       hc = *con_cls;
       if (NULL != hc)
         hc->rh = rh;
@@ -427,11 +440,12 @@ prepare_daemon ()
   GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Adding run_daemon select task\n");
-  ret =
-      GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
-                                  tv, wrs, wws,
-                                   &run_daemon,
-                                   NULL);
+  ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
+                                    tv,
+                                    wrs,
+                                    wws,
+                                    &run_daemon,
+                                    NULL);
   GNUNET_NETWORK_fdset_destroy (wrs);
   GNUNET_NETWORK_fdset_destroy (wws);
   return ret;
@@ -633,7 +647,7 @@ TMH_lookup_instance (const char *name)
  * a wrong instance
  */
 struct MerchantInstance *
-get_instance (struct json_t *json)
+TMH_lookup_instance_json (struct json_t *json)
 {
   struct json_t *instance;
   const char *instance_str;
@@ -655,7 +669,7 @@ get_instance (struct json_t *json)
  * @return #GNUNET_OK if successful, #GNUNET_SYSERR upon errors
  * (for example, if no "default" instance is defined)
  */
-static unsigned int
+static int
 iterate_instances (const struct GNUNET_CONFIGURATION_Handle *config,
                    const char *allowed)
 {
@@ -708,14 +722,11 @@ iterate_instances (const struct 
GNUNET_CONFIGURATION_Handle *config,
   return GNUNET_OK;
 
  fail:
-  do {
-    GNUNET_PLUGIN_unload (lib_name,
-                          iic->plugin);
-    GNUNET_free (lib_name);
-    GNUNET_free (iic);
-    GNUNET_SCHEDULER_shutdown ();
-    return GNUNET_SYSERR;
-  } while (0);
+  GNUNET_PLUGIN_unload (lib_name,
+                       iic->plugin);
+  GNUNET_free (lib_name);
+  GNUNET_free (iic);
+  return GNUNET_SYSERR;
 }
 
 
@@ -742,7 +753,7 @@ run (void *cls,
                                  NULL);
   GNUNET_assert (GNUNET_OK ==
                  GNUNET_log_setup ("taler-merchant-httpd",
-                                   "DEBUG",
+                                   "WARNING",
                                    NULL));
   if (GNUNET_SYSERR ==
       TMH_EXCHANGES_init (config))
@@ -784,6 +795,19 @@ run (void *cls,
     return;
   }
 
+  if (GNUNET_SYSERR ==
+      GNUNET_CONFIGURATION_get_value_time (config,
+                                           "merchant",
+                                           "DEFAULT_PAY_DEADLINE",
+                                           &default_pay_deadline))
+  {
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               "merchant",
+                               "DEFAULT_PAY_DEADLINE");
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+
   if (GNUNET_OK !=
       TALER_config_get_denom (config,
                               "merchant",
@@ -845,8 +869,14 @@ run (void *cls,
     GNUNET_SCHEDULER_shutdown ();
     return;
   }
-  iterate_instances (config,
-                     wireformat);
+  if (GNUNET_OK !=
+      iterate_instances (config,
+                        wireformat))
+  {
+    GNUNET_free (wireformat);
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
   GNUNET_free (wireformat);
 
   if (NULL ==
diff --git a/src/backend/taler-merchant-httpd.h 
b/src/backend/taler-merchant-httpd.h
index 0526ad2..c67a971 100644
--- a/src/backend/taler-merchant-httpd.h
+++ b/src/backend/taler-merchant-httpd.h
@@ -269,6 +269,12 @@ extern struct TALER_MERCHANTDB_Plugin *db;
 extern struct GNUNET_TIME_Relative wire_transfer_delay;
 
 /**
+ * If the frontend does NOT specify a payment deadline, how long should
+ * offers we make be valid by default?
+ */
+extern struct GNUNET_TIME_Relative default_pay_deadline;
+
+/**
  * Kick MHD to run now, to be called after MHD_resume_connection().
  * Basically, we need to explicitly resume MHD's event loop whenever
  * we made progress serving a request.  This function re-schedules
@@ -287,4 +293,21 @@ struct MerchantInstance *
 TMH_lookup_instance (const char *name);
 
 
+/**
+ * Extract merchant instance from the given JSON
+ *
+ * @param json the JSON to inspect; it is not required to
+ * comply with any particular format. It will only be checked
+ * if the field "instance" is there.
+ * @return a pointer to a #struct MerchantInstance. This will be
+ * the 'default' merchant if the frontend did not specif any
+ * "instance" field. The user should not care to free the returned
+ * value, as it is taken from a global array that will be freed
+ * by the general shutdown routine. NULL if the frontend specified
+ * a wrong instance
+ */
+struct MerchantInstance *
+TMH_lookup_instance_json (struct json_t *json);
+
+
 #endif
diff --git a/src/backend/taler-merchant-httpd_exchanges.c 
b/src/backend/taler-merchant-httpd_exchanges.c
index 3883d57..a011be4 100644
--- a/src/backend/taler-merchant-httpd_exchanges.c
+++ b/src/backend/taler-merchant-httpd_exchanges.c
@@ -255,10 +255,12 @@ json_t *trusted_exchanges;
  *   in order to get the "good" keys.
  * @param keys information about the various keys used
  *        by the exchange
+ * @param compat version compatibility data
  */
 static void
 keys_mgmt_cb (void *cls,
-              const struct TALER_EXCHANGE_Keys *keys);
+              const struct TALER_EXCHANGE_Keys *keys,
+             enum TALER_EXCHANGE_VersionCompatibility compat);
 
 
 /**
@@ -339,15 +341,36 @@ process_wire_fees (void *cls,
   }
   while (NULL != fees)
   {
+    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);
+    qs = db->store_wire_fee_by_exchange (db->cls,
+                                        &exchange->master_pub,
+                                        &h_wire_method,
+                                        &af->wire_fee,
+                                        &af->closing_fee,
+                                        af->start_date,
+                                        af->end_date,
+                                        &af->master_sig);
+    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;
     else
       endp->next = af;
     endp = af;
-    // FIXME: also preserve `fees` in backend DB (under wire method + exchange 
master pub!)
     fees = fees->next;
   }
 }
@@ -398,14 +421,15 @@ get_wire_fees (struct Exchange *exchange,
 static int
 process_find_operations (struct Exchange *exchange)
 {
-  struct TMH_EXCHANGES_FindOperation *fo;
   struct TMH_EXCHANGES_FindOperation *fn;
   struct GNUNET_TIME_Absolute now;
   int need_wire;
 
   now = GNUNET_TIME_absolute_get ();
   need_wire = GNUNET_NO;
-  for (fo = exchange->fo_head; NULL != fo; fo = fn)
+  for (struct TMH_EXCHANGES_FindOperation *fo = exchange->fo_head;
+       NULL != fo;
+       fo = fn)
   {
     const struct TALER_Amount *wire_fee;
 
@@ -588,10 +612,12 @@ wire_task_cb (void *cls)
  *   in order to get the "good" keys.
  * @param keys information about the various keys used
  *        by the exchange
+ * @param compat version compatibility data
  */
 static void
 keys_mgmt_cb (void *cls,
-              const struct TALER_EXCHANGE_Keys *keys)
+              const struct TALER_EXCHANGE_Keys *keys,
+             enum TALER_EXCHANGE_VersionCompatibility compat)
 {
   struct Exchange *exchange = cls;
   struct GNUNET_TIME_Absolute expire;
@@ -610,6 +636,14 @@ keys_mgmt_cb (void *cls,
       GNUNET_SCHEDULER_cancel (exchange->wire_task);
       exchange->wire_task = NULL;
     }
+    if (TALER_EXCHANGE_VC_INCOMPATIBLE_NEWER == compat)
+    {
+      /* Give up, log hard error. */
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 "Exchange `%s' runs an incompatible more recent version of 
the Taler protocol. Will not retry. This client may need to be updated.\n",
+                 exchange->uri);
+      return;
+    }
     exchange->retry_delay = RETRY_BACKOFF (exchange->retry_delay);
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                 "Failed to fetch /keys from `%s', retrying in %s\n",
@@ -621,6 +655,19 @@ keys_mgmt_cb (void *cls,
                                                          exchange);
     return;
   }
+  if (0 != (TALER_EXCHANGE_VC_NEWER & compat))
+  {
+    /* Warn user exactly once about need to upgrade */
+    static int once;
+
+    if (0 == once)
+    {
+      once = 1;
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                 "Exchange `%s' runs a more recent version of the Taler 
protocol. You may want to update this client.\n",
+                 exchange->uri);
+    }
+  }
   expire = TALER_EXCHANGE_check_keys_current (exchange->conn);
   if (0 == expire.abs_value_us)
     delay = RELOAD_DELAY;
@@ -887,9 +934,6 @@ accept_exchanges (void *cls,
 int
 TMH_EXCHANGES_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
-  struct Exchange *exchange;
-  json_t *j_exchange;
-
   merchant_curl_ctx
     = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
                         &merchant_curl_rc);
@@ -905,8 +949,12 @@ TMH_EXCHANGES_init (const struct 
GNUNET_CONFIGURATION_Handle *cfg)
                                          (void *) cfg);
   /* build JSON with list of trusted exchanges (will be included in contracts) 
*/
   trusted_exchanges = json_array ();
-  for (exchange = exchange_head; NULL != exchange; exchange = exchange->next)
+  for (struct Exchange *exchange = exchange_head;
+       NULL != exchange;
+       exchange = exchange->next)
   {
+    json_t *j_exchange;
+
     if (GNUNET_YES != exchange->trusted)
       continue;
     j_exchange = json_pack ("{s:s, s:o}",
diff --git a/src/backend/taler-merchant-httpd_history.c 
b/src/backend/taler-merchant-httpd_history.c
index 4ad6a26..9d6459e 100644
--- a/src/backend/taler-merchant-httpd_history.c
+++ b/src/backend/taler-merchant-httpd_history.c
@@ -45,23 +45,26 @@ pd_cb (void *cls,
   json_t *amount;
   json_t *timestamp;
   json_t *instance;
+  json_t *summary;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "/history's row_id: %llu\n",
               (unsigned long long) row_id);
 
   GNUNET_assert (-1 != json_unpack ((json_t *) contract_terms,
-                                    "{s:o, s:o, s:{s:o}}",
+                                    "{s:o, s:o, s:{s:o}, s:o}",
                                     "amount", &amount,
                                     "timestamp", &timestamp,
-                                    "merchant", "instance", &instance));
+                                    "merchant", "instance", &instance,
+                                    "summary", &summary));
 
-  GNUNET_break (NULL != (entry = json_pack ("{s:I, s:s, s:O, s:O, s:O}",
+  GNUNET_break (NULL != (entry = json_pack ("{s:I, s:s, s:O, s:O, s:O, s:O}",
                                             "row_id", row_id,
                                             "order_id", order_id,
                                             "amount", amount,
                                             "timestamp", timestamp,
-                                            "instance", instance)));
+                                            "instance", instance,
+                                            "summary", summary)));
 
   GNUNET_break (0 == json_array_append_new (response,
                                             entry));
@@ -90,11 +93,12 @@ MH_handler_history (struct TMH_RequestHandler *rh,
   const char *str;
   struct GNUNET_TIME_Absolute date;
   json_t *response;
-  unsigned int ret;
+  int ret;
   unsigned long long seconds;
   struct MerchantInstance *mi;
   int start = -1;
   unsigned int delta;
+  enum GNUNET_DB_QueryStatus qs;
 
   response = json_array ();
   str = MHD_lookup_connection_value (connection,
@@ -104,7 +108,9 @@ MH_handler_history (struct TMH_RequestHandler *rh,
 
   if (NULL != str)
   {
-    if (1 != sscanf (str, "%llu", &seconds))
+    if (1 != sscanf (str,
+                    "%llu",
+                    &seconds))
     {
       json_decref (response);
       return TMH_RESPONSE_reply_arg_invalid (connection,
@@ -144,13 +150,17 @@ MH_handler_history (struct TMH_RequestHandler *rh,
 
   if (NULL != str)
   {
-
-    ret = db->find_contract_terms_history (db->cls,
-                                           str,
-                                           &mi->pubkey,
-                                           &pd_cb,
-                                           response);
-    if (GNUNET_SYSERR == ret)
+    qs = db->find_contract_terms_history (db->cls,
+                                         str,
+                                         &mi->pubkey,
+                                         &pd_cb,
+                                         response);
+    /* 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)
     {
       json_decref (response);
       return TMH_RESPONSE_reply_internal_error (connection,
@@ -171,7 +181,9 @@ MH_handler_history (struct TMH_RequestHandler *rh,
                                      "start");
   if (NULL != str)
   {
-    if ( (1 != sscanf (str, "%d", &start)) ||
+    if ( (1 != sscanf (str,
+                      "%d",
+                      &start)) ||
          (0 > start) )
     {
       json_decref (response);
@@ -187,7 +199,9 @@ MH_handler_history (struct TMH_RequestHandler *rh,
 
   if (NULL != str)
   {
-    if (1 != sscanf (str, "%u", &delta))
+    if (1 != sscanf (str,
+                    "%u",
+                    &delta))
       return TMH_RESPONSE_reply_arg_invalid (connection,
                                              TALER_EC_PARAMETER_MALFORMED,
                                              "delta");
@@ -199,23 +213,28 @@ MH_handler_history (struct TMH_RequestHandler *rh,
               delta);
 
   if (0 > start)
-    ret = db->find_contract_terms_by_date (db->cls,
-                                           date,
-                                           &mi->pubkey,
-                                           delta,
-                                           &pd_cb,
-                                           response);
+    qs = db->find_contract_terms_by_date (db->cls,
+                                         date,
+                                         &mi->pubkey,
+                                         delta,
+                                         &pd_cb,
+                                         response);
   else
-    ret = db->find_contract_terms_by_date_and_range (db->cls,
-                                                     date,
-                                                     &mi->pubkey,
-                                                     (unsigned int) start,
-                                                     delta,
-                                                     GNUNET_NO,
-                                                     &pd_cb,
-                                                     response);
-  if (GNUNET_SYSERR == ret)
+    qs = db->find_contract_terms_by_date_and_range (db->cls,
+                                                   date,
+                                                   &mi->pubkey,
+                                                   (unsigned int) start,
+                                                   delta,
+                                                   GNUNET_NO,
+                                                   &pd_cb,
+                                                   response);
+  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);
     json_decref (response);
     return TMH_RESPONSE_reply_internal_error (connection,
                                              TALER_EC_HISTORY_DB_FETCH_ERROR,
diff --git a/src/backend/taler-merchant-httpd_mhd.c 
b/src/backend/taler-merchant-httpd_mhd.c
index 9debb67..e4e5329 100644
--- a/src/backend/taler-merchant-httpd_mhd.c
+++ b/src/backend/taler-merchant-httpd_mhd.c
@@ -146,10 +146,10 @@ TMH_MHD_handler_send_json_pack_error (struct 
TMH_RequestHandler *rh,
                                          size_t *upload_data_size)
 {
   return TMH_RESPONSE_reply_json_pack (connection,
-                                     rh->response_code,
-                                     "{s:s}",
-                                     "error",
-                                     rh->data);
+                                       rh->response_code,
+                                       "{s:s}",
+                                       "error",
+                                       rh->data);
 }
 
 
diff --git a/src/backend/taler-merchant-httpd_parsing.c 
b/src/backend/taler-merchant-httpd_parsing.c
index 754ea90..f04313a 100644
--- a/src/backend/taler-merchant-httpd_parsing.c
+++ b/src/backend/taler-merchant-httpd_parsing.c
@@ -133,6 +133,7 @@ buffer_append (struct Buffer *buf,
   {
     char *new_buf;
     size_t new_size = buf->alloc ? buf->alloc : 1;
+    
     while (new_size < buf->fill + data_size)
       new_size *= 2;
     if (new_size > max_size)
@@ -143,7 +144,9 @@ buffer_append (struct Buffer *buf,
     buf->data = new_buf;
     buf->alloc = new_size;
   }
-  memcpy (buf->data + buf->fill, data, data_size);
+  memcpy (buf->data + buf->fill,
+         data,
+         data_size);
   buf->fill += data_size;
   return GNUNET_OK;
 }
@@ -303,6 +306,9 @@ TMH_PARSE_json_data (struct MHD_Connection *connection,
   {
     if (NULL == error_json_name)
       error_json_name = "<no field>";
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Parsing failed due to field '%s'\n",
+                error_json_name);
     ret = (MHD_YES ==
            TMH_RESPONSE_reply_json_pack (connection,
                                          MHD_HTTP_BAD_REQUEST,
diff --git a/src/backend/taler-merchant-httpd_pay.c 
b/src/backend/taler-merchant-httpd_pay.c
index 837b17d..2e3767b 100644
--- a/src/backend/taler-merchant-httpd_pay.c
+++ b/src/backend/taler-merchant-httpd_pay.c
@@ -38,6 +38,10 @@
  */
 #define PAY_TIMEOUT (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 
30))
 
+/**
+ * How often do we retry the simple INSERT database transaction?
+ */
+#define MAX_RETRIES 3
 
 /**
  * Information we keep for an individual call to the /pay handler.
@@ -78,6 +82,11 @@ struct DepositConfirmation
   struct TALER_Amount deposit_fee;
 
   /**
+   * Fee charged by the exchange for the refund operation of this coin.
+   */
+  struct TALER_Amount refund_fee;
+
+  /**
    * Public key of the coin.
    */
   struct TALER_CoinSpendPublicKeyP coin_pub;
@@ -320,7 +329,9 @@ static struct PayContext *pc_tail;
 void
 MH_force_pc_resume ()
 {
-  for (struct PayContext *pc = pc_head; NULL != pc; pc = pc->next)
+  for (struct PayContext *pc = pc_head;
+       NULL != pc;
+       pc = pc->next)
   {
     if (GNUNET_YES == pc->suspended)
     {
@@ -370,11 +381,9 @@ resume_pay_with_response (struct PayContext *pc,
 static void
 abort_deposit (struct PayContext *pc)
 {
-  unsigned int i;
-
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Aborting pending /deposit operations\n");
-  for (i=0;i<pc->coins_cnt;i++)
+  for (unsigned int i;i<pc->coins_cnt;i++)
   {
     struct DepositConfirmation *dci = &pc->dc[i];
 
@@ -444,6 +453,7 @@ deposit_cb (void *cls,
 {
   struct DepositConfirmation *dc = cls;
   struct PayContext *pc = dc->pc;
+  enum GNUNET_DB_QueryStatus qs;
 
   dc->dh = NULL;
   pc->pending--;
@@ -488,18 +498,26 @@ deposit_cb (void *cls,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Storing successful payment for h_contract_terms '%s'\n",
               GNUNET_h2s (&pc->h_contract_terms));
-
-  if (GNUNET_OK !=
-      db->store_deposit (db->cls,
-                        &pc->h_contract_terms,
-                        &pc->mi->pubkey,
-                        &dc->coin_pub,
-                        &dc->amount_with_fee,
-                        &dc->deposit_fee,
-                         sign_key,
-                        proof))
+  for (unsigned int i=0;i<MAX_RETRIES;i++)
   {
-    GNUNET_break (0);
+    qs = db->store_deposit (db->cls,
+                           &pc->h_contract_terms,
+                           &pc->mi->pubkey,
+                           &dc->coin_pub,
+                           &dc->amount_with_fee,
+                           &dc->deposit_fee,
+                           &dc->refund_fee,
+                           sign_key,
+                           proof);
+    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);
     /* internal error */
     abort_deposit (pc);
     /* Forward error including 'proof' for the body */
@@ -662,6 +680,7 @@ process_pay_with_exchange (void *cls,
       return;
     }
     dc->deposit_fee = denom_details->fee_deposit;
+    dc->refund_fee = denom_details->fee_refund;
     if (0 == i)
     {
       acc_fee = denom_details->fee_deposit;
@@ -909,6 +928,7 @@ handle_pay_timeout (void *cls)
  * @param coin_pub public key of the coin
  * @param amount_with_fee amount the exchange will deposit for this coin
  * @param deposit_fee fee the exchange will charge for this coin
+ * @param refund_fee fee the exchange will charge for refunding this coin
  * @param exchange_proof proof from exchange that coin was accepted
  */
 static void
@@ -917,10 +937,10 @@ check_coin_paid (void *cls,
                  const struct TALER_CoinSpendPublicKeyP *coin_pub,
                  const struct TALER_Amount *amount_with_fee,
                  const struct TALER_Amount *deposit_fee,
+                 const struct TALER_Amount *refund_fee,
                  const json_t *exchange_proof)
 {
   struct PayContext *pc = cls;
-  unsigned int i;
 
   if (0 != memcmp (&pc->h_contract_terms,
                    h_contract_terms,
@@ -929,7 +949,7 @@ check_coin_paid (void *cls,
     GNUNET_break (0);
     return;
   }
-  for (i=0;i<pc->coins_cnt;i++)
+  for (unsigned int i=0;i<pc->coins_cnt;i++)
   {
     struct DepositConfirmation *dc = &pc->dc[i];
     /* Get matching coin from results*/
@@ -1000,11 +1020,6 @@ check_transaction_exists (void *cls,
 }
 
 
-// FIXME: declare in proper header!
-extern struct MerchantInstance *
-get_instance (struct json_t *json);
-
-
 /**
  * Try to parse the pay request into the given pay context.
  * Schedules an error response in the connection on failure.
@@ -1037,6 +1052,7 @@ parse_pay (struct MHD_Connection *connection,
     GNUNET_JSON_spec_fixed_auto ("merchant_pub", &merchant_pub),
     GNUNET_JSON_spec_end()
   };
+  enum GNUNET_DB_QueryStatus qs;
 
   res = TMH_PARSE_json_data (connection,
                              root,
@@ -1046,11 +1062,23 @@ parse_pay (struct MHD_Connection *connection,
     GNUNET_break (0);
     return res;
   }
-  res = db->find_contract_terms (db->cls,
+  qs = db->find_contract_terms (db->cls,
                                 &pc->contract_terms,
                                 order_id,
                                 &merchant_pub);
-  if (GNUNET_OK != res)
+  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_PAY_ERROR,
+                                             "db error to previous /pay data");
+
+  }
+  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
   {
     GNUNET_JSON_parse_free (spec);
     if (MHD_YES !=
@@ -1097,15 +1125,16 @@ parse_pay (struct MHD_Connection *connection,
     }
     return GNUNET_NO;
   }
-  pc->mi = get_instance (merchant);
+  pc->mi = TMH_lookup_instance_json (merchant);
   if (NULL == pc->mi)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Unable to find the specified instance\n");
     GNUNET_JSON_parse_free (spec);
-    if (MHD_NO == TMH_RESPONSE_reply_not_found (connection,
-                                                TALER_EC_PAY_INSTANCE_UNKNOWN,
-                                                "Unknown instance given"))
+    if (MHD_NO ==
+       TMH_RESPONSE_reply_not_found (connection,
+                                     TALER_EC_PAY_INSTANCE_UNKNOWN,
+                                     "Unknown instance given"))
     {
       GNUNET_break (0);
       return GNUNET_SYSERR;
@@ -1287,6 +1316,7 @@ handler_pay_json (struct MHD_Connection *connection,
                   struct PayContext *pc)
 {
   int ret;
+  enum GNUNET_DB_QueryStatus qs;
 
   ret = parse_pay (connection,
                    root,
@@ -1295,14 +1325,18 @@ handler_pay_json (struct MHD_Connection *connection,
     return (GNUNET_NO == ret) ? MHD_YES : MHD_NO;
 
   /* Check if this payment attempt has already succeeded */
-  if (GNUNET_SYSERR ==
-      db->find_payments (db->cls,
-                        &pc->h_contract_terms,
-                         &pc->mi->pubkey,
-                        &check_coin_paid,
-                        pc))
+  qs = db->find_payments (db->cls,
+                         &pc->h_contract_terms,
+                         &pc->mi->pubkey,
+                         &check_coin_paid,
+                         pc);
+  if (0 > qs)
   {
-    GNUNET_break (0);
+    /* 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");
@@ -1324,14 +1358,18 @@ handler_pay_json (struct MHD_Connection *connection,
     return ret;
   }
   /* Check if transaction is already known, if not store it. */
-  if (GNUNET_SYSERR ==
-      db->find_transaction (db->cls,
-                           &pc->h_contract_terms,
-                           &pc->mi->pubkey,
-                           &check_transaction_exists,
-                            pc))
+  qs = db->find_transaction (db->cls,
+                            &pc->h_contract_terms,
+                            &pc->mi->pubkey,
+                            &check_transaction_exists,
+                            pc);
+  if (0 > qs)
   {
-    GNUNET_break (0);
+    /* 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");
@@ -1369,17 +1407,25 @@ handler_pay_json (struct MHD_Connection *connection,
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Storing transaction '%s'\n",
                 GNUNET_h2s (&pc->h_contract_terms));
-    if (GNUNET_OK !=
-        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))
+    for (unsigned int i=0;i<MAX_RETRIES;i++)
     {
-      GNUNET_break (0);
+      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");
diff --git a/src/backend/taler-merchant-httpd_proposal.c 
b/src/backend/taler-merchant-httpd_proposal.c
index a431179..ae0c3dc 100644
--- a/src/backend/taler-merchant-httpd_proposal.c
+++ b/src/backend/taler-merchant-httpd_proposal.c
@@ -30,6 +30,12 @@
 
 
 /**
+ * How often do we retry the simple INSERT database transaction?
+ */
+#define MAX_RETRIES 3
+
+
+/**
  * Check that the given JSON array of products is well-formed.
  *
  * @param products JSON array to check
@@ -115,10 +121,6 @@ json_parse_cleanup (struct TM_HandlerContext *hc)
 }
 
 
-extern struct MerchantInstance *
-get_instance (struct json_t *json);
-
-
 /**
  * Transform an order into a proposal and store it in the database.
  * Write the resulting proposal or an error message ot a MHD connection
@@ -156,12 +158,12 @@ proposal_put (struct MHD_Connection *connection,
     GNUNET_JSON_spec_absolute_time ("pay_deadline", &pay_deadline),
     GNUNET_JSON_spec_end ()
   };
-
+  enum GNUNET_DB_QueryStatus qs;
 
   /* Add order_id if it doesn't exist. */
-
-  if (NULL == json_string_value (json_object_get (order,
-                                                  "order_id")))
+  if (NULL ==
+      json_string_value (json_object_get (order,
+                                         "order_id")))
   {
     char buf[256];
     time_t timer;
@@ -175,7 +177,8 @@ proposal_put (struct MHD_Connection *connection,
                     sizeof (buf),
                     "%H:%M:%S",
                     tm_info);
-    snprintf (buf + off, sizeof (buf) - off,
+    snprintf (buf + off,
+             sizeof (buf) - off,
               "-%llX",
               (long long unsigned) GNUNET_CRYPTO_random_u64 
(GNUNET_CRYPTO_QUALITY_WEAK,
                                                              UINT64_MAX));
@@ -210,8 +213,7 @@ proposal_put (struct MHD_Connection *connection,
   {
     struct GNUNET_TIME_Absolute t;
 
-    /* FIXME: read the delay for pay_deadline from config */
-    t = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS);
+    t = GNUNET_TIME_relative_to_absolute (default_pay_deadline);
     (void) GNUNET_TIME_round_abs (&t);
     json_object_set_new (order,
                          "pay_deadline",
@@ -258,7 +260,7 @@ proposal_put (struct MHD_Connection *connection,
                                           "order:products");
   }
 
-  mi = get_instance (merchant);
+  mi = TMH_lookup_instance_json (merchant);
   if (NULL == mi)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -299,22 +301,28 @@ proposal_put (struct MHD_Connection *connection,
                             &pdps.purpose,
                             &merchant_sig);
 
-  /* fetch timestamp from order */
-
-  if (GNUNET_OK !=
-      db->insert_contract_terms (db->cls,
-                                order_id,
-                                &mi->pubkey,
-                                timestamp,
-                                order))
+  for (unsigned int i=0;i<MAX_RETRIES;i++)
+  {
+    qs = db->insert_contract_terms (db->cls,
+                                   order_id,
+                                   &mi->pubkey,
+                                   timestamp,
+                                   order);
+    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);
     GNUNET_JSON_parse_free (spec);
     return TMH_RESPONSE_reply_internal_error (connection,
                                               TALER_EC_PROPOSAL_STORE_DB_ERROR,
                                               "db error: could not store this 
proposal's data into db");
   }
 
-
   res = TMH_RESPONSE_reply_json_pack (connection,
                                       MHD_HTTP_OK,
                                       "{s:O, s:o s:o}",
@@ -369,7 +377,8 @@ MH_handler_proposal_put (struct TMH_RequestHandler *rh,
   if (GNUNET_SYSERR == res)
     return MHD_NO;
   /* the POST's body has to be further fetched */
-  if ((GNUNET_NO == res) || (NULL == root))
+  if ( (GNUNET_NO == res) ||
+       (NULL == root) )
     return MHD_YES;
 
   order = json_object_get (root,
@@ -412,6 +421,7 @@ MH_handler_proposal_lookup (struct TMH_RequestHandler *rh,
   const char *order_id;
   const char *instance;
   int res;
+  enum GNUNET_DB_QueryStatus qs;
   json_t *contract_terms;
   struct MerchantInstance *mi;
 
@@ -434,18 +444,25 @@ MH_handler_proposal_lookup (struct TMH_RequestHandler *rh,
                                           TALER_EC_PARAMETER_MISSING,
                                            "order_id");
 
-  res = db->find_contract_terms (db->cls,
-                                 &contract_terms,
-                                 order_id,
-                                 &mi->pubkey);
-  if (GNUNET_NO == res)
-    return TMH_RESPONSE_reply_not_found (connection,
-                                         TALER_EC_PROPOSAL_LOOKUP_NOT_FOUND,
-                                         "unknown transaction id");
-  if (GNUNET_SYSERR == res)
+  qs = db->find_contract_terms (db->cls,
+                               &contract_terms,
+                               order_id,
+                               &mi->pubkey);
+  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_PROPOSAL_LOOKUP_DB_ERROR,
                                               "An error occurred while 
retrieving proposal data from db");
+  }
+  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+    return TMH_RESPONSE_reply_not_found (connection,
+                                         TALER_EC_PROPOSAL_LOOKUP_NOT_FOUND,
+                                         "unknown transaction id");
 
   res = TMH_RESPONSE_reply_json (connection,
                                  contract_terms,
diff --git a/src/backend/taler-merchant-httpd_refund.c 
b/src/backend/taler-merchant-httpd_refund.c
new file mode 100644
index 0000000..509235e
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_refund.c
@@ -0,0 +1,498 @@
+/*
+  This file is part of TALER
+  (C) 2014, 2015, 2016, 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
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file backend/taler-merchant-httpd_refund.c
+ * @brief HTTP serving layer mainly intended to communicate with the frontend
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include <jansson.h>
+#include <taler/taler_signatures.h>
+#include <taler/taler_json_lib.h>
+#include "taler-merchant-httpd.h"
+#include "taler-merchant-httpd_parsing.h"
+#include "taler-merchant-httpd_responses.h"
+#include "taler-merchant-httpd_refund.h"
+
+/**
+ * How often do we retry the non-trivial refund INSERT database
+ * transaction?
+ */
+#define MAX_RETRIES 5
+
+struct ProcessRefundData
+{
+  /**
+   * The array containing all the refund permissions.
+   */
+  json_t *response;
+
+  /**
+   * Hashed version of contract terms; needed by the callback
+   * to pack the response.
+   */
+  struct GNUNET_HashCode *h_contract_terms;
+
+  /**
+   * Both public and private key are needed by the callback
+   */
+   struct MerchantInstance *merchant;
+
+  /**
+   * Return code: #TALER_EC_NONE if successful.
+   */
+  enum TALER_ErrorCode ec;
+};
+
+/**
+ * Information we keep for individual calls
+ * to requests that parse JSON, but keep no other state.
+ */
+struct TMH_JsonParseContext
+{
+
+  /**
+   * This field MUST be first.
+   * FIXME: Explain why!
+   */
+  struct TM_HandlerContext hc;
+
+  /**
+   * Placeholder for #TMH_PARSE_post_json() to keep its internal state.
+   */
+  void *json_parse_context;
+};
+
+
+/**
+ * Custom cleanup routine for a `struct TMH_JsonParseContext`.
+ *
+ * @param hc the `struct TMH_JsonParseContext` to clean up.
+ */
+static void
+json_parse_cleanup (struct TM_HandlerContext *hc)
+{
+  struct TMH_JsonParseContext *jpc = (struct TMH_JsonParseContext *) hc;
+
+  TMH_PARSE_post_cleanup_callback (jpc->json_parse_context);
+  GNUNET_free (jpc);
+}
+
+
+/**
+ * Handle request for increasing the refund associated with
+ * a contract.
+ *
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+MH_handler_refund_increase (struct TMH_RequestHandler *rh,
+                            struct MHD_Connection *connection,
+                            void **connection_cls,
+                            const char *upload_data,
+                            size_t *upload_data_size)
+{
+  int res;
+  struct TMH_JsonParseContext *ctx;
+  struct TALER_Amount refund;
+  json_t *root;
+  json_t *contract_terms;
+  const char *order_id;
+  const char *reason;
+  const char *merchant;
+  struct MerchantInstance *mi;
+  struct GNUNET_HashCode h_contract_terms;
+  struct TALER_MerchantRefundConfirmationPS confirmation;
+  struct GNUNET_CRYPTO_EddsaSignature sig;
+  struct GNUNET_JSON_Specification spec[] = {
+    TALER_JSON_spec_amount ("refund", &refund),
+    GNUNET_JSON_spec_string ("order_id", &order_id),
+    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)
+  {
+    ctx = GNUNET_new (struct TMH_JsonParseContext);
+    ctx->hc.cc = &json_parse_cleanup;
+    *connection_cls = ctx;
+  }
+  else
+  {
+    ctx = *connection_cls;
+  }
+
+  res = TMH_PARSE_post_json (connection,
+                             &ctx->json_parse_context,
+                             upload_data,
+                             upload_data_size,
+                             &root);
+  if (GNUNET_SYSERR == res)
+    return MHD_NO;
+  /* the POST's body has to be further fetched */
+  if ( (GNUNET_NO == res) ||
+       (NULL == root) )
+    return MHD_YES;
+
+  res = TMH_PARSE_json_data (connection,
+                             root,
+                             spec);
+  if (GNUNET_NO == res)
+  {
+    GNUNET_break_op (0);
+    return MHD_YES;
+  }
+
+  if (GNUNET_SYSERR == res)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Hard error from JSON parser\n");
+    return MHD_NO;
+  }
+
+  mi = TMH_lookup_instance (merchant);
+  if (NULL == mi)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "No instance found\n");
+    GNUNET_JSON_parse_free (spec);
+    return TMH_RESPONSE_reply_not_found (connection,
+                                         TALER_EC_REFUND_INSTANCE_UNKNOWN,
+                                        "Unknown instance given");
+  }
+  
+  /* Convert order id to h_contract_terms */
+  qs = db->find_contract_terms (db->cls,
+                               &contract_terms,
+                               order_id,
+                               &mi->pubkey);
+  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_REFUND_LOOKUP_DB_ERROR,
+                                              "An error occurred while 
retrieving payment data from db");
+  }
+  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+                "Unknown order id given: %s\n",
+                order_id);
+    return TMH_RESPONSE_reply_not_found (connection,
+                                         TALER_EC_REFUND_ORDER_ID_UNKNOWN,
+                                         "Order id not found in database");
+  }
+
+  if (GNUNET_OK !=
+      TALER_JSON_hash (contract_terms,
+                       &h_contract_terms))
+  {
+    GNUNET_JSON_parse_free (spec);
+    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");
+  }
+  for (unsigned int i=0;i<MAX_RETRIES;i++)
+  {
+    qs = db->increase_refund_for_contract (db->cls,
+                                          &h_contract_terms,
+                                          &mi->pubkey,
+                                          &refund,
+                                          reason);
+    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);
+    GNUNET_JSON_parse_free (spec);
+    return TMH_RESPONSE_reply_internal_error (connection,
+                                              
TALER_EC_REFUND_MERCHANT_DB_COMMIT_ERROR,
+                                              "Internal database error or 
refund amount too big");
+  }
+  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Refunded amount lower or equal to previous refund: %s\n",
+                TALER_amount2s (&refund));
+    GNUNET_JSON_parse_free (spec);
+    return TMH_RESPONSE_reply_external_error (connection,
+                                              
TALER_EC_REFUND_INCONSISTENT_AMOUNT,
+                                              "Amount incorrect: not larger 
than the previous one");
+  }
+
+  /**
+   * Return to the frontend at this point.  The frontend will then return
+   * a "402 Payment required" carrying a "X-Taler-Refund-Url: www"
+   * where 'www' is the URL where the wallet can automatically fetch
+   * the refund permission.
+   *
+   * Just a "200 OK" should be fine here, as the frontend has all
+   * the information needed to generate the right response.
+   */
+
+  json_decref (contract_terms);
+  json_decref (root);
+  GNUNET_JSON_parse_free (spec);
+
+  confirmation.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND_OK);
+  confirmation.purpose.size = htonl (sizeof (struct 
TALER_MerchantRefundConfirmationPS));
+
+  if (GNUNET_OK !=
+      GNUNET_CRYPTO_eddsa_sign (&mi->privkey.eddsa_priv,
+                               &confirmation.purpose,
+                               &sig))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Failed to sign successful refund confirmation\n");
+    return TMH_RESPONSE_reply_internal_error (connection,
+                                              TALER_EC_NONE,
+                                              "Refund done, but failed to sign 
confirmation");
+  
+  }
+
+  return TMH_RESPONSE_reply_json_pack (connection, 
+                                       MHD_HTTP_OK,
+                                       "{s:o}",
+                                       "sig", GNUNET_JSON_from_data_auto 
(&sig));
+}
+
+
+/**
+ * Function called with information about a refund.
+ * It is responsible for packing up the data to return.
+ *
+ * @param cls closure
+ * @param coin_pub public coin from which the refund comes from
+ * @param rtransaction_id identificator of the refund
+ * @param reason human-readable explaination of the refund
+ * @param refund_amount refund amount which is being taken from coin_pub
+ * @param refund_fee cost of this refund operation
+ */
+static void
+process_refunds_cb (void *cls,
+                    const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                    uint64_t rtransaction_id,
+                    const char *reason,
+                    const struct TALER_Amount *refund_amount,
+                    const struct TALER_Amount *refund_fee)
+{
+  struct ProcessRefundData *prd = cls;
+  struct TALER_RefundRequestPS rr;
+  struct GNUNET_CRYPTO_EddsaSignature sig;
+  json_t *element;
+
+  rr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND);
+  rr.purpose.size = htonl (sizeof (struct TALER_RefundRequestPS));
+  rr.h_contract_terms = *prd->h_contract_terms;
+  rr.coin_pub = *coin_pub;
+  rr.merchant = prd->merchant->pubkey;
+  rr.rtransaction_id = GNUNET_htonll (rtransaction_id);
+  TALER_amount_hton (&rr.refund_amount,
+                     refund_amount);
+  TALER_amount_hton (&rr.refund_fee,
+                     refund_fee);
+
+  if (GNUNET_OK !=
+      GNUNET_CRYPTO_eddsa_sign (&prd->merchant->privkey.eddsa_priv,
+                               &rr.purpose,
+                               &sig))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Could not sign refund request\n");
+    prd->ec = TALER_EC_INTERNAL_LOGIC_ERROR;
+    return;
+  }
+
+  element = json_pack ("{s:o, s:o, s:o, s:o, s:I, s:o, s:o}",
+                       "refund_amount", TALER_JSON_from_amount (refund_amount),
+                       "refund_fee", TALER_JSON_from_amount (refund_fee),
+                       "h_contract_terms", GNUNET_JSON_from_data_auto 
(prd->h_contract_terms),
+                       "coin_pub", GNUNET_JSON_from_data_auto (coin_pub),
+                       "rtransaction_id", (json_int_t) rtransaction_id,
+                       "merchant_pub", GNUNET_JSON_from_data_auto 
(&prd->merchant->pubkey),
+                       "merchant_sig", GNUNET_JSON_from_data_auto (&sig));
+  if (NULL == element)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Could not pack a response's element up\n");
+    prd->ec = TALER_EC_PARSER_OUT_OF_MEMORY;
+    return;
+  }
+
+  if (-1 == json_array_append_new (prd->response,
+                                   element))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Could not append a response's element\n");
+    prd->ec = TALER_EC_PARSER_OUT_OF_MEMORY;
+    return; 
+  }
+}
+
+/**
+ * Return refund situation about a contract.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+MH_handler_refund_lookup (struct TMH_RequestHandler *rh,
+                          struct MHD_Connection *connection,
+                          void **connection_cls,
+                          const char *upload_data,
+                          size_t *upload_data_size)
+{
+  const char *order_id;
+  const char *instance;
+  struct GNUNET_HashCode h_contract_terms;
+  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,
+                                          "instance");
+  if (NULL == instance)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Argument 'instance' not given\n");
+    return TMH_RESPONSE_reply_arg_missing (connection,
+                                          TALER_EC_PARAMETER_MISSING,
+                                           "instance");
+  }
+
+  mi = TMH_lookup_instance (instance);
+
+  if (NULL == mi)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Unknown instance given: %s\n",
+                instance);
+    return TMH_RESPONSE_reply_not_found (connection,
+                                         TALER_EC_REFUND_INSTANCE_UNKNOWN,
+                                         "Unknown instance given");
+  }
+
+  order_id = MHD_lookup_connection_value (connection,
+                                          MHD_GET_ARGUMENT_KIND,
+                                          "order_id");
+  if (NULL == order_id)
+  { 
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+                "Argument 'order_id' not given\n");
+    return TMH_RESPONSE_reply_arg_missing (connection,
+                                          TALER_EC_PARAMETER_MISSING,
+                                           "order_id");
+  }
+
+  /* Convert order id to h_contract_terms */
+  qs = db->find_contract_terms (db->cls,
+                               &contract_terms,
+                               order_id,
+                               &mi->pubkey);
+  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_REFUND_LOOKUP_DB_ERROR,
+                                              "database error looking up 
order_id from merchant_contract_terms table");
+  }
+
+  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+                "Unknown order id given: %s\n",
+                order_id);
+    return TMH_RESPONSE_reply_not_found (connection,
+                                         TALER_EC_REFUND_ORDER_ID_UNKNOWN,
+                                         "Order id not found in database");
+  }
+
+  if (GNUNET_OK !=
+      TALER_JSON_hash (contract_terms,
+                       &h_contract_terms))
+  {
+    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");
+  }
+  prd.response = json_array ();
+  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,
+                                                  &process_refunds_cb,
+                                                  &prd);
+    if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
+      break;
+  }
+  if (0 > qs)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+                "database hard error on order_id lookup: %s\n",
+                order_id);
+    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");
+  }
+  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"); 
+  }
+   return TMH_RESPONSE_reply_json (connection,
+                                  prd.response,
+                                  MHD_HTTP_OK);
+}
+
+
+/* end of taler-merchant-httpd_refund.c */
diff --git a/src/backend/taler-merchant-httpd_map.h 
b/src/backend/taler-merchant-httpd_refund.h
similarity index 60%
rename from src/backend/taler-merchant-httpd_map.h
rename to src/backend/taler-merchant-httpd_refund.h
index 83aca2b..64da3f9 100644
--- a/src/backend/taler-merchant-httpd_map.h
+++ b/src/backend/taler-merchant-httpd_refund.h
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  (C) 2014, 2015, 2016 INRIA
+  (C) 2014, 2015, 2016, 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
@@ -13,23 +13,22 @@
   You should have received a copy of the GNU General Public License along with
   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
+
 /**
- * @file backend/taler-merchant-httpd_map.c
+ * @file backend/taler-merchant-httpd_refund.c
  * @brief HTTP serving layer mainly intended to communicate with the frontend
  * @author Marcello Stanisci
  */
 
-#ifndef TALER_MERCHANT_HTTPD_MAP_H
-#define TALER_MERCHANT_HTTPD_MAP_H
+#ifndef TALER_MERCHANT_HTTPD_REFUND_H
+#define TALER_MERCHANT_HTTPD_REFUND_H
 #include <microhttpd.h>
 #include "taler-merchant-httpd.h"
 
-
 /**
- * Manage a /map/in request. Store in db a plain text contract
- * and its hashcode.
+ * Handle request for increasing the refund associated with
+ * a contract.
  *
- * @param rh context of the handler
  * @param connection the MHD connection to handle
  * @param[in,out] connection_cls the connection's closure (can be updated)
  * @param upload_data upload data
@@ -37,16 +36,15 @@
  * @return MHD result code
  */
 int
-MH_handler_map_in (struct TMH_RequestHandler *rh,
-                   struct MHD_Connection *connection,
-                   void **connection_cls,
-                   const char *upload_data,
-                   size_t *upload_data_size);
+MH_handler_refund_increase (struct TMH_RequestHandler *rh,
+                            struct MHD_Connection *connection,
+                            void **connection_cls,
+                            const char *upload_data,
+                            size_t *upload_data_size);
 
 
 /**
- * Manage a /map/out request. Query the db and returns a plain
- * text contract associated with the hashcode given as input
+ * Return refund situation about a contract.
  *
  * @param rh context of the handler
  * @param connection the MHD connection to handle
@@ -56,11 +54,9 @@ MH_handler_map_in (struct TMH_RequestHandler *rh,
  * @return MHD result code
  */
 int
-MH_handler_map_out (struct TMH_RequestHandler *rh,
-                    struct MHD_Connection *connection,
-                    void **connection_cls,
-                    const char *upload_data,
-                    size_t *upload_data_size);
-
-/* end of taler-merchant-httpd_history.c */
-#endif
+MH_handler_refund_lookup (struct TMH_RequestHandler *rh,
+                          struct MHD_Connection *connection,
+                          void **connection_cls,
+                          const char *upload_data,
+                          size_t *upload_data_size);
+#endif                          
diff --git a/src/backend/taler-merchant-httpd_responses.c 
b/src/backend/taler-merchant-httpd_responses.c
index 8cbdf6b..1ea2600 100644
--- a/src/backend/taler-merchant-httpd_responses.c
+++ b/src/backend/taler-merchant-httpd_responses.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+  Copyright (C) 2014-2017 GNUnet e.V.
 
   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
@@ -395,52 +395,4 @@ TMH_RESPONSE_reply_arg_invalid (struct MHD_Connection 
*connection,
 }
 
 
-/**
- * Generate /track/transaction response.
- *
- * @param num_transfers how many wire transfers make up the transaction
- * @param transfers data on each wire transfer
- * @param exchange_uri URI of the exchange that made the transfer
- * @return MHD response object
- */
-struct MHD_Response *
-TMH_RESPONSE_make_track_transaction_ok (unsigned int num_transfers,
-                                        const struct 
TALER_MERCHANT_TransactionWireTransfer *transfers,
-                                        const char *exchange_uri)
-{
-  struct MHD_Response *ret;
-  unsigned int i;
-  json_t *j_transfers;
-  struct TALER_Amount sum;
-
-  j_transfers = json_array ();
-  for (i=0;i<num_transfers;i++)
-  {
-    const struct TALER_MERCHANT_TransactionWireTransfer *transfer = 
&transfers[i];
-    unsigned int j;
-
-    sum = transfer->coins[0].amount_with_fee;
-    for (j=1;j<transfer->num_coins;j++)
-    {
-      const struct TALER_MERCHANT_CoinWireTransfer *coin = &transfer->coins[j];
-
-      GNUNET_assert (GNUNET_SYSERR != TALER_amount_add (&sum,
-                                                        &sum,
-                                                        
&coin->amount_with_fee));
-    }
-
-    GNUNET_assert (0 ==
-                   json_array_append_new (j_transfers,
-                                          json_pack ("{s:s, s:o, s:o, s:o}",
-                                                     "exchange", exchange_uri,
-                                                     "wtid", 
GNUNET_JSON_from_data_auto (&transfer->wtid),
-                                                     "execution_time", 
GNUNET_JSON_from_time_abs (transfer->execution_time),
-                                                     "amount", 
TALER_JSON_from_amount (&sum))));
-  }
-  ret = TMH_RESPONSE_make_json (j_transfers);
-  json_decref (j_transfers);
-  return ret;
-}
-
-
 /* end of taler-exchange-httpd_responses.c */
diff --git a/src/backend/taler-merchant-httpd_responses.h 
b/src/backend/taler-merchant-httpd_responses.h
index 0b552fd..ea290c5 100644
--- a/src/backend/taler-merchant-httpd_responses.h
+++ b/src/backend/taler-merchant-httpd_responses.h
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+  Copyright (C) 2014-2017 GNUnet e.V.
 
   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
@@ -70,20 +70,6 @@ TMH_RESPONSE_make_json_pack (const char *fmt,
 
 
 /**
- * Generate /track/transaction response.
- *
- * @param num_transfers how many wire transfers make up the transaction
- * @param transfers data on each wire transfer
- * @param exchange_uri URI of the exchange that made the transfer
- * @return MHD response object
- */
-struct MHD_Response *
-TMH_RESPONSE_make_track_transaction_ok (unsigned int num_transfers,
-                                        const struct 
TALER_MERCHANT_TransactionWireTransfer *transfers,
-                                        const char *exchange_uri);
-
-
-/**
  * Function to call to handle the request by building a JSON
  * reply from a format string and varargs.
  *
diff --git a/src/backend/taler-merchant-httpd_track-transaction.c 
b/src/backend/taler-merchant-httpd_track-transaction.c
index e9610ae..2848bc7 100644
--- a/src/backend/taler-merchant-httpd_track-transaction.c
+++ b/src/backend/taler-merchant-httpd_track-transaction.c
@@ -42,6 +42,58 @@ extern struct GNUNET_CONTAINER_MultiHashMap *by_id_map;
  */
 #define TRACK_TIMEOUT (GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 30))
 
+/**
+ * How often do we retry the simple INSERT database transaction?
+ */
+#define MAX_RETRIES 3
+
+
+/**
+ * Generate /track/transaction response.
+ *
+ * @param num_transfers how many wire transfers make up the transaction
+ * @param transfers data on each wire transfer
+ * @param exchange_uri URI of the exchange that made the transfer
+ * @return MHD response object
+ */
+static struct MHD_Response *
+make_track_transaction_ok (unsigned int num_transfers,
+                          const struct TALER_MERCHANT_TransactionWireTransfer 
*transfers,
+                          const char *exchange_uri)
+{
+  struct MHD_Response *ret;
+  json_t *j_transfers;
+  struct TALER_Amount sum;
+
+  j_transfers = json_array ();
+  for (unsigned int i=0;i<num_transfers;i++)
+  {
+    const struct TALER_MERCHANT_TransactionWireTransfer *transfer = 
&transfers[i];
+
+    sum = transfer->coins[0].amount_with_fee;
+    for (unsigned int j=1;j<transfer->num_coins;j++)
+    {
+      const struct TALER_MERCHANT_CoinWireTransfer *coin = &transfer->coins[j];
+
+      GNUNET_assert (GNUNET_SYSERR != TALER_amount_add (&sum,
+                                                        &sum,
+                                                        
&coin->amount_with_fee));
+    }
+
+    GNUNET_assert (0 ==
+                   json_array_append_new (j_transfers,
+                                          json_pack ("{s:s, s:o, s:o, s:o}",
+                                                     "exchange", exchange_uri,
+                                                     "wtid", 
GNUNET_JSON_from_data_auto (&transfer->wtid),
+                                                     "execution_time", 
GNUNET_JSON_from_time_abs (transfer->execution_time),
+                                                     "amount", 
TALER_JSON_from_amount (&sum))));
+  }
+  ret = TMH_RESPONSE_make_json (j_transfers);
+  json_decref (j_transfers);
+  return ret;
+}
+
+
 
 /**
  * Context for a /track/transaction operation.
@@ -219,6 +271,12 @@ struct TrackTransactionContext
    */
   struct MerchantInstance *mi;
 
+  /**
+   * Set to negative values in #coin_cb() if we encounter
+   * a database problem.
+   */
+  enum GNUNET_DB_QueryStatus qs;
+
 };
 
 
@@ -358,8 +416,7 @@ wire_deposits_cb (void *cls,
                   const struct TALER_TrackTransferDetails *details)
 {
   struct TrackTransactionContext *tctx = cls;
-  struct TrackCoinContext *tcc;
-  unsigned int i;
+  enum GNUNET_DB_QueryStatus qs;
 
   tctx->wdh = NULL;
   if (MHD_HTTP_OK != http_status)
@@ -375,26 +432,37 @@ wire_deposits_cb (void *cls,
                                     "details", json));
     return;
   }
-  if (GNUNET_OK !=
-      db->store_transfer_to_proof (db->cls,
-                                   tctx->exchange_uri,
-                                   &tctx->current_wtid,
-                                   tctx->current_execution_time,
-                                   exchange_pub,
-                                   json))
+  for (unsigned int i=0;i<MAX_RETRIES;i++)
+  {
+    qs = db->store_transfer_to_proof (db->cls,
+                                     tctx->exchange_uri,
+                                     &tctx->current_wtid,
+                                     tctx->current_execution_time,
+                                     exchange_pub,
+                                     json);
+    if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
+      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);
+    /* Always report on hard error as well to enable diagnostics */
+    GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Failed to store transfer-to-proof mapping in DB\n");
   }
-  for (tcc=tctx->tcc_head;NULL != tcc;tcc=tcc->next)
+  for (struct TrackCoinContext *tcc=tctx->tcc_head;
+       NULL != tcc;
+       tcc=tcc->next)
   {
     if (GNUNET_YES == tcc->have_wtid)
       continue;
-    for (i=0;i<details_length;i++)
+    for (unsigned int d=0;d<details_length;d++)
     {
 
-      if (0 == memcmp (&details[i].coin_pub,
+      if (0 == memcmp (&details[d].coin_pub,
                        &tcc->coin_pub,
                        sizeof (struct TALER_CoinSpendPublicKeyP)))
       {
@@ -403,13 +471,22 @@ wire_deposits_cb (void *cls,
         tcc->have_wtid = GNUNET_YES;
       }
 
-      if (GNUNET_OK !=
-          db->store_coin_to_transfer (db->cls,
-                                      &details[i].h_contract_terms,
-                                      &details[i].coin_pub,
-                                      &tctx->current_wtid))
+      for (unsigned int i=0;i<MAX_RETRIES;i++)
       {
-        /* Not good, but not fatal either, log error and continue */
+       qs = db->store_coin_to_transfer (db->cls,
+                                        &details[d].h_contract_terms,
+                                        &details[d].coin_pub,
+                                        &tctx->current_wtid);
+       if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
+         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);
+       /* Always report on hard error as well to enable diagnostics */
+       GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                     "Failed to store coin-to-transfer mapping in DB\n");
       }
@@ -487,6 +564,7 @@ wtid_cb (void *cls,
   struct TrackCoinContext *tcc = cls;
   struct TrackTransactionContext *tctx = tcc->tctx;
   struct ProofCheckContext pcc;
+  enum GNUNET_DB_QueryStatus qs;
 
   tcc->dwh = NULL;
   if (MHD_HTTP_OK != http_status)
@@ -509,15 +587,28 @@ wtid_cb (void *cls,
   tctx->current_wtid = *wtid;
   tctx->current_execution_time = execution_time;
   pcc.p_ret = NULL;
+  qs = db->find_proof_by_wtid (db->cls,
+                              tctx->exchange_uri,
+                              wtid,
+                              &proof_cb,
+                              &pcc);
+  if (0 > qs)
+  {
+    /* Simple select queries should not cause serialization issues */
+    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);
+    resume_track_transaction_with_response
+      (tcc->tctx,
+       MHD_HTTP_INTERNAL_SERVER_ERROR,
+       TMH_RESPONSE_make_internal_error 
(TALER_EC_TRACK_TRANSACTION_DB_FETCH_FAILED,
+                                        "Fail to query database about 
proofs"));
+    return;
+  }
   /* WARNING: if two transactions got aggregated under the same
      WTID, then this branch is always taken (when attempting to
      track the second transaction). */
-  if (GNUNET_OK ==
-      db->find_proof_by_wtid (db->cls,
-                              tctx->exchange_uri,
-                              wtid,
-                              &proof_cb,
-                              &pcc))
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
   {
     GNUNET_break_op (0);
     resume_track_transaction_with_response
@@ -574,10 +665,11 @@ trace_coins (struct TrackTransactionContext *tctx)
      is worst-case O(n^2), in pracitce this is O(n) */
   for (tcc = tctx->tcc_head; NULL != tcc; tcc = tcc->next)
   {
-    struct TrackCoinContext *tcc2;
     int found = GNUNET_NO;
 
-    for (tcc2 = tctx->tcc_head; tcc2 != tcc; tcc2 = tcc2->next)
+    for (struct TrackCoinContext *tcc2 = tctx->tcc_head;
+        tcc2 != tcc;
+        tcc2 = tcc2->next)
     {
       if (0 == memcmp (&tcc->wtid,
                        &tcc2->wtid,
@@ -601,10 +693,11 @@ trace_coins (struct TrackTransactionContext *tctx)
     wtid_off = 0;
     for (tcc = tctx->tcc_head; NULL != tcc; tcc = tcc->next)
     {
-      struct TrackCoinContext *tcc2;
       int found = GNUNET_NO;
 
-      for (tcc2 = tctx->tcc_head; tcc2 != tcc; tcc2 = tcc2->next)
+      for (struct TrackCoinContext *tcc2 = tctx->tcc_head;
+          tcc2 != tcc;
+          tcc2 = tcc2->next)
       {
         if (0 == memcmp (&tcc->wtid,
                          &tcc2->wtid,
@@ -624,7 +717,9 @@ trace_coins (struct TrackTransactionContext *tctx)
         wt->execution_time = tcc->execution_time;
         /* count number of coins with this wtid */
         num_coins = 0;
-        for (tcc2 = tctx->tcc_head; NULL != tcc2; tcc2 = tcc2->next)
+        for (struct TrackCoinContext *tcc2 = tctx->tcc_head;
+            NULL != tcc2;
+            tcc2 = tcc2->next)
         {
           if (0 == memcmp (&wt->wtid,
                            &tcc2->wtid,
@@ -636,7 +731,9 @@ trace_coins (struct TrackTransactionContext *tctx)
         wt->coins = GNUNET_new_array (num_coins,
                                       struct TALER_MERCHANT_CoinWireTransfer);
         num_coins = 0;
-        for (tcc2 = tctx->tcc_head; NULL != tcc2; tcc2 = tcc2->next)
+        for (struct TrackCoinContext *tcc2 = tctx->tcc_head;
+            NULL != tcc2;
+            tcc2 = tcc2->next)
         {
           if (0 == memcmp (&wt->wtid,
                            &tcc2->wtid,
@@ -653,9 +750,9 @@ trace_coins (struct TrackTransactionContext *tctx)
     } /* for all tcc */
     GNUNET_assert (wtid_off == num_wtid);
 
-    resp = TMH_RESPONSE_make_track_transaction_ok (num_wtid,
-                                                   wts,
-                                                   tctx->exchange_uri);
+    resp = make_track_transaction_ok (num_wtid,
+                                     wts,
+                                     tctx->exchange_uri);
     for (wtid_off=0;wtid_off < num_wtid; wtid_off++)
       GNUNET_free (wts[wtid_off].coins);
     resume_track_transaction_with_response (tctx,
@@ -793,6 +890,7 @@ transfer_cb (void *cls,
  * @param coin_pub public key of the coin
  * @param amount_with_fee amount the exchange will deposit for this coin
  * @param deposit_fee fee the exchange will charge for this coin
+ * @param refund_fee fee the exchange will charge for refunding this coin
  * @param exchange_proof proof from exchange that coin was accepted
  */
 static void
@@ -801,26 +899,34 @@ coin_cb (void *cls,
          const struct TALER_CoinSpendPublicKeyP *coin_pub,
          const struct TALER_Amount *amount_with_fee,
          const struct TALER_Amount *deposit_fee,
+         const struct TALER_Amount *refund_fee,
          const json_t *exchange_proof)
 {
   struct TrackTransactionContext *tctx = cls;
   struct TrackCoinContext *tcc;
+  enum GNUNET_DB_QueryStatus qs;
 
   tcc = GNUNET_new (struct TrackCoinContext);
   tcc->tctx = tctx;
   tcc->coin_pub = *coin_pub;
+
   tcc->amount_with_fee = *amount_with_fee;
   tcc->deposit_fee = *deposit_fee;
   GNUNET_CONTAINER_DLL_insert (tctx->tcc_head,
                                tctx->tcc_tail,
                                tcc);
-  GNUNET_break (GNUNET_SYSERR !=
-                db->find_transfers_by_hash (db->cls,
-                                            h_contract_terms,
-                                            &transfer_cb,
-                                            tcc));
+  qs = db->find_transfers_by_hash (db->cls,
+                                  h_contract_terms,
+                                  &transfer_cb,
+                                  tcc);
+  if (0 > qs)
+  {
+    GNUNET_break (0);
+    tctx->qs = qs;
+  }
 }
 
+
 /**
  * Handle a "/track/transaction" request.
  *
@@ -842,6 +948,7 @@ MH_handler_track_transaction (struct TMH_RequestHandler *rh,
   const char *order_id;
   const char *instance;
   int ret;
+  enum GNUNET_DB_QueryStatus qs;
   struct GNUNET_HashCode h_instance;
   struct GNUNET_HashCode h_contract_terms;
   struct json_t *contract_terms;
@@ -917,11 +1024,18 @@ MH_handler_track_transaction (struct TMH_RequestHandler 
*rh,
                                         
TALER_EC_TRACK_TRANSACTION_INSTANCE_UNKNOWN,
                                         "unknown instance");
 
-  if (GNUNET_YES !=
-      db->find_contract_terms (db->cls,
-                               &contract_terms,
-                               order_id,
-                               &tctx->mi->pubkey))
+  qs = db->find_contract_terms (db->cls,
+                               &contract_terms,
+                               order_id,
+                               &tctx->mi->pubkey);
+  if (0 > qs)
+  {
+    GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+    return TMH_RESPONSE_reply_internal_error (connection,
+                                             
TALER_EC_TRACK_TRANSACTION_DB_FETCH_TRANSACTION_ERROR,
+                                              "Database error finding contract 
terms");
+  }
+  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
     return TMH_RESPONSE_reply_not_found (connection,
                                         TALER_EC_PROPOSAL_LOOKUP_NOT_FOUND,
                                         "Given order_id doesn't map to any 
proposal");
@@ -933,12 +1047,19 @@ MH_handler_track_transaction (struct TMH_RequestHandler 
*rh,
               "Trying to track h_contract_terms '%s'\n",
               GNUNET_h2s (&h_contract_terms));
 
-  ret = db->find_transaction (db->cls,
-                              &h_contract_terms,
-                             &tctx->mi->pubkey,
-                              &transaction_cb,
-                              tctx);
-  if (GNUNET_NO == ret)
+  qs = db->find_transaction (db->cls,
+                            &h_contract_terms,
+                            &tctx->mi->pubkey,
+                            &transaction_cb,
+                            tctx);
+  if (0 > qs)
+  {
+    GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+    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,
                 "h_contract_terms not found\n");
@@ -946,8 +1067,7 @@ MH_handler_track_transaction (struct TMH_RequestHandler 
*rh,
                                         
TALER_EC_TRACK_TRANSACTION_TRANSACTION_UNKNOWN,
                                          "h_contract_terms is unknown");
   }
-  if ( (GNUNET_SYSERR == ret) ||
-       (0 != memcmp (&tctx->h_contract_terms,
+  if ( (0 != memcmp (&tctx->h_contract_terms,
                      &h_contract_terms,
                      sizeof (struct GNUNET_HashCode))) ||
        (NULL == tctx->exchange_uri) )
@@ -955,25 +1075,28 @@ MH_handler_track_transaction (struct TMH_RequestHandler 
*rh,
     GNUNET_break (0);
     return TMH_RESPONSE_reply_internal_error (connection,
                                              
TALER_EC_TRACK_TRANSACTION_DB_FETCH_TRANSACTION_ERROR,
-                                              "Database error");
+                                              "Database error: failed to 
obtain correct data from database");
   }
-  ret = db->find_payments (db->cls,
-                           &h_contract_terms,
-                           &tctx->mi->pubkey,
-                           &coin_cb,
-                           tctx);
-  if (GNUNET_SYSERR == ret)
+  tctx->qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
+  qs = db->find_payments (db->cls,
+                         &h_contract_terms,
+                         &tctx->mi->pubkey,
+                         &coin_cb,
+                         tctx);
+  if ( (0 > qs) ||
+       (0 > tctx->qs) )
   {
-    GNUNET_break (0);
+    GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+    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");
+                                             "Database error: failed in find 
payment data");
   }
-  if (GNUNET_NO == ret)
+  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
   {
     return TMH_RESPONSE_reply_not_found (connection,
                                         
TALER_EC_TRACK_TRANSACTION_DB_NO_DEPOSITS_ERROR,
-                                         "deposits");
+                                         "deposit data not found");
   }
   *connection_cls = tctx;
 
diff --git a/src/backend/taler-merchant-httpd_track-transfer.c 
b/src/backend/taler-merchant-httpd_track-transfer.c
index 3df9703..d38cb66 100644
--- a/src/backend/taler-merchant-httpd_track-transfer.c
+++ b/src/backend/taler-merchant-httpd_track-transfer.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
@@ -37,6 +37,10 @@
  */
 #define TRACK_TIMEOUT (GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 30))
 
+/**
+ * How often do we retry the simple INSERT database transaction?
+ */
+#define MAX_RETRIES 3
 
 /**
  * Context used for handing /track/transfer requests.
@@ -130,11 +134,13 @@ struct TrackTransferContext
   int check_transfer_result;
 };
 
+
 /**
  * Represents an entry in the table used to sum up
  * individual deposits for each h_contract_terms.
  */
-struct Entry {
+struct Entry
+{
 
   /**
    * Sum accumulator for deposited value.
@@ -195,8 +201,8 @@ hashmap_free (void *cls,
               void *value)
 {
   struct TALER_Amount *amount = value;
+  
   GNUNET_free (amount);
-  /*NOTE: how to find out when iteration should stop?*/
   return GNUNET_YES;
 }
 
@@ -305,8 +311,9 @@ transform_response (const json_t *result,
     GNUNET_CRYPTO_hash_from_string (key,
                                     &h_key);
 
-    if (NULL != (current_entry = GNUNET_CONTAINER_multihashmap_get (map,
-                                                                    &h_key)))
+    if (NULL != (current_entry =
+                GNUNET_CONTAINER_multihashmap_get (map,
+                                                   &h_key)))
     {
       /* The map already knows this h_contract_terms*/
       if ( (GNUNET_SYSERR ==
@@ -418,6 +425,7 @@ track_transfer_cleanup (struct TM_HandlerContext *hc)
  * @param coin_pub public key of the coin
  * @param amount_with_fee amount the exchange will transfer for this coin
  * @param deposit_fee fee the exchange will charge for this coin
+ * @param refund_fee fee the exchange will charge for refunding this coin
  * @param exchange_proof proof from exchange that coin was accepted
  */
 static void
@@ -426,6 +434,7 @@ check_transfer (void *cls,
                 const struct TALER_CoinSpendPublicKeyP *coin_pub,
                 const struct TALER_Amount *amount_with_fee,
                 const struct TALER_Amount *deposit_fee,
+                const struct TALER_Amount *refund_fee,
                 const json_t *exchange_proof)
 {
   struct TrackTransferContext *rctx = cls;
@@ -492,9 +501,8 @@ wire_transfer_cb (void *cls,
                   const struct TALER_TrackTransferDetails *details)
 {
   struct TrackTransferContext *rctx = cls;
-  unsigned int i;
-  int ret;
   json_t *jresponse;
+  enum GNUNET_DB_QueryStatus qs;
 
   rctx->wdh = NULL;
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -512,17 +520,23 @@ wire_transfer_cb (void *cls,
                                     "details", json));
     return;
   }
-
-  if (GNUNET_OK !=
-      db->store_transfer_to_proof (db->cls,
-                                   rctx->uri,
-                                   &rctx->wtid,
-                                   execution_time,
-                                   exchange_pub,
-                                   json))
+  for (unsigned int i=0;i<MAX_RETRIES;i++)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Failed to persist wire transfer proof in DB\n");
+    qs = db->store_transfer_to_proof (db->cls,
+                                     rctx->uri,
+                                     &rctx->wtid,
+                                     execution_time,
+                                     exchange_pub,
+                                     json);
+    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);
     resume_track_transfer_with_response
       (rctx,
        MHD_HTTP_INTERNAL_SERVER_ERROR,
@@ -532,21 +546,24 @@ wire_transfer_cb (void *cls,
     return;
   }
   rctx->original_response = json;
-  for (i=0;i<details_length;i++)
+  for (unsigned int i=0;i<details_length;i++)
   {
     rctx->current_offset = i;
     rctx->current_detail = &details[i];
     rctx->check_transfer_result = GNUNET_NO;
-    ret = db->find_payments_by_hash_and_coin (db->cls,
-                                              &details[i].h_contract_terms,
-                                              &rctx->mi->pubkey,
-                                              &details[i].coin_pub,
-                                              &check_transfer,
-                                              rctx);
-    if (GNUNET_SYSERR == ret)
+    qs = db->find_payments_by_hash_and_coin (db->cls,
+                                            &details[i].h_contract_terms,
+                                            &rctx->mi->pubkey,
+                                            &details[i].coin_pub,
+                                            &check_transfer,
+                                            rctx);
+    if (0 > qs)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Failed to obtain existing payment data from DB\n");
+      /* 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);
       resume_track_transfer_with_response
         (rctx,
          MHD_HTTP_INTERNAL_SERVER_ERROR,
@@ -555,7 +572,7 @@ wire_transfer_cb (void *cls,
                                       "details", "failed to obtain deposit 
data from local database"));
       return;
     }
-    if (GNUNET_NO == ret)
+    if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
     {
       /* The exchange says we made this deposit, but WE do not
          recall making it! Well, let's say thanks and accept the
@@ -593,14 +610,21 @@ wire_transfer_cb (void *cls,
     }
     /* Response is consistent with the /deposit we made, remember
        it for future reference */
-    ret = db->store_coin_to_transfer (db->cls,
-                                      &details[i].h_contract_terms,
-                                      &details[i].coin_pub,
-                                      &rctx->wtid);
-    if (GNUNET_OK != ret)
+    for (unsigned int i=0;i<MAX_RETRIES;i++)
+    {
+      qs = db->store_coin_to_transfer (db->cls,
+                                      &details[i].h_contract_terms,
+                                      &details[i].coin_pub,
+                                      &rctx->wtid);
+      if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
+       break;
+    }
+    if (0 > qs)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Failed to persist coin to wire transfer mapping in DB\n");
+      /* 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);
       resume_track_transfer_with_response
         (rctx,
          MHD_HTTP_INTERNAL_SERVER_ERROR,
@@ -615,7 +639,9 @@ wire_transfer_cb (void *cls,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "About to call tracks transformator.\n");
 
-  if (NULL == (jresponse = transform_response (json, rctx)))
+  if (NULL == (jresponse =
+              transform_response (json,
+                                  rctx)))
   {
     resume_track_transfer_with_response
       (rctx,
@@ -709,12 +735,14 @@ proof_cb (void *cls,
   struct TrackTransferContext *rctx = cls;
   json_t *transformed_response;
 
-  if (NULL == (transformed_response = transform_response (proof,
-                                                          rctx)))
+  if (NULL == (transformed_response =
+              transform_response (proof,
+                                  rctx)))
   {
     rctx->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
-    rctx->response = TMH_RESPONSE_make_internal_error 
(TALER_EC_TRACK_TRANSFER_JSON_RESPONSE_ERROR,
-                                                       "Fail to elaborate 
response.");
+    rctx->response
+      = TMH_RESPONSE_make_internal_error 
(TALER_EC_TRACK_TRANSFER_JSON_RESPONSE_ERROR,
+                                         "Fail to elaborate response.");
     return;
   }
 
@@ -748,6 +776,7 @@ MH_handler_track_transfer (struct TMH_RequestHandler *rh,
   const char *uri;
   const char *instance_str;
   int ret;
+  enum GNUNET_DB_QueryStatus qs;
 
   if (NULL == *connection_cls)
   {
@@ -832,11 +861,21 @@ MH_handler_track_transfer (struct TMH_RequestHandler *rh,
   }
 
   /* Check if reply is already in database! */
-  ret = db->find_proof_by_wtid (db->cls,
-                                rctx->uri,
-                                &rctx->wtid,
-                                &proof_cb,
-                                rctx);
+  qs = db->find_proof_by_wtid (db->cls,
+                              rctx->uri,
+                              &rctx->wtid,
+                              &proof_cb,
+                              rctx);
+  if (0 > qs)
+  {
+    /* Simple select queries should not cause serialization issues */
+    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_TRACK_TRANSFER_DB_FETCH_FAILED,
+                                             "Fail to query database about 
proofs");   
+  }
   if (0 != rctx->response_code)
   {
     ret = MHD_queue_response (connection,
diff --git a/src/backenddb/Makefile.am b/src/backenddb/Makefile.am
index d1478cf..b38863c 100644
--- a/src/backenddb/Makefile.am
+++ b/src/backenddb/Makefile.am
@@ -24,7 +24,7 @@ libtalermerchantdb_la_LIBADD = \
 
 libtalermerchantdb_la_LDFLAGS = \
   $(POSTGRESQL_LDFLAGS) \
-  -version-info 0:0:0 \
+  -version-info 1:0:0 \
   -no-undefined
 
 libtaler_plugin_merchantdb_postgres_la_SOURCES = \
diff --git a/src/backenddb/plugin_merchantdb_postgres.c 
b/src/backenddb/plugin_merchantdb_postgres.c
index 5237e76..45ecab5 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  (C) 2014, 2015, 2016 INRIA
+  (C) 2014, 2015, 2016, 2017 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
@@ -43,40 +43,6 @@ struct PostgresClosure
 
 };
 
-/**
- * Extract error code.
- *
- * @param res postgres result object with error details
- */
-#define EXTRACT_DB_ERROR(res)                                         \
-  PQresultErrorField(res, PG_DIAG_SQLSTATE)
-
-
-/**
- * Log error from PostGres.
- *
- * @param kind log level to use
- * @param cmd command that failed
- * @param res postgres result object with error details
- */
-#define PQSQL_strerror(kind, cmd, res)                                \
-  GNUNET_log_from (kind, "merchantdb-postgres",                       \
-                   "SQL %s failed at %s:%u with error: %s",           \
-                   cmd, __FILE__, __LINE__, PQresultErrorMessage (res));
-
-
-/**
- * Log a really unexpected PQ error.
- *
- * @param result PQ result object of the PQ operation that failed
- */
-#define BREAK_DB_ERR(result) do {               \
-    GNUNET_break (0);                           \
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,        \
-                "Database failure: %s\n",       \
-                PQresultErrorMessage (result)); \
-  } while (0)
-
 
 /**
  * Drop merchant tables
@@ -94,6 +60,7 @@ postgres_drop_tables (void *cls)
     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_EXECUTE_STATEMENT_END
   };
 
@@ -121,6 +88,20 @@ postgres_initialize (void *cls)
                             ",timestamp INT8 NOT NULL"
                             ",row_id BIGSERIAL"
                             ",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"
                             ");"),
     GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_transactions 
("
                             " h_contract_terms BYTEA NOT NULL"
@@ -145,11 +126,14 @@ postgres_initialize (void *cls)
                             ",deposit_fee_val INT8 NOT NULL"
                             ",deposit_fee_frac INT4 NOT NULL"
                             ",deposit_fee_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"
                             ",signkey_pub BYTEA NOT NULL CHECK 
(LENGTH(signkey_pub)=32)"
                             ",exchange_proof BYTEA NOT NULL"
                             ",PRIMARY KEY (h_contract_terms, coin_pub)"
                             ");"),
-  GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_proofs ("
+    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"
@@ -170,6 +154,20 @@ postgres_initialize (void *cls)
                                 " ON merchant_transfers (h_contract_terms, 
coin_pub)"),
     GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS 
merchant_transfers_by_wtid"
                                 " ON merchant_transfers (wtid)"),
+    GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS exchange_wire_fees ("
+                           " exchange_pub BYTEA NOT NULL CHECK 
(length(exchange_pub)=32)"
+                           ",h_wire_method BYTEA NOT NULL CHECK 
(length(h_wire_method)=64)"
+                            ",wire_fee_val INT8 NOT NULL"
+                            ",wire_fee_frac INT4 NOT NULL"
+                            ",wire_fee_curr VARCHAR(" TALER_CURRENCY_LEN_STR 
") NOT NULL"
+                            ",closing_fee_val INT8 NOT NULL"
+                            ",closing_fee_frac INT4 NOT NULL"
+                            ",closing_fee_curr VARCHAR(" 
TALER_CURRENCY_LEN_STR ") NOT NULL"
+                           ",start_date INT8 NOT NULL"
+                           ",end_date INT8 NOT NULL"
+                           ",exchange_sig BYTEA NOT NULL CHECK 
(length(exchange_sig)=64)"
+                           ",PRIMARY KEY 
(exchange_pub,h_wire_method,start_date,end_date)"
+                           ");"),
     GNUNET_PQ_EXECUTE_STATEMENT_END
   };
   struct GNUNET_PQ_PreparedStatement ps[] = {
@@ -198,10 +196,13 @@ postgres_initialize (void *cls)
                             ",deposit_fee_val"
                             ",deposit_fee_frac"
                             ",deposit_fee_curr"
+                            ",refund_fee_val"
+                            ",refund_fee_frac"
+                            ",refund_fee_curr"
                             ",signkey_pub"
                             ",exchange_proof) VALUES "
-                            "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)",
-                            11),
+                            "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, 
$12, $13, $14)",
+                            14),
     GNUNET_PQ_make_prepare ("insert_transfer",
                             "INSERT INTO merchant_transfers"
                             "(h_contract_terms"
@@ -209,6 +210,21 @@ postgres_initialize (void *cls)
                             ",wtid) VALUES "
                             "($1, $2, $3)",
                             3),
+    GNUNET_PQ_make_prepare ("insert_refund",
+                            "INSERT INTO merchant_refunds"
+                            "(merchant_pub"
+                            ",h_contract_terms"
+                            ",coin_pub"
+                            ",reason"
+                            ",refund_amount_val"
+                            ",refund_amount_frac"
+                            ",refund_amount_curr"
+                            ",refund_fee_val"
+                            ",refund_fee_frac"
+                            ",refund_fee_curr"
+                            ") VALUES"
+                            "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
+                            10),
     GNUNET_PQ_make_prepare ("insert_proof",
                             "INSERT INTO merchant_proofs"
                             "(exchange_uri"
@@ -228,6 +244,22 @@ postgres_initialize (void *cls)
                             " VALUES "
                             "($1, $2, $3, $4, $5)",
                             4),
+    GNUNET_PQ_make_prepare ("insert_wire_fee",
+                            "INSERT INTO exchange_wire_fees"
+                            "(exchange_pub"
+                            ",h_wire_method"
+                            ",wire_fee_val"
+                            ",wire_fee_frac"
+                            ",wire_fee_curr"
+                            ",closing_fee_val"
+                            ",closing_fee_frac"
+                            ",closing_fee_curr"
+                            ",start_date"
+                            ",end_date"
+                            ",exchange_sig)"
+                            " VALUES "
+                            "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)",
+                            11),
     GNUNET_PQ_make_prepare ("find_contract_terms_from_hash",
                             "SELECT"
                             " contract_terms"
@@ -236,6 +268,19 @@ postgres_initialize (void *cls)
                             " h_contract_terms=$1"
                             " AND merchant_pub=$2",
                             2),
+    GNUNET_PQ_make_prepare ("end_transaction",
+                            "COMMIT",
+                            0),
+
+    /*NOTE: minimal version, to be expanded on a needed basis*/
+    GNUNET_PQ_make_prepare ("find_refunds",
+                            "SELECT"
+                            " refund_amount_val"
+                            ",refund_amount_frac"
+                            ",refund_amount_curr"
+                            " FROM merchant_refunds"
+                            " WHERE coin_pub=$1",
+                            1),
     GNUNET_PQ_make_prepare ("find_contract_terms",
                             "SELECT"
                             " contract_terms"
@@ -256,6 +301,21 @@ postgres_initialize (void *cls)
                             " ORDER BY row_id DESC, timestamp DESC"
                             " LIMIT $3",
                             3),
+    GNUNET_PQ_make_prepare ("find_refunds_from_contract_terms_hash",
+                            "SELECT"
+                           " coin_pub"
+                           ",rtransaction_id"
+                           ",refund_amount_val"
+                           ",refund_amount_frac"
+                           ",refund_amount_curr"
+                           ",refund_fee_val"
+                           ",refund_fee_frac"
+                           ",refund_fee_curr"
+                           ",reason"
+                           " FROM merchant_refunds"
+                            " WHERE merchant_pub=$1"
+                            " AND h_contract_terms=$2",
+                            2),
     GNUNET_PQ_make_prepare ("find_contract_terms_by_date_and_range",
                             "SELECT"
                             " contract_terms"
@@ -304,6 +364,9 @@ postgres_initialize (void *cls)
                             ",deposit_fee_val"
                             ",deposit_fee_frac"
                             ",deposit_fee_curr"
+                            ",refund_fee_val"
+                            ",refund_fee_frac"
+                            ",refund_fee_curr"
                             ",exchange_proof"
                             " FROM merchant_deposits"
                             " WHERE h_contract_terms=$1"
@@ -317,6 +380,9 @@ postgres_initialize (void *cls)
                             ",deposit_fee_val"
                             ",deposit_fee_frac"
                             ",deposit_fee_curr"
+                            ",refund_fee_val"
+                            ",refund_fee_frac"
+                            ",refund_fee_curr"
                             ",exchange_proof"
                             " FROM merchant_deposits"
                             " WHERE h_contract_terms=$1"
@@ -343,6 +409,9 @@ postgres_initialize (void *cls)
                             ",merchant_deposits.deposit_fee_val"
                             ",merchant_deposits.deposit_fee_frac"
                             ",merchant_deposits.deposit_fee_curr"
+                            ",merchant_deposits.refund_fee_val"
+                            ",merchant_deposits.refund_fee_frac"
+                            ",merchant_deposits.refund_fee_curr"
                             ",merchant_deposits.exchange_proof"
                             " FROM merchant_transfers"
                             "   JOIN merchant_deposits"
@@ -381,23 +450,108 @@ postgres_initialize (void *cls)
 
 
 /**
+ * Check that the database connection is still up.
+ *
+ * @param pg connection to check
+ */
+static void
+check_connection (struct PostgresClosure *pg)
+{
+  if (CONNECTION_BAD != PQstatus (pg->conn))
+    return;
+  PQfinish (pg->conn);
+  GNUNET_break (GNUNET_OK ==
+               postgres_initialize (pg));
+}
+
+
+/**
+ * Start a transaction.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @return #GNUNET_OK on success
+ */
+static int
+postgres_start (void *cls)
+{
+  struct PostgresClosure *pg = cls;
+  PGresult *result;
+  ExecStatusType ex;
+
+  check_connection (pg);
+  result = PQexec (pg->conn,
+                   "START TRANSACTION ISOLATION LEVEL SERIALIZABLE");
+  if (PGRES_COMMAND_OK !=
+      (ex = PQresultStatus (result)))
+  {
+    TALER_LOG_ERROR ("Failed to start transaction (%s): %s\n",
+                     PQresStatus (ex),
+                     PQerrorMessage (pg->conn));
+    GNUNET_break (0);
+    PQclear (result);
+    return GNUNET_SYSERR;
+  }
+  PQclear (result);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Roll back the current transaction of a database connection.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @return #GNUNET_OK on success
+ */
+static void
+postgres_rollback (void *cls)
+{
+  struct PostgresClosure *pg = cls;
+  PGresult *result;
+
+  result = PQexec (pg->conn,
+                   "ROLLBACK");
+  GNUNET_break (PGRES_COMMAND_OK ==
+                PQresultStatus (result));
+  PQclear (result);
+}
+
+
+/**
+ * Commit the current transaction of a database connection.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @return transaction status code
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_commit (void *cls)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_end
+  };
+
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                            "end_transaction",
+                                            params);
+}
+
+
+/**
  * Retrieve proposal data given its proposal data's hashcode
  *
  * @param cls closure
  * @param contract_terms where to store the retrieved proposal data
  * @param h_contract_terms proposal data's hashcode that will be used to
  * perform the lookup
- * @return #GNUNET_OK on success, #GNUNET_NO if no proposal is
- * found, #GNUNET_SYSERR upon error
+ * @return transaction status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_find_contract_terms_from_hash (void *cls,
                                        json_t **contract_terms,
                                        const struct GNUNET_HashCode 
*h_contract_terms,
                                        const struct TALER_MerchantPublicKeyP 
*merchant_pub)
 {
   struct PostgresClosure *pg = cls;
-  enum GNUNET_PQ_QueryStatus res;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
@@ -409,24 +563,11 @@ postgres_find_contract_terms_from_hash (void *cls,
     GNUNET_PQ_result_spec_end
   };
 
-  res = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                  
"find_contract_terms_from_hash",
-                                                  params,
-                                                  rs);
-  if (res < 0)
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  if (1 < res)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Mupltiple proposal data hash the same hashcode!\n");
-    return GNUNET_SYSERR;
-  }
-  if (0 == res)
-    return GNUNET_NO;
-  return GNUNET_OK;
+  check_connection (pg);
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                  
"find_contract_terms_from_hash",
+                                                  params,
+                                                  rs);
 }
 
 
@@ -434,19 +575,17 @@ postgres_find_contract_terms_from_hash (void *cls,
  * Retrieve proposal data given its order id.
  *
  * @param cls closure
- * @param[out] contract_terms where to store the retrieved proposal data
+ * @param[out] contract_terms where to store the retrieved contract terms
  * @param order id order id used to perform the lookup
- * @return #GNUNET_OK on success, #GNUNET_NO if no proposal is
- * found, #GNUNET_SYSERR upon error
+ * @return transaction status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_find_contract_terms (void *cls,
                               json_t **contract_terms,
                               const char *order_id,
                               const struct TALER_MerchantPublicKeyP 
*merchant_pub)
 {
   struct PostgresClosure *pg = cls;
-  enum GNUNET_PQ_QueryStatus res;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_string (order_id),
     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
@@ -463,24 +602,11 @@ postgres_find_contract_terms (void *cls,
               "Finding contract term, order_id: '%s', merchant_pub: '%s'.\n",
               order_id,
               TALER_B2S (merchant_pub));
-  res = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                  "find_contract_terms",
-                                                  params,
-                                                  rs);
-  if (res < 0)
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  if (res > 1)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Mupltiple proposal data share the same hashcode.\n");
-    return GNUNET_SYSERR;
-  }
-  if (0 == res)
-    return GNUNET_NO;
-  return GNUNET_OK;
+  check_connection (pg);
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                  "find_contract_terms",
+                                                  params,
+                                                  rs);
 }
 
 
@@ -490,9 +616,9 @@ postgres_find_contract_terms (void *cls,
  * @param cls closure
  * @param order_id identificator of the proposal being stored
  * @param contract_terms proposal data to store
- * @return #GNUNET_OK on success, #GNUNET_SYSERR upon error
+ * @return transaction status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_insert_contract_terms (void *cls,
                                const char *order_id,
                                const struct TALER_MerchantPublicKeyP 
*merchant_pub,
@@ -500,20 +626,7 @@ postgres_insert_contract_terms (void *cls,
                                const json_t *contract_terms)
 {
   struct PostgresClosure *pg = cls;
-  PGresult *result;
-  int ret;
   struct GNUNET_HashCode h_contract_terms;
-
-  if (GNUNET_OK != TALER_JSON_hash (contract_terms,
-                                    &h_contract_terms))
-    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,
-              TALER_B2S (merchant_pub),
-              GNUNET_h2s (&h_contract_terms));
-
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_string (order_id),
     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
@@ -522,33 +635,23 @@ postgres_insert_contract_terms (void *cls,
     GNUNET_PQ_query_param_auto_from_type (&h_contract_terms),
     GNUNET_PQ_query_param_end
   };
-
-  result = GNUNET_PQ_exec_prepared (pg->conn,
-                                    "insert_contract_terms",
-                                    params);
-
-  /**
-   * We don't treat a unique_violation (code '23505') error as
-   * an actual error, since there is no problem if a frontend tries
-   * to store twice the same proposal.  That is especially needed
-   * when DB-less frontends perform replayed payments.
-   */
-  if (PGRES_COMMAND_OK != PQresultStatus (result)
-      && (0 != memcmp ("23505",
-                       EXTRACT_DB_ERROR (result),
-                       5)))
-  {
-    ret = GNUNET_SYSERR;
-    BREAK_DB_ERR (result);
-  }
-  else
-  {
-    ret = GNUNET_OK;
-  }
-  PQclear (result);
-  return ret;
+  
+  if (GNUNET_OK !=
+      TALER_JSON_hash (contract_terms,
+                      &h_contract_terms))
+    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,
+              TALER_B2S (merchant_pub),
+              GNUNET_h2s (&h_contract_terms));
+  check_connection (pg);
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                            "insert_contract_terms",
+                                            params);
 }
 
+
 /**
  * Insert transaction data into the database.
  *
@@ -561,9 +664,9 @@ postgres_insert_contract_terms (void *cls,
  * @param timestamp time of the confirmation
  * @param refund refund deadline
  * @param total_amount total amount we receive for the contract after fees
- * @return #GNUNET_OK on success, #GNUNET_SYSERR upon error
+ * @return transaction status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_store_transaction (void *cls,
                             const struct GNUNET_HashCode *h_contract_terms,
                            const struct TALER_MerchantPublicKeyP *merchant_pub,
@@ -574,9 +677,6 @@ postgres_store_transaction (void *cls,
                             const struct TALER_Amount *total_amount)
 {
   struct PostgresClosure *pg = cls;
-  PGresult *result;
-  int ret;
-
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
     GNUNET_PQ_query_param_string (exchange_uri),
@@ -592,21 +692,10 @@ postgres_store_transaction (void *cls,
               "Storing transaction with h_contract_terms '%s', merchant_pub 
'%s'.\n",
               GNUNET_h2s (h_contract_terms),
               TALER_B2S (merchant_pub));
-
-  result = GNUNET_PQ_exec_prepared (pg->conn,
-                                    "insert_transaction",
-                                    params);
-  if (PGRES_COMMAND_OK != PQresultStatus (result))
-  {
-    ret = GNUNET_SYSERR;
-    BREAK_DB_ERR (result);
-  }
-  else
-  {
-    ret = GNUNET_OK;
-  }
-  PQclear (result);
-  return ret;
+  check_connection (pg);
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                            "insert_transaction",
+                                            params);
 }
 
 
@@ -619,51 +708,46 @@ postgres_store_transaction (void *cls,
  * @param coin_pub public key of the coin
  * @param amount_with_fee amount the exchange will deposit for this coin
  * @param deposit_fee fee the exchange will charge for this coin
+ * @param refund_fee fee the exchange will charge for refunding this coin
  * @param signkey_pub public key used by the exchange for @a exchange_proof
  * @param exchange_proof proof from exchange that coin was accepted
- * @return #GNUNET_OK on success, #GNUNET_SYSERR upon error
+ * @return transaction status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_store_deposit (void *cls,
                         const struct GNUNET_HashCode *h_contract_terms,
                         const struct TALER_MerchantPublicKeyP *merchant_pub,
                         const struct TALER_CoinSpendPublicKeyP *coin_pub,
                         const struct TALER_Amount *amount_with_fee,
                         const struct TALER_Amount *deposit_fee,
+                        const struct TALER_Amount *refund_fee,
                         const struct TALER_ExchangePublicKeyP *signkey_pub,
                         const json_t *exchange_proof)
 {
   struct PostgresClosure *pg = cls;
-  PGresult *result;
-  int ret;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
     GNUNET_PQ_query_param_auto_from_type (coin_pub),
     TALER_PQ_query_param_amount (amount_with_fee),
     TALER_PQ_query_param_amount (deposit_fee),
+    TALER_PQ_query_param_amount (refund_fee),
     GNUNET_PQ_query_param_auto_from_type (signkey_pub),
     TALER_PQ_query_param_json (exchange_proof),
     GNUNET_PQ_query_param_end
   };
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "storing payment for h_contract_terms '%s'\n",
-              GNUNET_h2s (h_contract_terms));
-  result = GNUNET_PQ_exec_prepared (pg->conn,
-                                    "insert_deposit",
-                                    params);
-  if (PGRES_COMMAND_OK != PQresultStatus (result))
-  {
-    ret = GNUNET_SYSERR;
-    BREAK_DB_ERR (result);
-  }
-  else
-  {
-    ret = GNUNET_OK;
-  }
-  PQclear (result);
-  return ret;
+              "storing payment for h_contract_terms '%s'"
+              ", coin_pub: %s, amount_with_fee: %s, merchant_pub: %s\n",
+              GNUNET_h2s (h_contract_terms),
+              TALER_B2S (coin_pub),
+              TALER_amount_to_string (amount_with_fee),
+              TALER_B2S (merchant_pub));
+  check_connection (pg);
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                            "insert_deposit",
+                                            params);
 }
 
 
@@ -676,18 +760,15 @@ postgres_store_deposit (void *cls,
  * @param coin_pub public key of the coin
  * @param wtid identifier of the wire transfer in which the exchange
  *             send us the money for the coin deposit
- * @return #GNUNET_OK on success, #GNUNET_SYSERR upon error
+ * @return transaction status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_store_coin_to_transfer (void *cls,
                                  const struct GNUNET_HashCode 
*h_contract_terms,
                                  const struct TALER_CoinSpendPublicKeyP 
*coin_pub,
                                  const struct TALER_WireTransferIdentifierRawP 
*wtid)
 {
   struct PostgresClosure *pg = cls;
-  PGresult *result;
-  int ret;
-
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
     GNUNET_PQ_query_param_auto_from_type (coin_pub),
@@ -695,20 +776,10 @@ postgres_store_coin_to_transfer (void *cls,
     GNUNET_PQ_query_param_end
   };
 
-  result = GNUNET_PQ_exec_prepared (pg->conn,
-                                    "insert_transfer",
-                                    params);
-  if (PGRES_COMMAND_OK != PQresultStatus (result))
-  {
-    ret = GNUNET_SYSERR;
-    BREAK_DB_ERR (result);
-  }
-  else
-  {
-    ret = GNUNET_OK;
-  }
-  PQclear (result);
-  return ret;
+  check_connection (pg);
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                            "insert_transfer",
+                                            params);
 }
 
 
@@ -721,9 +792,9 @@ postgres_store_coin_to_transfer (void *cls,
  * @param execution_time when was @a wtid executed
  * @param signkey_pub public key used by the exchange for @a exchange_proof
  * @param exchange_proof proof from exchange about what the deposit was for
- * @return #GNUNET_OK on success, #GNUNET_SYSERR upon error
+ * @return transaction status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_store_transfer_to_proof (void *cls,
                                   const char *exchange_uri,
                                   const struct 
TALER_WireTransferIdentifierRawP *wtid,
@@ -732,9 +803,6 @@ postgres_store_transfer_to_proof (void *cls,
                                   const json_t *exchange_proof)
 {
   struct PostgresClosure *pg = cls;
-  PGresult *result;
-  int ret;
-
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_string (exchange_uri),
     GNUNET_PQ_query_param_auto_from_type (wtid),
@@ -744,22 +812,13 @@ postgres_store_transfer_to_proof (void *cls,
     GNUNET_PQ_query_param_end
   };
 
-  result = GNUNET_PQ_exec_prepared (pg->conn,
-                                    "insert_proof",
-                                    params);
-  if (PGRES_COMMAND_OK != PQresultStatus (result))
-  {
-    ret = GNUNET_SYSERR;
-    BREAK_DB_ERR (result);
-  }
-  else
-  {
-    ret = GNUNET_OK;
-  }
-  PQclear (result);
-  return ret;
+  check_connection (pg);
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                            "insert_proof",
+                                            params);
 }
 
+
 /**
  * Lookup for a proposal, respecting the signature used by the
  * /history's db methods.
@@ -769,64 +828,112 @@ postgres_store_transfer_to_proof (void *cls,
  * @param merchant_pub public key of the merchant using this method
  * @param cb the callback
  * @param cb_cls closure to pass to the callback
- * @return GNUNET_YES, GNUNET_NO, GNUNET_SYSERR according to the
- * query being successful, unsuccessful, or generated errors.
+ * @return transaction status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_find_contract_terms_history (void *cls,
-                                     const char *order_id,
-                                     const struct TALER_MerchantPublicKeyP 
*merchant_pub,
-                                     TALER_MERCHANTDB_ProposalDataCallback cb,
-                                     void *cb_cls)
+                                     const char *order_id,
+                                     const struct TALER_MerchantPublicKeyP 
*merchant_pub,
+                                     TALER_MERCHANTDB_ProposalDataCallback cb,
+                                     void *cb_cls)
 {
   struct PostgresClosure *pg = cls;
-  PGresult *result;
-  unsigned int i;
   json_t *contract_terms;
-
+  enum GNUNET_DB_QueryStatus qs;
   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_end
   };
-
-  result = GNUNET_PQ_exec_prepared (pg->conn,
-                                    "find_contract_terms",
-                                    params);
-  i = PQntuples (result);
-  if (1 < i)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Mupltiple proposal data share the same hashcode.\n");
-    return GNUNET_SYSERR;
-  }
-
-  if (0 == i)
-    return GNUNET_NO;
-
   struct GNUNET_PQ_ResultSpec rs[] = {
     TALER_PQ_result_spec_json ("contract_terms",
                                &contract_terms),
     GNUNET_PQ_result_spec_end
   };
-  if (GNUNET_OK !=
-      GNUNET_PQ_extract_result (result,
-                                rs,
-                                0))
-  {
-    GNUNET_break (0);
-    PQclear (result);
-    return GNUNET_SYSERR;
-  }
 
+  qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                "find_contract_terms",
+                                                params,
+                                                rs);
+  if (qs <= 0)
+    return qs;
   cb (cb_cls,
       order_id,
       0,
       contract_terms);
+  GNUNET_PQ_cleanup_result (rs);
+  return qs;
+}
 
-  PQclear (result);
-  return GNUNET_OK;
 
+/**
+ * Closure for #find_contracts_cb().
+ */
+struct FindContractsContext
+{
+  /**
+   * Function to call on each result.
+   */
+  TALER_MERCHANTDB_ProposalDataCallback cb;
+
+  /**
+   * Closure for @e cb.
+   */
+  void *cb_cls;
+
+  /**
+   * 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.
+ *
+ * @param cls of type `struct FindContractsContext *`
+ * @param result the postgres result
+ * @param num_result the number of results in @a result
+ */
+static void
+find_contracts_cb (void *cls,
+                  PGresult *result,
+                  unsigned int num_results)
+{
+  struct FindContractsContext *fcctx = cls;
+  
+  for (unsigned int i = 0; i < num_results; i++)
+  {
+    char *order_id;
+    json_t *contract_terms;
+    uint64_t row_id;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      GNUNET_PQ_result_spec_string ("order_id",
+                                    &order_id),
+      TALER_PQ_result_spec_json ("contract_terms",
+                                 &contract_terms),
+      GNUNET_PQ_result_spec_uint64 ("row_id",
+                                    &row_id),
+      GNUNET_PQ_result_spec_end
+    };
+
+    if (GNUNET_OK !=
+        GNUNET_PQ_extract_result (result,
+                                  rs,
+                                  i))
+    {
+      GNUNET_break (0);
+      fcctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
+      return;
+    }
+    fcctx->qs = i + 1;
+    fcctx->cb (fcctx->cb_cls,
+              order_id,
+              row_id,
+              contract_terms);
+    GNUNET_PQ_cleanup_result (rs);
+  }
 }
 
 
@@ -853,88 +960,47 @@ postgres_find_contract_terms_history (void *cls,
  * Web interface.
  * @param cb function to call with transaction data, can be NULL.
  * @param cb_cls closure for @a cb
- * @return numer of found tuples, #GNUNET_SYSERR upon error
+ * @return transaction status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_find_contract_terms_by_date_and_range (void *cls,
-                                               struct GNUNET_TIME_Absolute 
date,
-                                               const struct 
TALER_MerchantPublicKeyP *merchant_pub,
-                                               unsigned int start,
-                                               unsigned int nrows,
-                                               unsigned int future,
-                                               
TALER_MERCHANTDB_ProposalDataCallback cb,
-                                               void *cb_cls)
+                                               struct GNUNET_TIME_Absolute 
date,
+                                               const struct 
TALER_MerchantPublicKeyP *merchant_pub,
+                                               uint64_t start,
+                                               uint64_t nrows,
+                                               int future,
+                                               
TALER_MERCHANTDB_ProposalDataCallback cb,
+                                               void *cb_cls)
 {
-  uint64_t s64 = start;
-  uint64_t r64 = nrows;
   struct PostgresClosure *pg = cls;
-  PGresult *result;
-  unsigned int n;
   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 (&s64),
-    GNUNET_PQ_query_param_uint64 (&r64),
+    GNUNET_PQ_query_param_uint64 (&start),
+    GNUNET_PQ_query_param_uint64 (&nrows),
     GNUNET_PQ_query_param_end
   };
+  const char *stmt;
+  enum GNUNET_DB_QueryStatus qs;
+  struct FindContractsContext fcctx = {
+    .cb = cb,
+    .cb_cls = cb_cls
+  };
 
   if (GNUNET_YES == future)
-    result = GNUNET_PQ_exec_prepared (pg->conn,
-                                      
"find_contract_terms_by_date_and_range_future",
-                                      params);
+    stmt = "find_contract_terms_by_date_and_range_future";
   else
-    result = GNUNET_PQ_exec_prepared (pg->conn,
-                                      "find_contract_terms_by_date_and_range",
-                                      params);
-  if (PGRES_TUPLES_OK != PQresultStatus (result))
-  {
-    BREAK_DB_ERR (result);
-    PQclear (result);
-    return GNUNET_SYSERR;
-  }
-  if ( (0 == (n = PQntuples (result))) ||
-       (NULL == cb) )
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "No records found.\n");
-    PQclear (result);
-    return n;
-  }
-  for (unsigned int i = 0; i < n; i++)
-  {
-    char *order_id;
-    json_t *contract_terms;
-    uint64_t row_id;
-
-    struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_string ("order_id",
-                                    &order_id),
-      TALER_PQ_result_spec_json ("contract_terms",
-                                 &contract_terms),
-      GNUNET_PQ_result_spec_uint64 ("row_id",
-                                    &row_id),
-      GNUNET_PQ_result_spec_end
-    };
-
-    if (GNUNET_OK !=
-        GNUNET_PQ_extract_result (result,
-                                  rs,
-                                  i))
-    {
-      GNUNET_break (0);
-      PQclear (result);
-      return GNUNET_SYSERR;
-    }
-    cb (cb_cls,
-        order_id,
-        row_id,
-        contract_terms);
-
-    GNUNET_PQ_cleanup_result (rs);
-  }
-  PQclear (result);
-  return n;
-}
+    stmt = "find_contract_terms_by_date_and_range";
+  check_connection (pg);
+  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+                                            stmt,
+                                            params,
+                                            &find_contracts_cb,
+                                            &fcctx);
+  if (0 >= qs)
+    return qs;
+  return fcctx.qs;
+}
 
 
 /**
@@ -948,79 +1014,41 @@ postgres_find_contract_terms_by_date_and_range (void 
*cls,
  * @param nrows at most nrows rows are returned.
  * @param cb function to call with transaction data, can be NULL.
  * @param cb_cls closure for @a cb
- * @return numer of found tuples, #GNUNET_SYSERR upon error
+ * @return transaction status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_find_contract_terms_by_date (void *cls,
-                                     struct GNUNET_TIME_Absolute date,
-                                     const struct TALER_MerchantPublicKeyP 
*merchant_pub,
-                                     unsigned int nrows,
-                                     TALER_MERCHANTDB_ProposalDataCallback cb,
-                                     void *cb_cls)
+                                     struct GNUNET_TIME_Absolute date,
+                                     const struct TALER_MerchantPublicKeyP 
*merchant_pub,
+                                     uint64_t nrows,
+                                     TALER_MERCHANTDB_ProposalDataCallback cb,
+                                     void *cb_cls)
 {
-
-  uint64_t r64 = nrows;
   struct PostgresClosure *pg = cls;
-  PGresult *result;
-  unsigned int n;
-  unsigned int i;
-
   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 (&r64),
+    GNUNET_PQ_query_param_uint64 (&nrows),
     GNUNET_PQ_query_param_end
   };
-  result = GNUNET_PQ_exec_prepared (pg->conn,
-                                    "find_contract_terms_by_date",
-                                    params);
-  if (PGRES_TUPLES_OK != PQresultStatus (result))
-  {
-    BREAK_DB_ERR (result);
-    PQclear (result);
-    return GNUNET_SYSERR;
-  }
-  if (0 == (n = PQntuples (result)) || NULL == cb)
-  {
-    PQclear (result);
-    return n;
-  }
-  for (i = 0; i < n; i++)
-  {
-    char *order_id;
-    json_t *contract_terms;
-    uint64_t row_id;
-
-    struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_string ("order_id",
-                                    &order_id),
-      TALER_PQ_result_spec_json ("contract_terms",
-                                 &contract_terms),
-      GNUNET_PQ_result_spec_uint64 ("row_id",
-                                    &row_id),
-      GNUNET_PQ_result_spec_end
-    };
-
-    if (GNUNET_OK !=
-        GNUNET_PQ_extract_result (result,
-                                  rs,
-                                  i))
-    {
-      GNUNET_break (0);
-      PQclear (result);
-      return GNUNET_SYSERR;
-    }
-    cb (cb_cls,
-        order_id,
-        row_id,
-        contract_terms);
+  enum GNUNET_DB_QueryStatus qs;
+  struct FindContractsContext fcctx = {
+    .cb = cb,
+    .cb_cls = cb_cls
+  };
 
-    GNUNET_PQ_cleanup_result (rs);
-  }
-  PQclear (result);
-  return n;
+  check_connection (pg);
+  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+                                            "find_contract_terms_by_date",
+                                            params,
+                                            &find_contracts_cb,
+                                            &fcctx);
+  if (0 >= qs)
+    return qs;
+  return fcctx.qs;
 }
 
+
 /**
  * Find information about a transaction.
  *
@@ -1029,10 +1057,9 @@ postgres_find_contract_terms_by_date (void *cls,
  * @param merchant_pub merchant's public key
  * @param cb function to call with transaction data
  * @param cb_cls closure for @a cb
- * @return #GNUNET_OK if found, #GNUNET_NO if not, #GNUNET_SYSERR
- *         upon error
+ * @return transaction status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_find_transaction (void *cls,
                            const struct GNUNET_HashCode *h_contract_terms,
                           const struct TALER_MerchantPublicKeyP *merchant_pub,
@@ -1040,84 +1067,139 @@ postgres_find_transaction (void *cls,
                            void *cb_cls)
 {
   struct PostgresClosure *pg = cls;
-  PGresult *result;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
     GNUNET_PQ_query_param_end
   };
+  char *exchange_uri;
+  struct GNUNET_HashCode h_wire;
+  struct GNUNET_TIME_Absolute timestamp;
+  struct GNUNET_TIME_Absolute refund_deadline;
+  struct TALER_Amount total_amount;
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_string ("exchange_uri",
+                                 &exchange_uri),
+    GNUNET_PQ_result_spec_auto_from_type ("h_wire",
+                                         &h_wire),
+    GNUNET_PQ_result_spec_absolute_time ("timestamp",
+                                        &timestamp),
+    GNUNET_PQ_result_spec_absolute_time ("refund_deadline",
+                                        &refund_deadline),
+    TALER_PQ_result_spec_amount ("total_amount",
+                                &total_amount),
+    GNUNET_PQ_result_spec_end
+  };
+  enum GNUNET_DB_QueryStatus qs;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Finding transaction for h_contract_terms '%s', merchant_pub: 
'%s'.\n",
               GNUNET_h2s (h_contract_terms),
               TALER_B2S (merchant_pub));
 
-  result = GNUNET_PQ_exec_prepared (pg->conn,
-                                    "find_transaction",
-                                    params);
-  if (PGRES_TUPLES_OK != PQresultStatus (result))
+  check_connection (pg);
+  qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                "find_transaction",
+                                                params,
+                                                rs);
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
   {
-    BREAK_DB_ERR (result);
-    PQclear (result);
-    return GNUNET_SYSERR;
+    cb (cb_cls,
+       merchant_pub,
+        exchange_uri,
+        h_contract_terms,
+        &h_wire,
+        timestamp,
+        refund_deadline,
+        &total_amount);
+    GNUNET_PQ_cleanup_result (rs);
   }
-  if (0 == PQntuples (result))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Could NOT find transaction for h_contract_terms '%s'\n",
-                GNUNET_h2s (h_contract_terms));
+  return qs;
+}
+
+
+/**
+ * Closure for #find_payments_cb().
+ */
+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).
+   */
+  enum GNUNET_DB_QueryStatus qs;
+};
 
-    PQclear (result);
-    return GNUNET_NO;
-  }
-  if (1 != PQntuples (result))
-  {
-    GNUNET_break (0);
-    PQclear (result);
-    return GNUNET_SYSERR;
-  }
 
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results.
+ *
+ * @param cls of type `struct FindPaymentsContext *`
+ * @param result the postgres result
+ * @param num_result the number of results in @a result
+ */
+static void
+find_payments_cb (void *cls,
+                 PGresult *result,
+                 unsigned int num_results)
+{
+  struct FindPaymentsContext *fpc = cls;
+  
+  for (unsigned int i=0;i<num_results;i++)
   {
-    char *exchange_uri;
-    struct GNUNET_HashCode h_wire;
-    struct GNUNET_TIME_Absolute timestamp;
-    struct GNUNET_TIME_Absolute refund_deadline;
-    struct TALER_Amount total_amount;
+    struct TALER_CoinSpendPublicKeyP coin_pub;
+    struct TALER_Amount amount_with_fee;
+    struct TALER_Amount deposit_fee;
+    struct TALER_Amount refund_fee;
+    json_t *exchange_proof;
     struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_string ("exchange_uri",
-                                    &exchange_uri),
-      GNUNET_PQ_result_spec_auto_from_type ("h_wire",
-                                            &h_wire),
-      GNUNET_PQ_result_spec_absolute_time ("timestamp",
-                                           &timestamp),
-      GNUNET_PQ_result_spec_absolute_time ("refund_deadline",
-                                           &refund_deadline),
-      TALER_PQ_result_spec_amount ("total_amount",
-                                   &total_amount),
+      GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+                                            &coin_pub),
+      TALER_PQ_result_spec_amount ("amount_with_fee",
+                                   &amount_with_fee),
+      TALER_PQ_result_spec_amount ("deposit_fee",
+                                   &deposit_fee),
+      TALER_PQ_result_spec_amount ("refund_fee",
+                                   &refund_fee),
+      TALER_PQ_result_spec_json ("exchange_proof",
+                                 &exchange_proof),
       GNUNET_PQ_result_spec_end
     };
 
     if (GNUNET_OK !=
         GNUNET_PQ_extract_result (result,
                                   rs,
-                                  0))
+                                  i))
     {
       GNUNET_break (0);
-      PQclear (result);
-      return GNUNET_SYSERR;
+      fpc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+      return;
     }
-    cb (cb_cls,
-       merchant_pub,
-        exchange_uri,
-        h_contract_terms,
-        &h_wire,
-        timestamp,
-        refund_deadline,
-        &total_amount);
+    fpc->qs = i + 1;
+    fpc->cb (fpc->cb_cls,
+            fpc->h_contract_terms,
+            &coin_pub,
+            &amount_with_fee,
+            &deposit_fee,
+            &refund_fee,
+            exchange_proof);
     GNUNET_PQ_cleanup_result (rs);
   }
-  PQclear (result);
-  return GNUNET_OK;
 }
 
 
@@ -1130,10 +1212,9 @@ postgres_find_transaction (void *cls,
  * @param merchant_pub merchant's public key
  * @param cb function to call with payment data
  * @param cb_cls closure for @a cb
- * @return #GNUNET_OK on success, #GNUNET_NO if transaction Id is unknown,
- *         #GNUNET_SYSERR on hard errors
+ * @return transaction status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_find_payments (void *cls,
                         const struct GNUNET_HashCode *h_contract_terms,
                        const struct TALER_MerchantPublicKeyP *merchant_pub,
@@ -1141,46 +1222,93 @@ postgres_find_payments (void *cls,
                         void *cb_cls)
 {
   struct PostgresClosure *pg = cls;
-  PGresult *result;
-  unsigned int i;
-
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
     GNUNET_PQ_query_param_end
   };
+  struct FindPaymentsContext fpc = {
+    .h_contract_terms = h_contract_terms,
+    .cb = cb,
+    .cb_cls = cb_cls
+  };
+  enum GNUNET_DB_QueryStatus qs;
+  
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "finding payment for h_contract_terms '%s'\n",
+              "Finding payment for h_contract_terms '%s'\n",
               GNUNET_h2s (h_contract_terms));
-  result = GNUNET_PQ_exec_prepared (pg->conn,
-                                    "find_deposits",
-                                    params);
-  if (PGRES_TUPLES_OK != PQresultStatus (result))
-  {
-    BREAK_DB_ERR (result);
-    PQclear (result);
-    return GNUNET_SYSERR;
-  }
-  if (0 == PQntuples (result))
-  {
-    PQclear (result);
-    return GNUNET_NO;
-  }
+  check_connection (pg);
+  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+                                            "find_deposits",
+                                            params,
+                                            &find_payments_cb,
+                                            &fpc);
+  if (qs <= 0)
+    return qs;
+  return fpc.qs;
+}
+
 
-  for (i=0;i<PQntuples (result);i++)
+/**
+ * Closure for #find_payments_by_coin_cb().
+ */
+struct FindPaymentsByCoinContext
+{
+  /**
+   * Function to call with results.
+   */
+  TALER_MERCHANTDB_CoinDepositCallback cb;
+  
+  /**
+   * Closure for @e cls.
+   */
+  void *cb_cls;
+
+  /**
+   * 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).
+   */
+  enum GNUNET_DB_QueryStatus qs;
+};
+
+
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results.
+ *
+ * @param cls of type `struct FindPaymentsByCoinContext *`
+ * @param result the postgres result
+ * @param num_result the number of results in @a result
+ */
+static void
+find_payments_by_coin_cb (void *cls,
+                         PGresult *result,
+                         unsigned int num_results)
+{
+  struct FindPaymentsByCoinContext *fpc = cls;
+  
+  for (unsigned int i=0;i<num_results;i++)
   {
-    struct TALER_CoinSpendPublicKeyP coin_pub;
     struct TALER_Amount amount_with_fee;
     struct TALER_Amount deposit_fee;
+    struct TALER_Amount refund_fee;
     json_t *exchange_proof;
-
     struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
-                                            &coin_pub),
       TALER_PQ_result_spec_amount ("amount_with_fee",
                                    &amount_with_fee),
       TALER_PQ_result_spec_amount ("deposit_fee",
                                    &deposit_fee),
+      TALER_PQ_result_spec_amount ("refund_fee",
+                                   &refund_fee),
       TALER_PQ_result_spec_json ("exchange_proof",
                                  &exchange_proof),
       GNUNET_PQ_result_spec_end
@@ -1192,22 +1320,19 @@ postgres_find_payments (void *cls,
                                   i))
     {
       GNUNET_break (0);
-      PQclear (result);
-      return GNUNET_SYSERR;
+      fpc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+      return;
     }
-    cb (cb_cls,
-        h_contract_terms,
-        &coin_pub,
-        &amount_with_fee,
-        &deposit_fee,
-        exchange_proof);
+    fpc->qs = i + 1;
+    fpc->cb (fpc->cb_cls,
+            fpc->h_contract_terms,
+            fpc->coin_pub,
+            &amount_with_fee,
+            &deposit_fee,
+            &refund_fee,
+            exchange_proof);
     GNUNET_PQ_cleanup_result (rs);
   }
-  PQclear (result);
-  return GNUNET_OK;
-
-  GNUNET_break (0);
-  return GNUNET_SYSERR;
 }
 
 
@@ -1220,10 +1345,9 @@ postgres_find_payments (void *cls,
  * @param coin_pub coin's public key used for the search
  * @param cb function to call with payment data
  * @param cb_cls closure for @a cb
- * @return #GNUNET_OK on success, #GNUNET_NO if transaction Id is unknown,
- *         #GNUNET_SYSERR on hard errors
+ * @return transaction status
  */
-static int
+static enum GNUNET_DB_QueryStatus
 postgres_find_payments_by_hash_and_coin (void *cls,
                                          const struct GNUNET_HashCode 
*h_contract_terms,
                                          const struct TALER_MerchantPublicKeyP 
*merchant_pub,
@@ -1232,116 +1356,75 @@ postgres_find_payments_by_hash_and_coin (void *cls,
                                          void *cb_cls)
 {
   struct PostgresClosure *pg = cls;
-  PGresult *result;
-  unsigned int i;
-
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
     GNUNET_PQ_query_param_auto_from_type (merchant_pub),
     GNUNET_PQ_query_param_auto_from_type (coin_pub),
     GNUNET_PQ_query_param_end
   };
+  struct FindPaymentsByCoinContext fpc = {
+    .cb = cb,
+    .cb_cls = cb_cls,
+    .h_contract_terms = h_contract_terms,
+    .coin_pub = coin_pub
+  };
+  enum GNUNET_DB_QueryStatus qs;
+
+  check_connection (pg);
+  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+                                            "find_deposits_by_hash_and_coin",
+                                            params,
+                                            &find_payments_by_coin_cb,
+                                            &fpc);
+  if (0 >= qs)
+    return qs;
+  return fpc.qs;
+}
 
-  result = GNUNET_PQ_exec_prepared (pg->conn,
-                                    "find_deposits_by_hash_and_coin",
-                                    params);
-  if (PGRES_TUPLES_OK != PQresultStatus (result))
-  {
-    BREAK_DB_ERR (result);
-    PQclear (result);
-    return GNUNET_SYSERR;
-  }
-  if (0 == PQntuples (result))
-  {
-    PQclear (result);
-    return GNUNET_NO;
-  }
-
-  for (i=0;i<PQntuples (result);i++)
-  {
-    struct TALER_Amount amount_with_fee;
-    struct TALER_Amount deposit_fee;
-    json_t *exchange_proof;
 
-    struct GNUNET_PQ_ResultSpec rs[] = {
-      TALER_PQ_result_spec_amount ("amount_with_fee",
-                                   &amount_with_fee),
-      TALER_PQ_result_spec_amount ("deposit_fee",
-                                   &deposit_fee),
-      TALER_PQ_result_spec_json ("exchange_proof",
-                                 &exchange_proof),
-      GNUNET_PQ_result_spec_end
-    };
+/**
+ * Closure for #find_transfers_cb().
+ */
+struct FindTransfersContext
+{
+  /**
+   * Function to call on results.
+   */
+  TALER_MERCHANTDB_TransferCallback cb;
 
-    if (GNUNET_OK !=
-        GNUNET_PQ_extract_result (result,
-                                  rs,
-                                  i))
-    {
-      GNUNET_break (0);
-      PQclear (result);
-      return GNUNET_SYSERR;
-    }
-    cb (cb_cls,
-        h_contract_terms,
-        coin_pub,
-        &amount_with_fee,
-        &deposit_fee,
-        exchange_proof);
-    GNUNET_PQ_cleanup_result (rs);
-  }
-  PQclear (result);
-  return GNUNET_OK;
+  /**
+   * Closure for @e cb.
+   */
+  void *cb_cls;
 
-  GNUNET_break (0);
-  return GNUNET_SYSERR;
-}
+  /** 
+   * Hash of the contract we are looking under.
+   */
+  const struct GNUNET_HashCode *h_contract_terms;
+  
+  /**
+   * Transaction status (set).
+   */
+  enum GNUNET_DB_QueryStatus qs;
+};
 
 
 /**
- * Lookup information about a transfer by @a h_contract_terms.  Note
- * that in theory there could be multiple wire transfers for a
- * single @a h_contract_terms, as the transaction may have involved
- * multiple coins and the coins may be spread over different wire
- * transfers.
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results.
  *
- * @param cls closure
- * @param h_contract_terms key for the search
- * @param cb function to call with transfer data
- * @param cb_cls closure for @a cb
- * @return #GNUNET_OK on success, #GNUNET_NO if transaction Id is unknown,
- *         #GNUNET_SYSERR on hard errors
+ * @param cls of type `struct FindTransfersContext *`
+ * @param result the postgres result
+ * @param num_result the number of results in @a result
  */
-static int
-postgres_find_transfers_by_hash (void *cls,
-                                 const struct GNUNET_HashCode 
*h_contract_terms,
-                                 TALER_MERCHANTDB_TransferCallback cb,
-                                 void *cb_cls)
+static void
+find_transfers_cb (void *cls,
+                  PGresult *result,
+                  unsigned int num_results)
 {
-  struct PostgresClosure *pg = cls;
-  PGresult *result;
-  unsigned int i;
+  struct FindTransfersContext *ftc = cls;
 
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
-    GNUNET_PQ_query_param_end
-  };
-  result = GNUNET_PQ_exec_prepared (pg->conn,
-                                    "find_transfers_by_hash",
-                                    params);
-  if (PGRES_TUPLES_OK != PQresultStatus (result))
-  {
-    BREAK_DB_ERR (result);
-    PQclear (result);
-    return GNUNET_SYSERR;
-  }
-  if (0 == PQntuples (result))
-  {
-    PQclear (result);
-    return GNUNET_NO;
-  }
-
-  for (i=0;i<PQntuples (result);i++)
+  for (unsigned int i=0;i<PQntuples (result);i++)
   {
     struct TALER_CoinSpendPublicKeyP coin_pub;
     struct TALER_WireTransferIdentifierRawP wtid;
@@ -1366,69 +1449,110 @@ postgres_find_transfers_by_hash (void *cls,
                                   i))
     {
       GNUNET_break (0);
-      PQclear (result);
-      return GNUNET_SYSERR;
+      ftc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+      return;
     }
-    cb (cb_cls,
-        h_contract_terms,
-        &coin_pub,
-        &wtid,
-        execution_time,
-        proof);
+    ftc->qs = i + 1;
+    ftc->cb (ftc->cb_cls,
+            ftc->h_contract_terms,
+            &coin_pub,
+            &wtid,
+            execution_time,
+            proof);
     GNUNET_PQ_cleanup_result (rs);
   }
-  PQclear (result);
-  return GNUNET_OK;
 }
-
+  
 
 /**
- * Lookup information about a coin deposits by @a wtid.
+ * Lookup information about a transfer by @a h_contract_terms.  Note
+ * that in theory there could be multiple wire transfers for a
+ * single @a h_contract_terms, as the transaction may have involved
+ * multiple coins and the coins may be spread over different wire
+ * transfers.
  *
  * @param cls closure
- * @param wtid wire transfer identifier to find matching transactions for
- * @param cb function to call with payment data
+ * @param h_contract_terms key for the search
+ * @param cb function to call with transfer data
  * @param cb_cls closure for @a cb
- * @return #GNUNET_OK on success, #GNUNET_NO if transaction Id is unknown,
- *         #GNUNET_SYSERR on hard errors
+ * @return transaction status
  */
-static int
-postgres_find_deposits_by_wtid (void *cls,
-                                const struct TALER_WireTransferIdentifierRawP 
*wtid,
-                                TALER_MERCHANTDB_CoinDepositCallback cb,
-                                void *cb_cls)
+static enum GNUNET_DB_QueryStatus
+postgres_find_transfers_by_hash (void *cls,
+                                 const struct GNUNET_HashCode 
*h_contract_terms,
+                                 TALER_MERCHANTDB_TransferCallback cb,
+                                 void *cb_cls)
 {
   struct PostgresClosure *pg = cls;
-  PGresult *result;
-  unsigned int i;
-
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (wtid),
+    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
     GNUNET_PQ_query_param_end
   };
-  result = GNUNET_PQ_exec_prepared (pg->conn,
-                                    "find_deposits_by_wtid",
-                                    params);
-  if (PGRES_TUPLES_OK != PQresultStatus (result))
-  {
-    BREAK_DB_ERR (result);
-    PQclear (result);
-    return GNUNET_SYSERR;
-  }
-  if (0 == PQntuples (result))
-  {
-    PQclear (result);
-    return GNUNET_NO;
-  }
+  struct FindTransfersContext ftc = {
+    .h_contract_terms = h_contract_terms,
+    .cb = cb,
+    .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",
+                                            params,
+                                            &find_transfers_cb,
+                                            &ftc);
+  if (0 >= qs)
+    return qs;
+  return ftc.qs;
+}
+
 
-  for (i=0;i<PQntuples (result);i++)
+/**
+ * Closure for #find_deposits_cb().
+ */
+struct FindDepositsContext
+{
+
+  /**
+   * Function to call for each result.
+   */ 
+  TALER_MERCHANTDB_CoinDepositCallback cb;
+
+  /**
+   * Closure for @e cb.
+   */
+  void *cb_cls;
+  
+  /**
+   * Transaction status (set).
+   */
+  enum GNUNET_DB_QueryStatus qs;
+};
+
+
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results.
+ *
+ * @param cls of type `struct FindDepositsContext *`
+ * @param result the postgres result
+ * @param num_result the number of results in @a result
+ */
+static void
+find_deposits_cb (void *cls,
+                 PGresult *result,
+                 unsigned int num_results)
+{
+  struct FindDepositsContext *fdc = cls;
+
+  for (unsigned int i=0;i<PQntuples (result);i++)
   {
     struct GNUNET_HashCode h_contract_terms;
     struct TALER_CoinSpendPublicKeyP coin_pub;
     struct TALER_Amount amount_with_fee;
     struct TALER_Amount deposit_fee;
+    struct TALER_Amount refund_fee;
     json_t *exchange_proof;
-
     struct GNUNET_PQ_ResultSpec rs[] = {
       GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
                                             &h_contract_terms),
@@ -1438,6 +1562,8 @@ postgres_find_deposits_by_wtid (void *cls,
                                    &amount_with_fee),
       TALER_PQ_result_spec_amount ("deposit_fee",
                                    &deposit_fee),
+      TALER_PQ_result_spec_amount ("refund_fee",
+                                   &refund_fee),
       TALER_PQ_result_spec_json ("exchange_proof",
                                  &exchange_proof),
       GNUNET_PQ_result_spec_end
@@ -1449,93 +1575,713 @@ postgres_find_deposits_by_wtid (void *cls,
                                   i))
     {
       GNUNET_break (0);
-      PQclear (result);
-      return GNUNET_SYSERR;
+      fdc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+      return;
     }
-    cb (cb_cls,
-        &h_contract_terms,
-        &coin_pub,
-        &amount_with_fee,
-        &deposit_fee,
-        exchange_proof);
+    fdc->qs = i + 1;
+    fdc->cb (fdc->cb_cls,
+            &h_contract_terms,
+            &coin_pub,
+            &amount_with_fee,
+            &deposit_fee,
+            &refund_fee,
+            exchange_proof);
     GNUNET_PQ_cleanup_result (rs);
   }
-  PQclear (result);
-  return GNUNET_OK;
 }
 
 
 /**
- * Lookup proof information about a wire transfer.
+ * Lookup information about a coin deposits by @a wtid.
  *
  * @param cls closure
- * @param exchange_uri from which exchange are we looking for proof
- * @param wtid wire transfer identifier for the search
- * @param cb function to call with proof data
+ * @param wtid wire transfer identifier to find matching transactions for
+ * @param cb function to call with payment data
  * @param cb_cls closure for @a cb
- * @return #GNUNET_OK on success, #GNUNET_NO if transaction Id is unknown,
- *         #GNUNET_SYSERR on hard errors
+ * @return transaction status
  */
-static int
-postgres_find_proof_by_wtid (void *cls,
-                             const char *exchange_uri,
-                             const struct TALER_WireTransferIdentifierRawP 
*wtid,
-                             TALER_MERCHANTDB_ProofCallback cb,
-                             void *cb_cls)
+static enum GNUNET_DB_QueryStatus
+postgres_find_deposits_by_wtid (void *cls,
+                                const struct TALER_WireTransferIdentifierRawP 
*wtid,
+                                TALER_MERCHANTDB_CoinDepositCallback cb,
+                                void *cb_cls)
 {
   struct PostgresClosure *pg = cls;
-  PGresult *result;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_auto_from_type (wtid),
-    GNUNET_PQ_query_param_string (exchange_uri),
     GNUNET_PQ_query_param_end
   };
+  struct FindDepositsContext fdc = {
+    .cb = cb,
+    .cb_cls = cb_cls
+  };
+  enum GNUNET_DB_QueryStatus qs;
+
+  check_connection (pg);
+  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+                                            "find_deposits_by_wtid",
+                                            params,
+                                            &find_deposits_cb,
+                                            &fdc);
+  if (0 >= qs)
+    return qs;
+  return fdc.qs;
+}
 
-  result = GNUNET_PQ_exec_prepared (pg->conn,
-                                    "find_proof_by_wtid",
-                                    params);
-  if (PGRES_TUPLES_OK != PQresultStatus (result))
-  {
-    BREAK_DB_ERR (result);
-    PQclear (result);
-    return GNUNET_SYSERR;
-  }
-  if (0 == PQntuples (result))
+
+/**
+ * Closure for #get_refunds_cb().
+ */
+struct GetRefundsContext
+{
+  /**
+   * Function to call for each refund.
+   */
+  TALER_MERCHANTDB_RefundCallback rc;
+
+  /**
+   * Closure for @e rc.
+   */ 
+  void *rc_cls;
+
+  /**
+   * Transaction result.
+   */
+  enum GNUNET_DB_QueryStatus qs;
+};
+
+
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results.
+ *
+ * @param cls of type `struct GetRefundsContext *`
+ * @param result the postgres result
+ * @param num_result the number of results in @a result
+ */
+static void
+get_refunds_cb (void *cls,
+               PGresult *result,
+               unsigned int num_results)
+{
+  struct GetRefundsContext *grc = cls;
+  
+  for (unsigned int i=0;i<num_results;i++)
   {
-    PQclear (result);
-    return GNUNET_NO;
+    struct TALER_CoinSpendPublicKeyP coin_pub;
+    uint64_t rtransaction_id;
+    struct TALER_Amount refund_amount;
+    struct TALER_Amount refund_fee;
+    char *reason;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+                                            &coin_pub),
+      GNUNET_PQ_result_spec_uint64 ("rtransaction_id",
+                                    &rtransaction_id),
+      TALER_PQ_result_spec_amount ("refund_amount",
+                                   &refund_amount),
+      TALER_PQ_result_spec_amount ("refund_fee",
+                                   &refund_fee),
+      GNUNET_PQ_result_spec_string ("reason",
+                                    &reason),
+      GNUNET_PQ_result_spec_end
+    };
+
+    if (GNUNET_OK !=
+        GNUNET_PQ_extract_result (result,
+                                  rs,
+                                  i))
+    {
+      GNUNET_break (0);
+      grc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+      return;
+    }
+    grc->qs = i + 1;
+    grc->rc (grc->rc_cls,
+            &coin_pub,
+            rtransaction_id,
+            reason,
+            &refund_amount,
+            &refund_fee);
+    GNUNET_PQ_cleanup_result (rs);
   }
-  if (1 != PQntuples (result))
+}
+
+
+/**
+ * Obtain refunds associated with a contract.
+ *
+ * @param cls closure, typically a connection to the db
+ * @param merchant_pub public key of the merchant instance
+ * @param h_contract_terms hash code of the contract
+ * @param rc function to call for each coin on which there is a refund
+ * @param rc_cls closure for @a rc
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_get_refunds_from_contract_terms_hash (void *cls,
+                                               const struct 
TALER_MerchantPublicKeyP *merchant_pub,
+                                               const struct GNUNET_HashCode 
*h_contract_terms,
+                                               TALER_MERCHANTDB_RefundCallback 
rc,
+                                               void *rc_cls)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+    GNUNET_PQ_query_param_end
+  };
+  struct GetRefundsContext grc = {
+    .rc = rc,
+    .rc_cls = rc_cls
+  };
+  enum GNUNET_DB_QueryStatus qs;
+
+  TALER_LOG_DEBUG ("Looking for refund %s + %s\n",
+                   GNUNET_h2s (h_contract_terms),
+                   TALER_B2S (merchant_pub));
+
+  check_connection (pg);
+  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+                                            
"find_refunds_from_contract_terms_hash",
+                                            params,
+                                            &get_refunds_cb,
+                                            &grc);
+  if (0 >= qs)
+    return qs; 
+  return grc.qs; 
+}
+
+
+/**
+ * Insert a refund row into merchant_refunds.  Not meant to be exported
+ * in the db API.
+ *
+ * @param cls closure, tipically a connection to the db
+ * @param merchant_pub merchant instance public key
+ * @param h_contract_terms hashcode of the contract related to this refund
+ * @param coin_pub public key of the coin giving the (part of) refund
+ * @param reason human readable explaination behind the refund
+ * @param refund how much this coin is refunding
+ * @param refund_fee refund fee for this coin
+ */
+enum GNUNET_DB_QueryStatus
+insert_refund (void *cls,
+               const struct TALER_MerchantPublicKeyP *merchant_pub,
+               const struct GNUNET_HashCode *h_contract_terms,
+               const struct TALER_CoinSpendPublicKeyP *coin_pub,
+               const char *reason,
+               const struct TALER_Amount *refund,
+               const struct TALER_Amount *refund_fee)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+    GNUNET_PQ_query_param_auto_from_type (coin_pub),
+    GNUNET_PQ_query_param_string (reason),
+    TALER_PQ_query_param_amount (refund),
+    TALER_PQ_query_param_amount (refund_fee),
+    GNUNET_PQ_query_param_end
+  };
+
+  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",
+                                             params);
+}
+
+
+/**
+ * Store information about wire fees charged by an exchange,
+ * including signature (so we have proof).
+ *
+ * @param cls closure
+ * @paramm 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,
+ *              but needed to check signature)
+ * @param start_date start of fee being used
+ * @param end_date end of fee being used
+ * @param exchange_sig signature of exchange over fee structure
+ * @return transaction status code
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_store_wire_fee_by_exchange (void *cls,
+                                    const struct TALER_MasterPublicKeyP 
*exchange_pub,
+                                    const struct GNUNET_HashCode 
*h_wire_method,
+                                    const struct TALER_Amount *wire_fee,
+                                    const struct TALER_Amount *closing_fee,
+                                    struct GNUNET_TIME_Absolute start_date,
+                                    struct GNUNET_TIME_Absolute end_date,
+                                    const 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),
+    TALER_PQ_query_param_amount (wire_fee),
+    TALER_PQ_query_param_amount (closing_fee),
+    GNUNET_PQ_query_param_absolute_time (&start_date),
+    GNUNET_PQ_query_param_absolute_time (&end_date),
+    GNUNET_PQ_query_param_auto_from_type (exchange_sig),
+    GNUNET_PQ_query_param_end
+  };
+
+  check_connection (pg);
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "insert_wire_fee",
+                                             params);  
+}
+
+
+/**
+ * Closure for #process_refund_cb.
+ */
+struct FindRefundContext
+{
+  /**
+   * Updated to reflect total amount refunded so far.
+   */
+  struct TALER_Amount refunded_amount;
+
+  /**
+   * Set to #GNUNET_SYSERR on hard errors.
+   */
+  int err;
+};
+
+
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results.
+ *
+ * @param cls closure, our `struct FindRefundContext`
+ * @param result the postgres result
+ * @param num_result the number of results in @a result
+ */
+static void
+process_refund_cb (void *cls,
+                   PGresult *result,
+                   unsigned int num_results)
+{
+  struct FindRefundContext *ictx = cls;
+
+  for (unsigned int i=0; i<num_results; i++)
   {
-    GNUNET_break (0);
-    PQclear (result);
-    return GNUNET_SYSERR;
+    /* Sum up existing refunds */
+    struct TALER_Amount acc;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      TALER_PQ_result_spec_amount ("refund_amount",
+                                   &acc),
+      GNUNET_PQ_result_spec_end
+    };
+
+    if (GNUNET_OK !=
+        GNUNET_PQ_extract_result (result,
+                                  rs,
+                                  i))
+    {
+      GNUNET_break (0);
+      ictx->err = GNUNET_SYSERR;
+      return;
+    }
+    if (GNUNET_SYSERR ==
+        TALER_amount_add (&ictx->refunded_amount,
+                          &ictx->refunded_amount,
+                          &acc))
+    {
+      GNUNET_break (0);
+      ictx->err = GNUNET_SYSERR;
+      return;
+    }
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Found refund of %s\n",
+                TALER_amount2s (&acc));
   }
+}
+
 
+/**
+ * Closure for #process_deposits_cb.
+ */
+struct InsertRefundContext
+{
+  /**
+   * Used to provide a connection to the db
+   */
+  struct PostgresClosure *pg;
+
+  /**
+   * Amount to which increase the refund for this contract
+   */
+  const struct TALER_Amount *refund;
+
+  /**
+   * Merchant instance public key
+   */
+  const struct TALER_MerchantPublicKeyP *merchant_pub;
+
+  /**
+   * Hash code representing the contract
+   */
+  const struct GNUNET_HashCode *h_contract_terms;
+
+  /**
+   * Human-readable reason behind this refund
+   */
+  const char *reason;
+
+  /**
+   * Transaction status code.
+   */
+  enum GNUNET_DB_QueryStatus qs;
+};
+
+
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results.
+ *
+ * @param cls closure, our `struct InsertRefundContext`
+ * @param result the postgres result
+ * @param num_result the number of results in @a result
+ */
+static void
+process_deposits_for_refund_cb (void *cls,
+                               PGresult *result,
+                               unsigned int num_results)
+{
+  struct InsertRefundContext *ctx = cls;
+  struct TALER_Amount previous_refund;
+
+  TALER_amount_get_zero (ctx->refund->currency,
+                         &previous_refund);
+
+  for (unsigned int i=0;i<num_results;i++)
   {
-    json_t *proof;
+    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[] = {
-      TALER_PQ_result_spec_json ("proof",
-                                 &proof),
+      GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+                                            &coin_pub),
+      TALER_PQ_result_spec_amount ("amount_with_fee",
+                                   &amount_with_fee),
+      TALER_PQ_result_spec_amount ("refund_fee",
+                                   &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,
                                   rs,
-                                  0))
+                                  i))
+    {
+      GNUNET_break (0);
+      ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
+      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);
+    ictx.err = GNUNET_OK; /* no error so far */
+    ires = GNUNET_PQ_eval_prepared_multi_select (ctx->pg->conn,
+                                                 "find_refunds",
+                                                 params,
+                                                 &process_refund_cb,
+                                                 &ictx);
+    if ( (GNUNET_OK != ictx.err) ||
+         (GNUNET_DB_STATUS_HARD_ERROR == ires) )
+    { 
+      GNUNET_break (0);
+      ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
+      return;
+    }
+    if (GNUNET_DB_STATUS_SOFT_ERROR == ires)
+    {
+      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.
+     */
+    if (GNUNET_SYSERR ==
+       TALER_amount_add (&previous_refund,
+                         &previous_refund,
+                         &ictx.refunded_amount))
+    {
+      GNUNET_break (0);
+      ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
+      return;
+    }
+
+    if (0 >= TALER_amount_cmp (ctx->refund,
+                              &previous_refund))
+    {
+      /* refund <= refunded_amount; nothing to do! */ 
+      ctx->qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
+      return;
+    }
+
+    /* How much of the coin is left after the existing refunds? */
+    if (GNUNET_SYSERR ==
+       TALER_amount_subtract (&left, 
+                              &amount_with_fee,
+                              &ictx.refunded_amount))
+    {
+      GNUNET_break (0);
+      ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
+      return;
+    }
+
+    if ( (0 == left.value) &&
+        (0 == left.fraction) )
+    {
+      /* 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));
+      continue;
+    }
+
+    /* How much of the refund is left? */
+    if (GNUNET_SYSERR ==
+       TALER_amount_subtract (&remaining_refund, 
+                              ctx->refund,
+                              &previous_refund))
+    {
+      GNUNET_break (0);
+      ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
+      return;
+    }
+
+    /* By how much will we increase the refund for this coin? */
+    if (0 >= TALER_amount_cmp (&remaining_refund,
+                              &left))
+    {
+      /* remaining_refund <= left */
+      increment = &remaining_refund;
+    }
+    else
+    {
+      increment = &left;
+    }
+    
+    if (GNUNET_SYSERR ==
+       TALER_amount_add (&previous_refund,
+                         &previous_refund,
+                         increment))
     {
       GNUNET_break (0);
-      PQclear (result);
-      return GNUNET_SYSERR;
+      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 refund will be incremented by %s\n",
+               TALER_B2S (&coin_pub),
+               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,
+                              ctx->reason,
+                              increment,
+                              &refund_fee)))
+      {
+       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;
+    }
+  }
+
+  /**
+   * We end up here if nto all of the refund has been covered.
+   * Although this should be checked as the business should never
+   * issue a refund bigger than the contract's actual price, we cannot
+   * rely upon the frontend being correct.
+   */
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+             "The refund of %s is bigger than the order's value\n",
+             TALER_amount2s (ctx->refund));
+  ctx->qs = GNUNET_DB_STATUS_HARD_ERROR;
+}
+
+
+/**
+ * Function called when some backoffice staff decides to award or
+ * increase the refund on an existing contract.
+ *
+ * @param cls closure
+ * @param h_contract_terms
+ * @param merchant_pub merchant's instance public key
+ * @param refund maximum refund to return to the customer for this contract
+ * @param reason 0-terminated UTF-8 string giving the reason why the customer
+ *               got a refund (free form, business-specific)
+ * @return transaction status
+ *         #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if the refund is accepted
+ *         #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the refund cannot be 
issued: this can happen for two
+ *               reasons: the issued refund is not greater of the previous 
refund,
+ *               or the coins don't have enough amount left to pay for this 
refund.
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_increase_refund_for_contract (void *cls,
+                                       const struct GNUNET_HashCode 
*h_contract_terms,
+                                       const struct TALER_MerchantPublicKeyP 
*merchant_pub,
+                                       const struct TALER_Amount *refund,
+                                       const char *reason)
+{
+  struct PostgresClosure *pg = cls;
+  struct InsertRefundContext ctx;
+  enum GNUNET_DB_QueryStatus qs;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+    GNUNET_PQ_query_param_auto_from_type (merchant_pub),
+    GNUNET_PQ_query_param_end
+  };
+
+  if (GNUNET_OK !=
+      postgres_start (cls))
+  {
+    GNUNET_break (0);
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  }
+  ctx.pg = pg;
+  ctx.qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
+  ctx.refund = refund;
+  ctx.reason = reason;
+  ctx.h_contract_terms = h_contract_terms;
+  ctx.merchant_pub = merchant_pub;
+  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+                                            "find_deposits",
+                                            params,
+                                            &process_deposits_for_refund_cb,
+                                            &ctx);
+  switch (qs)
+  {
+  case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Unknown contract: %s (merchant_pub: %s), no refund 
possible\n",
+                GNUNET_h2s (h_contract_terms),
+                TALER_B2S (merchant_pub));
+    postgres_rollback (cls);
+    return qs;
+  case GNUNET_DB_STATUS_SOFT_ERROR:
+  case GNUNET_DB_STATUS_HARD_ERROR:
+    postgres_rollback (cls);
+    return qs;
+  default:
+    /* Got one or more deposits */
+    if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != ctx.qs)
+    {
+      postgres_rollback (cls);
+      return ctx.qs;
+    }
+    qs = postgres_commit (cls);
+    if (0 > qs)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Failed to commit transaction increasing refund\n");
+      return qs;
+    }
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "Committed refund transaction\n");
+    return ctx.qs;
+  }
+}
+
+
+/**
+ * Lookup proof information about a wire transfer.
+ *
+ * @param cls closure
+ * @param exchange_uri from which exchange are we looking for proof
+ * @param wtid wire transfer identifier for the search
+ * @param cb function to call with proof data
+ * @param cb_cls closure for @a cb
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_find_proof_by_wtid (void *cls,
+                             const char *exchange_uri,
+                             const struct TALER_WireTransferIdentifierRawP 
*wtid,
+                             TALER_MERCHANTDB_ProofCallback cb,
+                             void *cb_cls)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (wtid),
+    GNUNET_PQ_query_param_string (exchange_uri),
+    GNUNET_PQ_query_param_end
+  };
+  json_t *proof;
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    TALER_PQ_result_spec_json ("proof",
+                              &proof),
+    GNUNET_PQ_result_spec_end
+  };
+  enum GNUNET_DB_QueryStatus qs;
+
+  check_connection (pg);
+  qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                "find_proof_by_wtid",
+                                                params,
+                                                rs);
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+  {
     cb (cb_cls,
         proof);
     GNUNET_PQ_cleanup_result (rs);
   }
-
-  PQclear (result);
-  return GNUNET_OK;
+  return qs;
 }
 
 
@@ -1590,6 +2336,7 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
   plugin->store_deposit = &postgres_store_deposit;
   plugin->store_coin_to_transfer = &postgres_store_coin_to_transfer;
   plugin->store_transfer_to_proof = &postgres_store_transfer_to_proof;
+  plugin->store_wire_fee_by_exchange = &postgres_store_wire_fee_by_exchange;
   plugin->find_transaction = &postgres_find_transaction;
   plugin->find_payments_by_hash_and_coin = 
&postgres_find_payments_by_hash_and_coin;
   plugin->find_payments = &postgres_find_payments;
@@ -1602,6 +2349,8 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
   plugin->find_contract_terms_by_date = &postgres_find_contract_terms_by_date;
   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->increase_refund_for_contract = postgres_increase_refund_for_contract;
 
   return plugin;
 }
diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c
index c512651..9a12a1b 100644
--- a/src/backenddb/test_merchantdb.c
+++ b/src/backenddb/test_merchantdb.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 Lesser General Public License as published by the Free 
Software
@@ -84,7 +84,7 @@ struct GNUNET_HashCode h_contract_terms;
 /**
  * Proposal's hash.
  */
-struct GNUNET_HashCode h_contract_terms2;
+struct GNUNET_HashCode h_contract_terms;
 
 /**
  * Time of the transaction.
@@ -112,6 +112,36 @@ static struct TALER_Amount amount_with_fee;
 static struct TALER_Amount deposit_fee;
 
 /**
+ * Refund fee for the coin.
+ */
+static struct TALER_Amount refund_fee;
+
+/**
+ * Amount to be refunded.
+ */
+static struct TALER_Amount refund_amount;
+
+/**
+ * Amount to be refunded.  Used to trigger error about
+ * subsequest refund amount being lesser than the previous
+ * ones.
+ */
+static struct TALER_Amount little_refund_amount;
+
+
+/**
+ * Amount to be refunded in a call which is subsequent
+ * to the good one, expected to succeed.
+ */
+static struct TALER_Amount right_second_refund_amount;
+
+/**
+ * Refund amount meant to raise an error because the
+ * contract's coins aren't enough to pay it back
+ */
+static struct TALER_Amount too_big_refund_amount;
+
+/**
  * Public key of the coin.  Set to some random value.
  */
 static struct TALER_CoinSpendPublicKeyP coin_pub;
@@ -152,6 +182,10 @@ static json_t *contract;
  */
 static json_t *contract_terms;
 
+/**
+ * Mock proposal data, not need to be well-formed
+ */
+static json_t *contract_terms_future;
 
 
 /**
@@ -194,6 +228,31 @@ transaction_cb (void *cls,
                                 &amount_with_fee));
 }
 
+
+/**
+ * Function called with information about a refund.
+ *
+ * @param cls closure
+ * @param coin_pub public coin from which the refund comes from
+ * @param rtransaction_id identificator of the refund
+ * @param reason human-readable explaination of the refund
+ * @param refund_amount refund amount which is being taken from coin_pub
+ * @param refund_fee cost of this refund operation
+ */
+static void
+refund_cb (void *cls,
+          const struct TALER_CoinSpendPublicKeyP *coin_pub,
+          uint64_t rtransaction_id,
+          const char *reason,
+          const struct TALER_Amount *refund_amount,
+          const struct TALER_Amount *refund_fee)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "refund_cb\n");
+  /* FIXME, more logic here? */
+}
+
+
 /**
  * Callback for `find_contract_terms_by_date`.
  *
@@ -211,14 +270,16 @@ pd_cb (void *cls,
   return;
 }
 
+
 /**
  * Function called with information about a coin that was deposited.
  *
  * @param cls closure
  * @param transaction_id of the contract
  * @param coin_pub public key of the coin
- * @param amount_with_fee amount the exchange will deposit for this coin
- * @param deposit_fee fee the exchange will charge for this coin
+ * @param aamount_with_fee amount the exchange will deposit for this coin
+ * @param adeposit_fee fee the exchange will charge for this coin
+ * @param adeposit_fee fee the exchange will charge for refunding this coin
  * @param exchange_proof proof from exchange that coin was accepted
  */
 static void
@@ -227,6 +288,7 @@ deposit_cb (void *cls,
             const struct TALER_CoinSpendPublicKeyP *acoin_pub,
             const struct TALER_Amount *aamount_with_fee,
             const struct TALER_Amount *adeposit_fee,
+            const struct TALER_Amount *arefund_fee,
             const json_t *aexchange_proof)
 {
   CHECK ((0 == memcmp (ah_contract_terms,
@@ -317,8 +379,11 @@ run (void *cls)
     result = 77;
     return;
   }
+
   if (GNUNET_OK != plugin->drop_tables (plugin->cls))
   {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Dropping tables failed\n");
     result = 77;
     return;
   }
@@ -343,11 +408,26 @@ run (void *cls)
   refund_deadline = GNUNET_TIME_absolute_get();
   GNUNET_TIME_round_abs (&refund_deadline);
   GNUNET_assert (GNUNET_OK ==
-                 TALER_string_to_amount (CURRENCY ":1.000010",
+                 TALER_string_to_amount (CURRENCY ":5",
                                          &amount_with_fee));
   GNUNET_assert (GNUNET_OK ==
                  TALER_string_to_amount (CURRENCY ":0.000010",
                                          &deposit_fee));
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_string_to_amount (CURRENCY ":0.000010",
+                                         &refund_fee));
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_string_to_amount (CURRENCY ":2",
+                                         &refund_amount));
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_string_to_amount (CURRENCY ":1",
+                                         &little_refund_amount));
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_string_to_amount (CURRENCY ":3",
+                                         &right_second_refund_amount));
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_string_to_amount (CURRENCY ":30",
+                                         &too_big_refund_amount));
   RND_BLK (&coin_pub);
   deposit_proof = json_object ();
   GNUNET_assert (0 ==
@@ -361,77 +441,87 @@ run (void *cls)
                                       json_string ("backenddb test B")));
   contract = json_object ();
   contract_terms = json_object ();
+  GNUNET_assert (0 ==
+                 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_terms2);
+                   &h_contract_terms);
 
-  FAILIF (GNUNET_OK !=
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->insert_contract_terms (plugin->cls,
-                                        order_id,
-                                        &merchant_pub,
-                                        timestamp,
-                                        contract_terms));
+                                        order_id,
+                                        &merchant_pub,
+                                        timestamp,
+                                        contract_terms));
 
   json_t *out;
 
-  FAILIF (GNUNET_OK !=
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->find_contract_terms (plugin->cls,
-                                      &out,
-                                      order_id,
-                                      &merchant_pub));
-
-  FAILIF (GNUNET_OK !=
-          plugin->find_contract_terms_history (plugin->cls,
-                                              order_id,
-                                              &merchant_pub,
-                                              pd_cb,
-                                              NULL));
-
-  FAILIF (GNUNET_OK !=
+                                      &out,
+                                      order_id,
+                                      &merchant_pub));
+
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+         plugin->find_contract_terms_history (plugin->cls,
+                                              order_id,
+                                              &merchant_pub,
+                                              &pd_cb,
+                                              NULL));
+
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->find_contract_terms_from_hash (plugin->cls,
-                                                &out,
-                                                &h_contract_terms2,
-                                                &merchant_pub));
+                                                &out,
+                                                &h_contract_terms,
+                                                &merchant_pub));
   FAILIF (1 !=
           plugin->find_contract_terms_by_date_and_range (plugin->cls,
-                                                        fake_now,
-                                                        &merchant_pub,
-                                                        2,
-                                                        1,
-                                                        GNUNET_NO,
-                                                        pd_cb,
-                                                        NULL));
+                                                        fake_now,
+                                                        &merchant_pub,
+                                                        2,
+                                                        1,
+                                                        GNUNET_NO,
+                                                        &pd_cb,
+                                                        NULL));
   timestamp = GNUNET_TIME_absolute_get ();
   GNUNET_TIME_round_abs (&timestamp);
 
-  FAILIF (GNUNET_OK !=
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->insert_contract_terms (plugin->cls,
-                                        order_id_future,
-                                        &merchant_pub,
-                                        timestamp,
-                                        contract_terms));
+                                        order_id_future,
+                                        &merchant_pub,
+                                        timestamp,
+                                        contract_terms_future));
 
   fake_now = GNUNET_TIME_absolute_subtract (timestamp, delta);
 
   FAILIF (2 !=
           plugin->find_contract_terms_by_date_and_range (plugin->cls,
-                                                        fake_now,
-                                                        &merchant_pub,
-                                                        0,
-                                                        5,
-                                                        GNUNET_YES,
-                                                        pd_cb,
-                                                        NULL));
+                                                        fake_now,
+                                                        &merchant_pub,
+                                                        0,
+                                                        5,
+                                                        GNUNET_YES,
+                                                        &pd_cb,
+                                                        NULL));
 
   FAILIF (0 !=
           plugin->find_contract_terms_by_date (plugin->cls,
-                                              fake_now,
-                                              &merchant_pub,
-                                              1,
-                                              pd_cb,
-                                              NULL));
+                                              fake_now,
+                                              &merchant_pub,
+                                              1,
+                                              &pd_cb,
+                                              NULL));
 
-  FAILIF (GNUNET_OK !=
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->store_transaction (plugin->cls,
                                      &h_contract_terms,
                                     &merchant_pub,
@@ -440,61 +530,106 @@ run (void *cls)
                                      timestamp,
                                      refund_deadline,
                                      &amount_with_fee));
-  FAILIF (GNUNET_OK !=
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->store_deposit (plugin->cls,
                                  &h_contract_terms,
                                 &merchant_pub,
                                  &coin_pub,
                                  &amount_with_fee,
                                  &deposit_fee,
+                                 &refund_fee,
                                  &signkey_pub,
                                  deposit_proof));
-  FAILIF (GNUNET_OK !=
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->store_coin_to_transfer (plugin->cls,
                                           &h_contract_terms,
                                           &coin_pub,
                                           &wtid));
-  FAILIF (GNUNET_OK !=
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->store_transfer_to_proof (plugin->cls,
                                            EXCHANGE_URI,
                                            &wtid,
                                            GNUNET_TIME_UNIT_ZERO_ABS,
                                            &signkey_pub,
                                            transfer_proof));
-  FAILIF (GNUNET_OK !=
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->find_transaction (plugin->cls,
                                     &h_contract_terms,
                                    &merchant_pub,
                                     &transaction_cb,
                                     NULL));
 
-  FAILIF (GNUNET_OK !=
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->find_payments (plugin->cls,
                                  &h_contract_terms,
                                  &merchant_pub,
                                  &deposit_cb,
                                  NULL));
-  FAILIF (GNUNET_OK !=
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->find_transfers_by_hash (plugin->cls,
-                                        &h_contract_terms,
-                                        &transfer_cb,
-                                        NULL));
-  FAILIF (GNUNET_OK !=
+                                          &h_contract_terms,
+                                          &transfer_cb,
+                                          NULL));
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->find_deposits_by_wtid (plugin->cls,
                                          &wtid,
                                          &deposit_cb,
                                          NULL));
-  FAILIF (GNUNET_OK !=
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->find_proof_by_wtid (plugin->cls,
                                       EXCHANGE_URI,
                                       &wtid,
                                       &proof_cb,
                                       NULL));
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
+          plugin->get_refunds_from_contract_terms_hash (plugin->cls,
+                                                        &merchant_pub,
+                                                        &h_contract_terms,
+                                                        &refund_cb,
+                                                        NULL));
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+          plugin->increase_refund_for_contract (plugin->cls,
+                                                &h_contract_terms,
+                                                &merchant_pub,
+                                                &refund_amount,
+                                                "refund testing"));
+
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
+          plugin->increase_refund_for_contract (plugin->cls,
+                                                &h_contract_terms,
+                                                &merchant_pub,
+                                                &refund_amount,
+                                                "same refund amount as "
+                                                "the previous one, should 
fail"));
+
+  /*Should fail as this refund a lesser amount respect to the previous one*/
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
+          plugin->increase_refund_for_contract (plugin->cls,
+                                                &h_contract_terms,
+                                                &merchant_pub,
+                                                &little_refund_amount,
+                                                "make refund testing fail"));
+  FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+          plugin->increase_refund_for_contract (plugin->cls,
+                                                &h_contract_terms,
+                                                &merchant_pub,
+                                                &right_second_refund_amount,
+                                                "right refund increase"));
+
+  FAILIF (GNUNET_DB_STATUS_HARD_ERROR != 
+          plugin->increase_refund_for_contract (plugin->cls,
+                                                &h_contract_terms,
+                                                &merchant_pub,
+                                                &too_big_refund_amount,
+                                                "make refund testing fail due"
+                                                " to too big refund amount"));
+
   if (-1 == result)
     result = 0;
 
  drop:
-  GNUNET_break (GNUNET_OK == plugin->drop_tables (plugin->cls));
+  GNUNET_break (GNUNET_OK ==
+               plugin->drop_tables (plugin->cls));
   TALER_MERCHANTDB_plugin_unload (plugin);
   plugin = NULL;
   if (NULL != deposit_proof)
diff --git a/src/include/taler_merchant_service.h 
b/src/include/taler_merchant_service.h
index aee46af..8a2343a 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -28,7 +28,95 @@
 #include <jansson.h>
 
 
-/* ********************* /map/{in,out} *********************** */
+/* ********************* /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
+ */
+typedef void
+(*TALER_MERCHANT_RefundIncreaseCallback) (void *cls,
+                                          unsigned int http_status,
+                                          enum TALER_ErrorCode ec,
+                                          const json_t *obj);
+
+/**
+ * Callback to process a GET /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_RefundLookupCallback) (void *cls,
+                                                 unsigned int http_status,
+                                                 enum TALER_ErrorCode ec,
+                                                 const json_t *obj);
+
+/**
+ * Does a GET /refund.
+ *
+ * @param ctx execution context
+ * @param backend_uri base URL of the merchant backend
+ * @param order_id order id used to perform the lookup
+ * @param cb callback which will work the response gotten from the backend
+ * @param cb_cls closure to pass to the callback
+ * @return handle for this operation, NULL upon errors
+ */
+struct TALER_MERCHANT_RefundLookupOperation *
+TALER_MERCHANT_refund_lookup (struct GNUNET_CURL_Context *ctx,
+                              const char *backend_uri,
+                              const char *order_id,
+                              const char *instance,
+                              TALER_MERCHANT_RefundLookupCallback cb,
+                              void *cb_cls);
+
+/**
+ * Increase the refund associated to a order
+ *
+ * @param ctx the CURL context used to connect to the backend
+ * @param backend_uri backend's base URL, including final "/"
+ * @param order_id id of the order whose refund is to be increased
+ * @param refund amount to which increase the refund
+ * @param reason human-readable reason justifying the refund
+ * @param instance id of the merchant instance issuing the request
+ * @param cb callback processing the response from /refund
+ * @param cb_cls closure for cb
+ */
+struct TALER_MERCHANT_RefundIncreaseOperation *
+TALER_MERCHANT_refund_increase (struct GNUNET_CURL_Context *ctx,
+                                const char *backend_uri,
+                                const char *order_id,
+                                const struct TALER_Amount *refund,
+                                const char *reason,
+                                const char *instance,
+                                TALER_MERCHANT_RefundIncreaseCallback cb,
+                                void *cb_cls);
+
+/**
+ * Cancel a POST /refund request.
+ *
+ * @param rio the refund increasing operation to cancel
+ */
+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 *********************** */
 
diff --git a/src/include/taler_merchantdb_plugin.h 
b/src/include/taler_merchantdb_plugin.h
index 92f4a53..efb03cb 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.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 Lesser General Public License as published by the Free 
Software
@@ -23,6 +23,7 @@
 #define TALER_MERCHANTDB_PLUGIN_H
 
 #include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_db_lib.h>
 #include <jansson.h>
 
 /**
@@ -76,6 +77,7 @@ typedef void
  * @param coin_pub public key of the coin
  * @param amount_with_fee amount the exchange will deposit for this coin
  * @param deposit_fee fee the exchange will charge for this coin
+ * @param refund_fee fee the exchange will charge for refunding this coin
  * @param exchange_proof proof from exchange that coin was accepted,
  *        matches the `interface DepositSuccess` of the documentation.
  */
@@ -85,6 +87,7 @@ typedef void
                                         const struct TALER_CoinSpendPublicKeyP 
*coin_pub,
                                         const struct TALER_Amount 
*amount_with_fee,
                                         const struct TALER_Amount *deposit_fee,
+                                        const struct TALER_Amount *refund_fee,
                                         const json_t *exchange_proof);
 
 
@@ -126,6 +129,25 @@ typedef void
 
 
 /**
+ * Function called with information about a refund.
+ *
+ * @param cls closure
+ * @param coin_pub public coin from which the refund comes from
+ * @param rtransaction_id identificator of the refund
+ * @param reason human-readable explaination of the refund
+ * @param refund_amount refund amount which is being taken from coin_pub
+ * @param refund_fee cost of this refund operation
+ */
+typedef void
+(*TALER_MERCHANTDB_RefundCallback)(void *cls,
+                                   const struct TALER_CoinSpendPublicKeyP 
*coin_pub,
+                                   uint64_t rtransaction_id,
+                                   const char *reason,
+                                   const struct TALER_Amount *refund_amount,
+                                   const struct TALER_Amount *refund_fee);
+
+
+/**
  * Handle to interact with the database.
  */
 struct TALER_MERCHANTDB_Plugin
@@ -170,9 +192,9 @@ struct TALER_MERCHANTDB_Plugin
    * @param merchant_pub merchant's public key
    * @param timestamp timestamp of this proposal data
    * @param contract_terms proposal data to store
-   * @return #GNUNET_OK on success, #GNUNET_SYSERR upon error
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*insert_contract_terms) (void *cls,
                            const char *order_id,
                            const struct TALER_MerchantPublicKeyP *merchant_pub,
@@ -186,10 +208,9 @@ struct TALER_MERCHANTDB_Plugin
    * @param[out] contract_terms where to store the result
    * @param order_id order_id used to lookup.
    * @param merchant_pub instance's public key.
-   * @return #GNUNET_OK on success, #GNUNET_NO if no contract is
-   * found, #GNUNET_SYSERR upon error
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*find_contract_terms) (void *cls,
                          json_t **contract_terms,
                          const char *order_id,
@@ -200,13 +221,12 @@ struct TALER_MERCHANTDB_Plugin
    * Retrieve proposal data given its hashcode
    *
    * @param cls closure
-   * @param contract_terms where to store the result
+   * @param[out] contract_terms where to store the result
    * @param h_contract_terms hashcode used to lookup.
    * @param merchant_pub instance's public key.
-   * @return #GNUNET_OK on success, #GNUNET_NO if no contract is
-   * found, #GNUNET_SYSERR upon error
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*find_contract_terms_from_hash) (void *cls,
                                    json_t **contract_terms,
                                    const struct GNUNET_HashCode 
*h_contract_terms,
@@ -230,17 +250,17 @@ struct TALER_MERCHANTDB_Plugin
    * This is typically used to show live updates on the merchant's backoffice
    * @param cb function to call with transaction data, can be NULL.
    * @param cb_cls closure for @a cb
-   * @return numer of found tuples, #GNUNET_SYSERR upon error
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*find_contract_terms_by_date_and_range) (void *cls,
-                                           struct GNUNET_TIME_Absolute date,
-                                           const struct 
TALER_MerchantPublicKeyP *merchant_pub,
-                                           unsigned int start,
-                                           unsigned int nrows,
-                                           unsigned int future,
-                                           
TALER_MERCHANTDB_ProposalDataCallback cb,
-                                           void *cb_cls);
+                                           struct GNUNET_TIME_Absolute date,
+                                           const struct 
TALER_MerchantPublicKeyP *merchant_pub,
+                                           uint64_t start,
+                                           uint64_t nrows,
+                                           int future,
+                                           
TALER_MERCHANTDB_ProposalDataCallback cb,
+                                           void *cb_cls);
 
   /**
    * Lookup for a proposal, respecting the signature used by the
@@ -251,10 +271,9 @@ struct TALER_MERCHANTDB_Plugin
    * @param merchant_pub public key of the merchant using this method
    * @param cb the callback
    * @param cb_cls closure to pass to @a cb
-   * @return #GNUNET_YES, #GNUNET_NO, #GNUNET_SYSERR according to the
-   * query being successful, unsuccessful, or generated errors.
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*find_contract_terms_history) (void *cls,
                                  const char *order_id,
                                  const struct TALER_MerchantPublicKeyP 
*merchant_pub,
@@ -273,15 +292,15 @@ struct TALER_MERCHANTDB_Plugin
    * @param nrows only nrows rows are returned.
    * @param cb function to call with transaction data, can be NULL.
    * @param cb_cls closure for @a cb
-   * @return numer of found tuples, #GNUNET_SYSERR upon error
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*find_contract_terms_by_date) (void *cls,
-                                 struct GNUNET_TIME_Absolute date,
-                                 const struct TALER_MerchantPublicKeyP 
*merchant_pub,
-                                 unsigned int nrows,
-                                 TALER_MERCHANTDB_ProposalDataCallback cb,
-                                 void *cb_cls);
+                                 struct GNUNET_TIME_Absolute date,
+                                 const struct TALER_MerchantPublicKeyP 
*merchant_pub,
+                                 uint64_t nrows,
+                                 TALER_MERCHANTDB_ProposalDataCallback cb,
+                                 void *cb_cls);
 
 
   /**
@@ -295,9 +314,9 @@ struct TALER_MERCHANTDB_Plugin
    * @param timestamp time of the confirmation
    * @param refund refund deadline
    * @param total_amount total amount we receive for the contract after fees
-   * @return #GNUNET_OK on success, #GNUNET_SYSERR upon error
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*store_transaction) (void *cls,
                         const struct GNUNET_HashCode *h_contract_terms,
                        const struct TALER_MerchantPublicKeyP *merchant_pub,
@@ -319,15 +338,16 @@ struct TALER_MERCHANTDB_Plugin
    * @param deposit_fee fee the exchange will charge for this coin
    * @param signkey_pub public key used by the exchange for @a exchange_proof
    * @param exchange_proof proof from exchange that coin was accepted
-   * @return #GNUNET_OK on success, #GNUNET_SYSERR upon error
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*store_deposit) (void *cls,
                     const struct GNUNET_HashCode *h_contract_terms,
                     const struct TALER_MerchantPublicKeyP *merchant_pub,
                     const struct TALER_CoinSpendPublicKeyP *coin_pub,
                     const struct TALER_Amount *amount_with_fee,
                     const struct TALER_Amount *deposit_fee,
+                    const struct TALER_Amount *refund_fee,
                     const struct TALER_ExchangePublicKeyP *signkey_pub,
                     const json_t *exchange_proof);
 
@@ -341,9 +361,9 @@ struct TALER_MERCHANTDB_Plugin
    * @param coin_pub public key of the coin
    * @param wtid identifier of the wire transfer in which the exchange
    *             send us the money for the coin deposit
-   * @return #GNUNET_OK on success, #GNUNET_SYSERR upon error
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*store_coin_to_transfer) (void *cls,
                              const struct GNUNET_HashCode *h_contract_terms,
                              const struct TALER_CoinSpendPublicKeyP *coin_pub,
@@ -359,9 +379,9 @@ struct TALER_MERCHANTDB_Plugin
    * @param execution_time when was @a wtid executed
    * @param signkey_pub public key used by the exchange for @a exchange_proof
    * @param exchange_proof proof from exchange about what the deposit was for
-   * @return #GNUNET_OK on success, #GNUNET_SYSERR upon error
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*store_transfer_to_proof) (void *cls,
                               const char *exchange_uri,
                               const struct TALER_WireTransferIdentifierRawP 
*wtid,
@@ -371,20 +391,46 @@ struct TALER_MERCHANTDB_Plugin
 
 
   /**
+   * Store information about wire fees charged by an exchange,
+   * including signature (so we have proof).
+   *
+   * @param cls closure
+   * @paramm 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,
+   *              but needed to check signature)
+   * @param start_date start of fee being used
+   * @param end_date end of fee being used
+   * @param exchange_sig signature of exchange over fee structure
+   * @return transaction status code
+   */
+  enum GNUNET_DB_QueryStatus
+  (*store_wire_fee_by_exchange) (void *cls,
+                                const struct TALER_MasterPublicKeyP 
*exchange_pub,
+                                const struct GNUNET_HashCode *h_wire_method,
+                                const struct TALER_Amount *wire_fee,
+                                const struct TALER_Amount *closing_fee,
+                                struct GNUNET_TIME_Absolute start_date,
+                                struct GNUNET_TIME_Absolute end_date,
+                                const struct TALER_MasterSignatureP 
*exchange_sig);
+                                
+
+  /**
    * Find information about a transaction.
    *
    * @param cls our plugin handle
    * @param date limit to transactions' age
    * @param cb function to call with transaction data
    * @param cb_cls closure for @a cb
-   * @return #GNUNET_OK if found, #GNUNET_NO if not, #GNUNET_SYSERR
-   *         upon error
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*find_transactions_by_date) (void *cls,
                                 struct GNUNET_TIME_Absolute date,
                                 TALER_MERCHANTDB_TransactionCallback cb,
                                 void *cb_cls);
+  
 
   /**
    * Find information about a transaction.
@@ -394,9 +440,9 @@ struct TALER_MERCHANTDB_Plugin
    * @param merchant_pub merchant's public key.
    * @param cb function to call with transaction data
    * @param cb_cls closure for @a cb
-   * @return number of found tuples, #GNUNET_SYSERR upon error
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*find_transaction) (void *cls,
                        const struct GNUNET_HashCode *h_contract_terms,
                       const struct TALER_MerchantPublicKeyP *merchant_pub,
@@ -413,15 +459,15 @@ struct TALER_MERCHANTDB_Plugin
    *        in order to find the result.
    * @param cb function to call with payment data
    * @param cb_cls closure for @a cb
-   * @return #GNUNET_OK on success, #GNUNET_NO if h_contract_terms is unknown,
-   *         #GNUNET_SYSERR on hard errors
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*find_payments) (void *cls,
                     const struct GNUNET_HashCode *h_contract_terms,
                     const struct TALER_MerchantPublicKeyP *merchant_pub,
                     TALER_MERCHANTDB_CoinDepositCallback cb,
                     void *cb_cls);
+  
 
   /**
    * Lookup information about coin payments by h_contract_terms and coin.
@@ -433,10 +479,9 @@ struct TALER_MERCHANTDB_Plugin
    * @param coin_pub public key to use for the search
    * @param cb function to call with payment data
    * @param cb_cls closure for @a cb
-   * @return #GNUNET_OK on success, #GNUNET_NO if h_contract_terms is unknown,
-   *         #GNUNET_SYSERR on hard errors
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*find_payments_by_hash_and_coin) (void *cls,
                                      const struct GNUNET_HashCode 
*h_contract_terms,
                                      const struct TALER_MerchantPublicKeyP 
*merchant_pub,
@@ -456,10 +501,9 @@ struct TALER_MERCHANTDB_Plugin
    * @param h_contract_terms proposal data's hashcode
    * @param cb function to call with transfer data
    * @param cb_cls closure for @a cb
-   * @return #GNUNET_OK on success, #GNUNET_NO if h_contract_terms is unknown,
-   *         #GNUNET_SYSERR on hard errors
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*find_transfers_by_hash) (void *cls,
                              const struct GNUNET_HashCode *h_contract_terms,
                              TALER_MERCHANTDB_TransferCallback cb,
@@ -473,10 +517,9 @@ struct TALER_MERCHANTDB_Plugin
    * @param wtid wire transfer identifier to find matching transactions for
    * @param cb function to call with payment data
    * @param cb_cls closure for @a cb
-   * @return #GNUNET_OK on success, #GNUNET_NO if h_contract_terms is unknown,
-   *         #GNUNET_SYSERR on hard errors
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*find_deposits_by_wtid) (void *cls,
                             const struct TALER_WireTransferIdentifierRawP 
*wtid,
                             TALER_MERCHANTDB_CoinDepositCallback cb,
@@ -491,16 +534,53 @@ struct TALER_MERCHANTDB_Plugin
    * @param wtid wire transfer identifier for the search
    * @param cb function to call with proof data
    * @param cb_cls closure for @a cb
-   * @return #GNUNET_OK on success, #GNUNET_NO if h_contract_terms is unknown,
-   *         #GNUNET_SYSERR on hard errors
+   * @return transaction status
    */
-  int
+  enum GNUNET_DB_QueryStatus
   (*find_proof_by_wtid) (void *cls,
                          const char *exchange_uri,
                          const struct TALER_WireTransferIdentifierRawP *wtid,
                          TALER_MERCHANTDB_ProofCallback cb,
                          void *cb_cls);
-};
 
 
+  /**
+   * Function called when some backoffice staff decides to award or
+   * increase the refund on an existing contract.
+   *
+   * @param cls closure
+   * @param merchant_pub merchant's instance public key
+   * @param h_contract_terms
+   * @param merchant_pub merchant's instance public key
+   * @param refund maximum refund to return to the customer for this contract
+   * @param reason 0-terminated UTF-8 string giving the reason why the customer
+   *               got a refund (free form, business-specific)
+   * @return transaction status
+   */
+  enum GNUNET_DB_QueryStatus
+  (*increase_refund_for_contract)(void *cls,
+                                  const struct GNUNET_HashCode 
*h_contract_terms,
+                                  const struct TALER_MerchantPublicKeyP 
*merchant_pub,
+                                  const struct TALER_Amount *refund,
+                                  const char *reason);
+
+
+  /**
+   * Obtain refunds associated with a contract.
+   *
+   * @param cls closure, typically a connection to the db
+   * @param merchant_pub public key of the merchant instance
+   * @param h_contract_terms hash code of the contract
+   * @param rc function to call for each coin on which there is a refund
+   * @param rc_cls closure for @a rc
+   * @return transaction status
+   */
+  enum GNUNET_DB_QueryStatus
+  (*get_refunds_from_contract_terms_hash)(void *cls,
+                                          const struct 
TALER_MerchantPublicKeyP *merchant_pub,
+                                          const struct GNUNET_HashCode 
*h_contract_terms,
+                                          TALER_MERCHANTDB_RefundCallback rc,
+                                          void *rc_cls);
+};
+
 #endif
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 1e4a7cb..aebf74b 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -1,5 +1,5 @@
 # This Makefile.am is in the public domain
-AM_CPPFLAGS = -I$(top_srcdir)/src/include
+AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/backend
 
 if USE_COVERAGE
   AM_CFLAGS = --coverage -O0
@@ -10,15 +10,17 @@ lib_LTLIBRARIES = \
   libtalermerchant.la
 
 libtalermerchant_la_LDFLAGS = \
-  -version-info 0:0:0 \
+  -version-info 1:0:0 \
   -no-undefined
 
 libtalermerchant_la_SOURCES = \
+  merchant_api_common.c merchant_api_common.h \
   merchant_api_proposal.c \
   merchant_api_pay.c \
   merchant_api_track_transaction.c \
   merchant_api_track_transfer.c \
-  merchant_api_history.c
+  merchant_api_history.c \
+  merchant_api_refund.c
 
 libtalermerchant_la_LIBADD = \
   -ltalerexchange \
diff --git a/src/lib/merchant_api_common.c b/src/lib/merchant_api_common.c
new file mode 100644
index 0000000..05e2637
--- /dev/null
+++ b/src/lib/merchant_api_common.c
@@ -0,0 +1,50 @@
+/*
+  This file is part of TALER
+  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
+  Foundation; either version 2.1, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more 
details.
+
+  You should have received a copy of the GNU Lesser General Public License 
along with
+  TALER; see the file COPYING.LGPL.  If not, see
+  <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/merchant_api_common.c
+ * @brief Shared functionality
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+
+
+/**
+ * Obtain the URL to use for an API request.
+ *
+ * @param base_url base URL of the exchange (i.e. "http://exchange/";)
+ * @param path Taler API path (i.e. "/reserve/withdraw")
+ * @return the full URI to use with cURL
+ */
+char *
+MAH_path_to_url_ (const char *base_url,
+                 const char *path)
+{
+  char *url;
+
+  if ( ('/' == path[0]) &&
+       (0 < strlen (base_url)) &&
+       ('/' == base_url[strlen (base_url) - 1]) )
+    path++; /* avoid generating URL with "//" from concat */
+  GNUNET_asprintf (&url,
+                   "%s%s",
+                   base_url,
+                   path);
+  return url;
+}
+
+/* end of merchant_api_common.c */
diff --git a/src/lib/merchant_api_common.h b/src/lib/merchant_api_common.h
new file mode 100644
index 0000000..683f1db
--- /dev/null
+++ b/src/lib/merchant_api_common.h
@@ -0,0 +1,36 @@
+/*
+  This file is part of TALER
+  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
+  Foundation; either version 2.1, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more 
details.
+
+  You should have received a copy of the GNU Lesser General Public License 
along with
+  TALER; see the file COPYING.LGPL.  If not, see
+  <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/merchant_api_common.h
+ * @brief Shared functions
+ * @author Christian Grothoff
+ */
+#ifndef MERCHANT_API_COMMON_H
+#define MERCHANT_API_COMMON_H
+
+/**
+ * Obtain the URL to use for an API request.
+ *
+ * @param base_url base URL of the exchange (i.e. "http://exchange/";)
+ * @param path Taler API path (i.e. "/reserve/withdraw")
+ * @return the full URI to use with cURL
+ */
+char *
+MAH_path_to_url_ (const char *base_url,
+                 const char *path);
+
+#endif
diff --git a/src/lib/merchant_api_history.c b/src/lib/merchant_api_history.c
index c002d0a..efc20be 100644
--- a/src/lib/merchant_api_history.c
+++ b/src/lib/merchant_api_history.c
@@ -27,6 +27,7 @@
 #include <gnunet/gnunet_curl_lib.h>
 #include "taler_merchant_service.h"
 #include <taler/taler_json_lib.h>
+#include "merchant_api_common.h"
 
 
 /**
@@ -159,21 +160,23 @@ TALER_MERCHANT_history (struct GNUNET_CURL_Context *ctx,
   struct TALER_MERCHANT_HistoryOperation *ho;
   uint64_t seconds;
   CURL *eh;
+  char *base;
 
   ho = GNUNET_new (struct TALER_MERCHANT_HistoryOperation);
   ho->ctx = ctx;
   ho->cb = history_cb;
   ho->cb_cls = history_cb_cls;
   seconds = date.abs_value_us / 1000LL / 1000LL;
-
+  base = MAH_path_to_url_ (backend_uri,
+                          "/history");
   GNUNET_asprintf (&ho->url,
-                   "%s/history?date=%llu&instance=%s&start=%d&delta=%d",
-                   backend_uri,
+                   "%s?date=%llu&instance=%s&start=%d&delta=%d",
+                   base,
                    seconds,
                    instance,
                    start,
                    delta);
-
+  GNUNET_free (base);
   eh = curl_easy_init ();
   if (CURLE_OK != curl_easy_setopt (eh,
                                     CURLOPT_URL,
diff --git a/src/lib/merchant_api_pay.c b/src/lib/merchant_api_pay.c
index aa875bc..e65ecb4 100644
--- a/src/lib/merchant_api_pay.c
+++ b/src/lib/merchant_api_pay.c
@@ -29,6 +29,7 @@
 #include <taler/taler_json_lib.h>
 #include <taler/taler_signatures.h>
 #include <taler/taler_exchange_service.h>
+#include "merchant_api_common.h"
 
 
 /**
@@ -150,7 +151,6 @@ check_forbidden (struct TALER_MERCHANT_Pay *ph,
     GNUNET_JSON_spec_fixed_auto ("coin_pub", &coin_pub),
     GNUNET_JSON_spec_end()
   };
-  unsigned int i;
   int ret;
 
   if (GNUNET_OK !=
@@ -161,7 +161,7 @@ check_forbidden (struct TALER_MERCHANT_Pay *ph,
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
   }
-  for (i=0;i<ph->num_coins;i++)
+  for (unsigned int i=0;i<ph->num_coins;i++)
   {
     if (0 == memcmp (&ph->coins[i].coin_pub,
                      &coin_pub,
@@ -249,6 +249,9 @@ handle_pay_finished (void *cls,
 
 /**
  * Pay a merchant.  API for wallets that have the coin's private keys.
+ * _NOTE_: this function does NOT calculate each coin amount in order
+ * to match the contract total price.  This calculation is to be made
+ * by the logic using this library.
  *
  * @param ctx the execution loop context
  * @param merchant_uri base URI of the merchant's backend
@@ -476,10 +479,8 @@ TALER_MERCHANT_pay_frontend (struct GNUNET_CURL_Context 
*ctx,
   ph->ctx = ctx;
   ph->cb = pay_cb;
   ph->cb_cls = pay_cb_cls;
-  GNUNET_asprintf (&ph->url,
-                   "%s%s",
-                   merchant_uri,
-                   "/pay");
+  ph->url = MAH_path_to_url_ (merchant_uri,
+                             "/pay");
   ph->num_coins = num_coins;
   ph->coins = GNUNET_new_array (num_coins,
                                 struct TALER_MERCHANT_PaidCoin);
diff --git a/src/lib/merchant_api_proposal.c b/src/lib/merchant_api_proposal.c
index 84f7045..fa7e6b6 100644
--- a/src/lib/merchant_api_proposal.c
+++ b/src/lib/merchant_api_proposal.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
@@ -16,7 +16,7 @@
 */
 /**
  * @file lib/merchant_api_proposal.c
- * @brief Implementation of the /proposal PUT and GET
+ * @brief Implementation of the /proposal POST and GET
  * @author Christian Grothoff
  * @author Marcello Stanisci
  */
@@ -29,6 +29,7 @@
 #include "taler_merchant_service.h"
 #include <taler/taler_json_lib.h>
 #include <taler/taler_signatures.h>
+#include "merchant_api_common.h"
 
 
 /**
@@ -103,11 +104,11 @@ struct TALER_MERCHANT_ProposalLookupOperation
 
 /**
  * Function called when we're done processing the
- * HTTP PUT /proposal request.
+ * HTTP POST /proposal request.
  *
  * @param cls the `struct TALER_MERCHANT_ProposalOperation`
  * @param response_code HTTP response code, 0 on error
- * @param json response body, NULL if not in JSON
+ * @param json response body, NULL if not JSON
  */
 static void
 handle_proposal_finished (void *cls,
@@ -192,7 +193,7 @@ handle_proposal_finished (void *cls,
 
 
 /**
- * PUT an order to the backend and receives the related proposal.
+ * POST an order to the backend and receives the related proposal.
  *
  * @param ctx execution context
  * @param backend_uri URI of the backend
@@ -218,11 +219,8 @@ TALER_MERCHANT_order_put (struct GNUNET_CURL_Context *ctx,
   po->ctx = ctx;
   po->cb = proposal_cb;
   po->cb_cls = proposal_cb_cls;
-  GNUNET_asprintf (&po->url,
-                   "%s%s",
-                   backend_uri,
-                   "/proposal");
-
+  po->url = MAH_path_to_url_ (backend_uri,
+                             "/proposal");
   req = json_pack ("{s:O}",
                    "order", (json_t *) order);
   eh = curl_easy_init ();
@@ -239,7 +237,6 @@ TALER_MERCHANT_order_put (struct GNUNET_CURL_Context *ctx,
                  curl_easy_setopt (eh,
                                    CURLOPT_URL,
                                    po->url));
-  /* FIXME: as for the specs, POST becomes PUT */
   GNUNET_assert (CURLE_OK ==
                  curl_easy_setopt (eh,
                                    CURLOPT_POSTFIELDS,
@@ -304,17 +301,20 @@ TALER_MERCHANT_proposal_lookup (struct 
GNUNET_CURL_Context *ctx,
 {
   struct TALER_MERCHANT_ProposalLookupOperation *plo;
   CURL *eh;
+  char *base;
 
   plo = GNUNET_new (struct TALER_MERCHANT_ProposalLookupOperation);
   plo->ctx = ctx;
   plo->cb = plo_cb;
   plo->cb_cls = plo_cb_cls;
-
+  base = MAH_path_to_url_ (backend_uri,
+                          "/proposal");
   GNUNET_asprintf (&plo->url,
-                   "%s/proposal?order_id=%s&instance=%s",
-                   backend_uri,
+                   "%s?order_id=%s&instance=%s",
+                   base,
                    order_id,
                    instance);
+  GNUNET_free (base);
   eh = curl_easy_init ();
   if (CURLE_OK != curl_easy_setopt (eh,
                                     CURLOPT_URL,
@@ -338,7 +338,7 @@ TALER_MERCHANT_proposal_lookup (struct GNUNET_CURL_Context 
*ctx,
 
 
 /**
- * Cancel a PUT /proposal request.  This function cannot be used
+ * Cancel a POST /proposal request.  This function cannot be used
  * on a request handle if a response is already served for it.
  *
  * @param po the proposal operation request handle
diff --git a/src/lib/merchant_api_refund.c b/src/lib/merchant_api_refund.c
new file mode 100644
index 0000000..8cea8b7
--- /dev/null
+++ b/src/lib/merchant_api_refund.c
@@ -0,0 +1,352 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2014, 2015, 2016, 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
+  Foundation; either version 2.1, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more 
details.
+
+  You should have received a copy of the GNU Lesser General Public License 
along with
+  TALER; see the file COPYING.LGPL.  If not, see
+  <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/merchant_api_proposal.c
+ * @brief Implementation of the /refund POST and GET
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_merchant_service.h"
+#include <taler/taler_json_lib.h>
+#include <taler/taler_signatures.h>
+#include "merchant_api_common.h"
+
+
+struct TALER_MERCHANT_RefundLookupOperation
+{
+  /**
+   * URL of the request, includes parameters
+   */
+  char *url;
+
+  /**
+   * Handle of the request
+   */
+  struct GNUNET_CURL_Job *job;
+
+  /**
+   * Function to call with the response
+   */
+  TALER_MERCHANT_RefundLookupCallback cb;
+
+  /**
+   * Closure for cb
+   */
+  void *cb_cls;
+
+  /**
+   * Reference to the execution context
+   */
+  struct GNUNET_CURL_Context *ctx;
+
+};
+
+struct TALER_MERCHANT_RefundIncreaseOperation
+{
+  /**
+   * Complete URL where the backend offers /refund
+   */
+  char *url;
+
+  /**
+   * The request body
+   */
+  char *json_enc;
+
+  /**
+   * The CURL context to connect to the backend
+   */
+  struct GNUNET_CURL_Context *ctx;
+
+  /**
+   * The callback to pass the backend response to
+   */
+  TALER_MERCHANT_RefundIncreaseCallback cb;
+
+  /**
+   * Clasure to pass to the callback
+   */
+  void *cb_cls;
+
+  /**
+   * Handle for the request
+   */
+  struct GNUNET_CURL_Job *job;
+
+};
+
+
+/**
+ * Callback to process POST /refund response
+ *
+ * @param cls the `struct TALER_MERCHANT_RefundIncreaseOperation`
+ * @param response_code HTTP response code, 0 on error
+ * @param json response body, NULL if not JSON
+ */
+static void
+handle_refund_increase_finished (void *cls,
+                                 long response_code,
+                                 const json_t *json)
+{
+  struct TALER_MERCHANT_RefundIncreaseOperation *rio = cls;
+  char *error;
+  char *hint;
+  enum TALER_ErrorCode code;
+
+  rio->job = NULL;
+  switch (response_code)
+  {
+  case 0:
+    /* Hard error */
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Backend didn't even return from POST /refund\n");
+    return;
+  case MHD_HTTP_OK:
+    rio->cb (rio->cb_cls,
+             MHD_HTTP_OK,
+             TALER_EC_NONE,
+             json);
+    break;
+  default:
+    /**
+     * The backend gave response, but it's error, log it.
+     * NOTE that json must be a Taler-specific error object (FIXME,
+     * need a link to error objects at docs)
+     */
+    json_unpack ((json_t *) json,
+                 "{s:s, s:I, s:s}",
+                 "error", &error,
+                 "code", &code,
+                 "hint", &hint);
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Failed POST /refund, error: %s, code: %d, hint: %s\n",
+                error,
+                code,
+                hint);
+  }
+  TALER_MERCHANT_refund_increase_cancel (rio);
+}
+
+/**
+ * Cancel a POST /refund request.
+ *
+ * @param rio the refund increasing operation to cancel
+ */
+void
+TALER_MERCHANT_refund_increase_cancel (struct 
TALER_MERCHANT_RefundIncreaseOperation *rio)
+{
+  if (NULL != rio->job)
+  {
+    GNUNET_CURL_job_cancel (rio->job);
+    rio->job = NULL;
+  }
+  GNUNET_free (rio->url);
+  GNUNET_free (rio->json_enc);
+  GNUNET_free (rio);
+}
+
+/**
+ * Increase the refund associated to a order
+ *
+ * @param ctx the CURL context used to connect to the backend
+ * @param backend_uri backend's base URL, including final "/"
+ * @param order_id id of the order whose refund is to be increased
+ * @param refund amount to which increase the refund
+ * @param reason human-readable reason justifying the refund
+ * @param instance id of the merchant instance issuing the request
+ * @param cb callback processing the response from /refund
+ * @param cb_cls closure for cb
+ */
+struct TALER_MERCHANT_RefundIncreaseOperation *
+TALER_MERCHANT_refund_increase (struct GNUNET_CURL_Context *ctx,
+                                const char *backend_uri,
+                                const char *order_id,
+                                const struct TALER_Amount *refund,
+                                const char *reason,
+                                const char *instance,
+                                TALER_MERCHANT_RefundIncreaseCallback cb,
+                                void *cb_cls)
+{
+  struct TALER_MERCHANT_RefundIncreaseOperation *rio;
+  json_t *req;
+  CURL *eh;
+
+  rio = GNUNET_new (struct TALER_MERCHANT_RefundIncreaseOperation);
+  rio->ctx = ctx;
+  rio->cb = cb;
+  rio->cb_cls = cb_cls;
+  rio->url = MAH_path_to_url_ (backend_uri,
+                              "/refund");
+  req = json_pack ("{s:o, s:s, s:s, s:s}",
+                   "refund", TALER_JSON_from_amount (refund),
+                   "order_id", order_id,
+                   "reason", reason,
+                   "instance", instance);
+  eh = curl_easy_init ();
+  rio->json_enc = json_dumps (req,
+                              JSON_COMPACT);
+  json_decref (req);
+  if (NULL == rio->json_enc)
+  {
+    GNUNET_break (0);
+    GNUNET_free (rio);
+    return NULL;
+  }
+  GNUNET_assert (CURLE_OK ==
+                 curl_easy_setopt (eh,
+                                   CURLOPT_URL,
+                                   rio->url));
+  GNUNET_assert (CURLE_OK ==
+                 curl_easy_setopt (eh,
+                                   CURLOPT_POSTFIELDS,
+                                   rio->json_enc));
+  GNUNET_assert (CURLE_OK ==
+                 curl_easy_setopt (eh,
+                                   CURLOPT_POSTFIELDSIZE,
+                                   strlen (rio->json_enc)));
+  rio->job = GNUNET_CURL_job_add (ctx,
+                                  eh,
+                                  GNUNET_YES,
+                                  &handle_refund_increase_finished,
+                                  rio);
+  return rio;
+}
+
+
+/**
+ * Cancel a /refund lookup operation
+ *
+ * @param 
+ */
+void
+TALER_MERCHANT_refund_lookup_cancel (struct 
TALER_MERCHANT_RefundLookupOperation *rlo)
+{
+  if (NULL != rlo->job)
+  {
+    GNUNET_CURL_job_cancel (rlo->job);
+    rlo->job = NULL;
+  }
+  
+  GNUNET_free (rlo->url);
+  GNUNET_free (rlo);
+}
+
+
+/**
+ * Process GET /refund response
+ */
+void
+handle_refund_lookup_finished (void *cls,
+                               long response_code,
+                               const json_t *json)
+{
+  struct TALER_MERCHANT_RefundLookupOperation *rlo = cls;
+  char *error;
+  enum TALER_ErrorCode code;
+
+  rlo->job = NULL;
+  switch (response_code)
+  {
+  case 0:
+    /* Hard error */
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Backend didn't even return from GET /refund\n");
+    return;
+  case MHD_HTTP_OK:
+    rlo->cb (rlo->cb_cls,
+             MHD_HTTP_OK,
+             TALER_EC_NONE,
+             json);
+    TALER_MERCHANT_refund_lookup_cancel (rlo);
+    break;
+  default:
+    /**
+     * The backend gave response, but it's error, log it.
+     * NOTE that json must be a Taler-specific error object (FIXME,
+     * need a link to error objects at docs)
+     */
+    json_unpack ((json_t *) json,
+                 "{s:s, s:I, s:s}",
+                 "error", &error,
+                 "code", &code);
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Failed GET /refund, error: %s, code: %d\n",
+                error,
+                code);
+  }
+}
+
+/**
+ * Does a GET /refund.
+ *
+ * @param ctx execution context
+ * @param backend_uri base URL of the merchant backend
+ * @param order_id order id used to perform the lookup
+ * @param cb callback which will work the response gotten from the backend
+ * @param cb_cls closure to pass to the callback
+ * @return handle for this operation, NULL upon errors
+ */
+struct TALER_MERCHANT_RefundLookupOperation *
+TALER_MERCHANT_refund_lookup (struct GNUNET_CURL_Context *ctx,
+                              const char *backend_uri,
+                              const char *order_id,
+                              const char *instance,
+                              TALER_MERCHANT_RefundLookupCallback cb,
+                              void *cb_cls)
+{
+  struct TALER_MERCHANT_RefundLookupOperation *rlo;
+  CURL *eh;
+
+  rlo = GNUNET_new (struct TALER_MERCHANT_RefundLookupOperation);
+  rlo->ctx = ctx;
+  rlo->cb = cb;
+  rlo->cb_cls = cb_cls;
+
+  GNUNET_asprintf (&rlo->url,
+                   "%s/refund?instance=%s&order_id=%s",
+                   backend_uri,
+                   instance,
+                   order_id);
+  eh = curl_easy_init ();
+  if (CURLE_OK != curl_easy_setopt (eh,
+                                    CURLOPT_URL,
+                                    rlo->url))
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
+
+  if (NULL == (rlo->job = GNUNET_CURL_job_add (ctx,
+                                               eh,
+                                               GNUNET_NO,
+                                               handle_refund_lookup_finished,
+                                               rlo)))
+  {
+    GNUNET_break (0);
+    return NULL;
+  
+  }
+
+  return rlo;
+}
diff --git a/src/lib/merchant_api_track_transaction.c 
b/src/lib/merchant_api_track_transaction.c
index 560408f..25a88b7 100644
--- a/src/lib/merchant_api_track_transaction.c
+++ b/src/lib/merchant_api_track_transaction.c
@@ -30,6 +30,7 @@
 #include "taler_merchant_service.h"
 #include <taler/taler_json_lib.h>
 #include <taler/taler_signatures.h>
+#include "merchant_api_common.h"
 
 
 /**
@@ -168,16 +169,20 @@ TALER_MERCHANT_track_transaction (struct 
GNUNET_CURL_Context *ctx,
 {
   struct TALER_MERCHANT_TrackTransactionHandle *tdo;
   CURL *eh;
+  char *base;
 
   tdo = GNUNET_new (struct TALER_MERCHANT_TrackTransactionHandle);
   tdo->ctx = ctx;
   tdo->cb = track_transaction_cb;
   tdo->cb_cls = track_transaction_cb_cls;
+  base = MAH_path_to_url_ (backend_uri,
+                          "/track/transaction");
   GNUNET_asprintf (&tdo->url,
-                   "%s/track/transaction?order_id=%s&instance=%s",
-                   backend_uri,
+                   "%s?order_id=%s&instance=%s",
+                   base,
                    order_id,
                    instance);
+  GNUNET_free (base);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Requesting URI '%s'\n",
               tdo->url);
diff --git a/src/lib/merchant_api_track_transfer.c 
b/src/lib/merchant_api_track_transfer.c
index fcd208c..f0b6590 100644
--- a/src/lib/merchant_api_track_transfer.c
+++ b/src/lib/merchant_api_track_transfer.c
@@ -30,6 +30,7 @@
 #include "taler_merchant_service.h"
 #include <taler/taler_json_lib.h>
 #include <taler/taler_signatures.h>
+#include "merchant_api_common.h"
 
 
 /**
@@ -234,6 +235,7 @@ TALER_MERCHANT_track_transfer (struct GNUNET_CURL_Context 
*ctx,
   struct TALER_MERCHANT_TrackTransferHandle *tdo;
   CURL *eh;
   char *wtid_str;
+  char *base;
 
   wtid_str = GNUNET_STRINGS_data_to_string_alloc (wtid,
                                                   sizeof (struct 
TALER_WireTransferIdentifierRawP));
@@ -242,12 +244,15 @@ TALER_MERCHANT_track_transfer (struct GNUNET_CURL_Context 
*ctx,
   tdo->cb = track_transfer_cb; // very last to be called
   tdo->cb_cls = track_transfer_cb_cls;
   /* TODO: do we need to escape 'exchange_uri' here? */
+  base = MAH_path_to_url_ (backend_uri,
+                          "/track/transfer");
   GNUNET_asprintf (&tdo->url,
-                   "%s/track/transfer?wtid=%s&exchange=%s&instance=%s",
-                   backend_uri,
+                   "%s?wtid=%s&exchange=%s&instance=%s",
+                   base,
                    wtid_str,
                    exchange_uri,
                   instance);
+  GNUNET_free (base);
   GNUNET_free (wtid_str);
   eh = curl_easy_init ();
   GNUNET_assert (CURLE_OK ==
diff --git a/src/lib/test_merchant_api.c b/src/lib/test_merchant_api.c
index 4b157ee..f7fe943 100644
--- a/src/lib/test_merchant_api.c
+++ b/src/lib/test_merchant_api.c
@@ -26,6 +26,7 @@
 #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>
@@ -96,6 +97,11 @@ unsigned int ninstances = 0;
 static char *instance;
 
 /**
+ * Current instance key
+ */
+struct GNUNET_CRYPTO_EddsaPrivateKey *instance_priv;
+
+/**
  * Current instance being tested
  */
 unsigned int instance_idx = 0;
@@ -190,7 +196,17 @@ enum OpCode
   /**
    * Test getting transactions based on timestamp
    */
-  OC_HISTORY
+  OC_HISTORY,
+
+  /**
+   * Test the increase of a order refund
+   */
+  OC_REFUND_INCREASE,
+
+  /**
+   * Test refund lookup
+   */
+  OC_REFUND_LOOKUP 
 
 };
 
@@ -522,9 +538,9 @@ struct Command
       uint64_t account_credit;
 
       /**
-       * Set (!) to the wire transfer identifier observed.
+       * Set (!) to the wire transfer subject observed.
        */
-      struct TALER_WireTransferIdentifierRawP wtid;
+      char *subject;
 
     } check_bank_transfer;
 
@@ -609,7 +625,64 @@ struct Command
 
     } history;
 
+    struct {
+      /**
+       * Reference to the order we want reimbursed
+       */
+      char *order_id;
 
+      /**
+       * Handle to a refund increase operation
+       */
+      struct TALER_MERCHANT_RefundIncreaseOperation *rio;
+
+      /**
+       * Amount to refund
+       */
+      const char *refund_amount;
+      
+      /**
+       * Reason for refunding
+       */
+      const char *reason;
+
+      /**
+       * Refund fee (MUST match the value given in config)
+       */
+      const char *refund_fee;
+
+    } refund_increase;
+
+    struct {
+
+      /**
+       * Reference to the order whose refund was increased
+       */
+      char *order_id;
+
+      /**
+       * Handle to the operation
+       */
+      struct TALER_MERCHANT_RefundLookupOperation *rlo;
+
+      /**
+       * Used to retrieve the asked refund amount.
+       * This information helps the callback to mock a GET /refund
+       * response and match it against what the backend actually
+       * responded.
+       */
+      char *increase_ref;
+
+      /**
+       * Used to retrieve the number and denomination of coins
+       * used to pay for the related contract.
+       * This information helps the callback to mock a GET /refund
+       * response and match it against what the backend actually
+       * responded.
+       */
+      char *pay_ref;
+
+    } refund_lookup;
 
   } details;
 
@@ -650,6 +723,40 @@ struct InterpreterState
  */
 static struct GNUNET_DISK_PipeHandle *sigpipe;
 
+/**
+ * Return instance private key from config
+ *
+ * @param config configuration handle
+ * @param instance instance name
+ * @return pointer to private key, NULL on error
+ */
+struct GNUNET_CRYPTO_EddsaPrivateKey *
+get_instance_priv (struct GNUNET_CONFIGURATION_Handle *config,
+                   const char *instance)
+{
+  char *config_section;
+  char *filename;
+  struct GNUNET_CRYPTO_EddsaPrivateKey *ret;
+  
+  (void) GNUNET_asprintf (&config_section,
+                          "merchant-instance-%s",
+                          instance);
+
+  if (GNUNET_OK !=
+        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)))
+    GNUNET_break (0);
+
+  return ret;
+}
 
 /**
  * The testcase failed, return with an error code.
@@ -788,10 +895,6 @@ history_cb (void *cls,
     fail (is);
     return;
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "/history data: %s\n",
-              json_dumps (json, JSON_INDENT (1)));
-
   next_command (is);
 }
 
@@ -1089,12 +1192,152 @@ proposal_cb (void *cls,
 
 
 /**
+ * Process POST /refund (increase) response
+ *
+ * @param cls closure
+ * @param http_status HTTP status code
+ * @param ec taler-specific error object
+ * @param obj response body; is NULL on success.
+ */
+static void
+refund_increase_cb (void *cls,
+                    unsigned int http_status,
+                    enum TALER_ErrorCode ec,
+                    const json_t *obj)
+{
+  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,
+                "Refund increase failed\n");
+    fail (is);
+    return;
+  }
+  cmd->details.refund_increase.rio = NULL;
+  next_command (is);
+}
+
+/**
+ * Process GET /refund (increase) response. 
+ *
+ * @param cls closure
+ * @param http_status HTTP status code
+ * @param ec taler-specific error object
+ * @param obj response body; is NULL on error.
+ */
+static void
+refund_lookup_cb (void *cls,
+                  unsigned int http_status,
+                  enum TALER_ErrorCode ec,
+                  const json_t *obj)
+{
+  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;
+  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;
+
+  if (MHD_HTTP_OK != http_status)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Refund lookup failed\n");
+    fail (is);
+    return;
+  }
+
+  increase_ref = find_command (is, cmd->details.refund_lookup.increase_ref);
+  GNUNET_assert (NULL != increase_ref);
+
+  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));
+
+  pay_ref = find_command (is, cmd->details.refund_lookup.pay_ref);
+  GNUNET_assert (NULL != pay_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))
+  {
+    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)));
+    fail (is);
+  }
+
+  cmd->details.refund_lookup.rlo = NULL;
+  next_command (is);
+}
+
+
+/**
  * Function called with the result of a /pay operation.
  *
  * @param cls closure with the interpreter state
  * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful 
deposit;
  *                    0 if the exchange's reply is bogus (fails to follow the 
protocol)
- * @param ec taler-specific error code
+ * @param ec taler-specific error object
  * @param obj the received JSON reply, should be kept as proof (and, in case 
of errors,
  *            be forwarded to the customer)
  */
@@ -1108,7 +1351,6 @@ pay_cb (void *cls,
   struct Command *cmd = &is->commands[is->ip];
   struct PaymentResponsePS mr;
   struct GNUNET_CRYPTO_EddsaSignature sig;
-  struct GNUNET_HashCode h_contract_terms;
   const char *error_name;
   unsigned int error_line;
 
@@ -1128,7 +1370,7 @@ pay_cb (void *cls,
     /* Check signature */
     struct GNUNET_JSON_Specification spec[] = {
       GNUNET_JSON_spec_fixed_auto ("sig", &sig),
-      GNUNET_JSON_spec_fixed_auto ("h_contract_terms", &h_contract_terms),
+      GNUNET_JSON_spec_fixed_auto ("h_contract_terms", 
&cmd->details.pay.h_contract_terms),
       GNUNET_JSON_spec_end ()
     };
     if (GNUNET_OK !=
@@ -1147,7 +1389,7 @@ pay_cb (void *cls,
     }
     mr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_PAYMENT_OK);
     mr.purpose.size = htonl (sizeof (mr));
-    mr.h_contract_terms = h_contract_terms;
+    mr.h_contract_terms = cmd->details.pay.h_contract_terms;
     if (GNUNET_OK !=
         GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_PAYMENT_OK,
                                     &mr.purpose,
@@ -1217,10 +1459,6 @@ track_transfer_cb (void *cls,
   struct InterpreterState *is = cls;
   struct Command *cmd = &is->commands[is->ip];
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Tracked transfers: '%s'.\n",
-              json_dumps (json, JSON_INDENT (1)));
-
   cmd->details.track_transfer.tdo = NULL;
   if (cmd->expected_response_code != http_status)
   {
@@ -1465,6 +1703,8 @@ cleanup_state (struct InterpreterState *is)
       }
       break;
     case OC_CHECK_BANK_TRANSFER:
+      GNUNET_free_non_null (cmd->details.check_bank_transfer.subject);
+      cmd->details.check_bank_transfer.subject = NULL;
       break;
     case OC_CHECK_BANK_TRANSFERS_EMPTY:
       break;
@@ -1483,7 +1723,6 @@ cleanup_state (struct InterpreterState *is)
       }
       break;
     case OC_HISTORY:
-
       if (NULL != cmd->details.history.ho)
       {
         TALER_MERCHANT_history_cancel (cmd->details.history.ho);
@@ -1491,6 +1730,21 @@ cleanup_state (struct InterpreterState *is)
       }
       break;
 
+    case OC_REFUND_INCREASE:
+      if (NULL != cmd->details.refund_increase.rio)
+      {
+        TALER_MERCHANT_refund_increase_cancel 
(cmd->details.refund_increase.rio);
+        cmd->details.refund_increase.rio = NULL;
+      }
+      break;
+
+    case OC_REFUND_LOOKUP:
+      if (NULL != cmd->details.refund_lookup.rlo)
+      {
+        TALER_MERCHANT_refund_lookup_cancel (cmd->details.refund_lookup.rlo); 
+        cmd->details.refund_lookup.rlo = NULL;
+      }
+      break;
     default:
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   "Shutdown: unknown instruction %d at %u (%s)\n",
@@ -1516,137 +1770,138 @@ 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)
+      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))
       {
-        GNUNET_SCHEDULER_shutdown ();
+        fprintf (stderr,
+                 "Test aborted by shutdown request\n");
+        fail (is);
         return;
       }
-      cleanup_state (is);
-      is->ip = 0;
-      instance_idx++;
-      instance = instances[instance_idx];
-      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);
+      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;
 
-      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)));
-    }
+        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;
+        return;
 
-  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;
+      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;
 
-      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;
-    }
+          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;
+        }
 
-    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);
+        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);
 
-    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;
-    }
+        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;
+        }
 
-    cmd->details.admin_add_incoming.aih
-      = TALER_EXCHANGE_admin_add_incoming (exchange,
-                                           "http://localhost:18080/";,
-                                           &reserve_pub,
-                                           &amount,
-                                           execution_date,
-                                           sender_details,
+        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);
@@ -1944,11 +2199,11 @@ interpreter_run (void *cls)
       }
       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.wtid))
+                                &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);
@@ -1970,18 +2225,29 @@ interpreter_run (void *cls)
       return;
     }
   case OC_TRACK_TRANSFER:
-    ref = find_command (is,
-                        cmd->details.track_transfer.check_bank_ref);
-    GNUNET_assert (NULL != ref);
-    cmd->details.track_transfer.tdo =
-      TALER_MERCHANT_track_transfer (ctx,
-                                     MERCHANT_URI,
-                                     instance,
-                                     &ref->details.check_bank_transfer.wtid,
-                                     EXCHANGE_URI,
-                                     &track_transfer_cb,
-                                     is);
-    return;
+    {
+      struct TALER_WireTransferIdentifierRawP wtid;
+      const char *subject;
+
+      ref = find_command (is,
+                          cmd->details.track_transfer.check_bank_ref);
+      GNUNET_assert (NULL != 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;
+    }
   case OC_TRACK_TRANSACTION:
   {
     const struct Command *proposal_ref;
@@ -2018,8 +2284,50 @@ interpreter_run (void *cls)
       fail (is);
       return;
     }
-  break;
+    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_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Could not issue a /refund increase request\n");
+      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)))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Could not issue a /refund lookup request\n");
+      fail (is);
+      return;
+    }
+    break;
+  }
   default:
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Unknown instruction %d at %u (%s)\n",
@@ -2064,6 +2372,7 @@ do_shutdown (void *cls)
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Shutdown executing\n");
   cleanup_state (is);
+
   if (NULL != is->task)
   {
     GNUNET_SCHEDULER_cancel (is->task);
@@ -2091,7 +2400,11 @@ 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);
 }
@@ -2104,10 +2417,12 @@ do_shutdown (void *cls)
  *
  * @param cls closure
  * @param keys information about keys of the exchange
+ * @param vc compatibility information
  */
 static void
 cert_cb (void *cls,
-         const struct TALER_EXCHANGE_Keys *keys)
+         const struct TALER_EXCHANGE_Keys *keys,
+        enum TALER_EXCHANGE_VersionCompatibility vc)
 {
   struct InterpreterState *is = cls;
 
@@ -2228,6 +2543,7 @@ run (void *cls)
                   \"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}\"} 
] }" },
 
@@ -2380,7 +2696,19 @@ run (void *cls)
       .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"    
+    },
+    { .oc = OC_REFUND_LOOKUP,
+      .label = "refund-lookup-1",
+      .details.refund_lookup.order_id = "1",
+      .details.refund_lookup.increase_ref = "refund-increase-1",
+      .details.refund_lookup.pay_ref = "deposit-simple"
+    },
     /* end of testcase */
     { .oc = OC_END }
   };
@@ -2461,6 +2789,7 @@ main (int argc,
                          GNUNET_strdup (token));
   GNUNET_free (_instances);
   instance = instances[instance_idx];
+  instance_priv = get_instance_priv (cfg, instance);
   db = TALER_MERCHANTDB_plugin_load (cfg);
   if (NULL == db)
   {
diff --git a/src/merchant-tools/taler-merchant-generate-payments.c 
b/src/merchant-tools/taler-merchant-generate-payments.c
index 5faa55a..8ba3704 100644
--- a/src/merchant-tools/taler-merchant-generate-payments.c
+++ b/src/merchant-tools/taler-merchant-generate-payments.c
@@ -1315,10 +1315,12 @@ interpreter_run (void *cls)
  *
  * @param cls closure
  * @param keys information about keys of the exchange
+ * @param compat version compatibility data
  */
 static void
 cert_cb (void *cls,
-         const struct TALER_EXCHANGE_Keys *keys)
+         const struct TALER_EXCHANGE_Keys *keys,
+        enum TALER_EXCHANGE_VersionCompatibility compat)
 {
   struct InterpreterState *is = cls;
 
@@ -1738,9 +1740,14 @@ run (void *cls,
     fprintf (stderr, "\n");
     GNUNET_free (wget_cmd);
   }
+  /* timeout, given 60s + 5s per command, which should be more
+     than enough */
   timeout_task
-    = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
-                                    (GNUNET_TIME_UNIT_SECONDS, 150),
+    = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_add
+                                   (GNUNET_TIME_UNIT_MINUTES,
+                                    GNUNET_TIME_relative_multiply
+                                    (GNUNET_TIME_UNIT_SECONDS,
+                                     5 * times)),
                                     &do_timeout, NULL);
   run_test ();
 }

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



reply via email to

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