gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant] branch master updated: Factor out 13 new functions (shi


From: gnunet
Subject: [taler-merchant] branch master updated: Factor out 13 new functions (shit job)
Date: Sat, 13 May 2023 07:17:43 +0200

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

ivan-avalos pushed a commit to branch master
in repository merchant.

The following commit(s) were added to refs/heads/master by this push:
     new 594aa457 Factor out 13 new functions (shit job)
594aa457 is described below

commit 594aa4576f9ec45315c4d253356b9962d59d46c2
Author: Iván Ávalos <avalos@disroot.org>
AuthorDate: Fri May 12 23:16:21 2023 -0600

    Factor out 13 new functions (shit job)
---
 src/backenddb/Makefile.am                  |   13 +
 src/backenddb/pg_delete_contract_terms.c   |   59 +
 src/backenddb/pg_delete_contract_terms.h   |   47 +
 src/backenddb/pg_delete_order.c            |   87 +
 src/backenddb/pg_delete_order.h            |   45 +
 src/backenddb/pg_expire_locks.c            |   84 +
 src/backenddb/pg_expire_locks.h            |   38 +
 src/backenddb/pg_insert_contract_terms.c   |  132 +
 src/backenddb/pg_insert_contract_terms.h   |   52 +
 src/backenddb/pg_insert_order.c            |   82 +
 src/backenddb/pg_insert_order.h            |   53 +
 src/backenddb/pg_insert_order_lock.c       |   78 +
 src/backenddb/pg_insert_order_lock.h       |   47 +
 src/backenddb/pg_lookup_contract_terms.c   |   82 +
 src/backenddb/pg_lookup_contract_terms.h   |   50 +
 src/backenddb/pg_lookup_contract_terms2.c  |   96 +
 src/backenddb/pg_lookup_contract_terms2.h  |   54 +
 src/backenddb/pg_lookup_order.c            |   96 +
 src/backenddb/pg_lookup_order.h            |   49 +
 src/backenddb/pg_lookup_order_summary.c    |   75 +
 src/backenddb/pg_lookup_order_summary.h    |   45 +
 src/backenddb/pg_lookup_orders.c           |  926 +++++
 src/backenddb/pg_lookup_orders.h           |   45 +
 src/backenddb/pg_unlock_inventory.c        |   47 +
 src/backenddb/pg_unlock_inventory.h        |   42 +
 src/backenddb/pg_update_contract_terms.c   |  103 +
 src/backenddb/pg_update_contract_terms.h   |   49 +
 src/backenddb/plugin_merchantdb_postgres.c | 5833 ++++++++++------------------
 28 files changed, 4623 insertions(+), 3786 deletions(-)

diff --git a/src/backenddb/Makefile.am b/src/backenddb/Makefile.am
index 91b48223..1b400bce 100644
--- a/src/backenddb/Makefile.am
+++ b/src/backenddb/Makefile.am
@@ -81,6 +81,19 @@ libtaler_plugin_merchantdb_postgres_la_SOURCES = \
   pg_insert_product.h pg_insert_product.c \
   pg_update_product.h pg_update_product.c \
   pg_lock_product.h pg_lock_product.c \
+  pg_expire_locks.h pg_expire_locks.c \
+  pg_delete_order.h pg_delete_order.c \
+  pg_lookup_order.h pg_lookup_order.c \
+  pg_lookup_order_summary.h pg_lookup_order_summary.c \
+  pg_lookup_orders.h pg_lookup_orders.c \
+  pg_insert_order.h pg_insert_order.c \
+  pg_unlock_inventory.h pg_unlock_inventory.c \
+  pg_insert_order_lock.h pg_insert_order_lock.c \
+  pg_lookup_contract_terms2.h pg_lookup_contract_terms2.c \
+  pg_lookup_contract_terms.h pg_lookup_contract_terms.c \
+  pg_insert_contract_terms.h pg_insert_contract_terms.c \
+  pg_update_contract_terms.h pg_update_contract_terms.c \
+  pg_delete_contract_terms.h pg_delete_contract_terms.c \
   plugin_merchantdb_postgres.c  pg_helper.h
 libtaler_plugin_merchantdb_postgres_la_LIBADD = \
   $(LTLIBINTL)
diff --git a/src/backenddb/pg_delete_contract_terms.c 
b/src/backenddb/pg_delete_contract_terms.c
new file mode 100644
index 00000000..708a724a
--- /dev/null
+++ b/src/backenddb/pg_delete_contract_terms.c
@@ -0,0 +1,59 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_delete_contract_terms.c
+ * @brief Implementation of the delete_contract_terms function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_delete_contract_terms.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_delete_contract_terms (void *cls,
+                              const char *instance_id,
+                              const char *order_id,
+                              struct GNUNET_TIME_Relative legal_expiration)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_string (order_id),
+    GNUNET_PQ_query_param_relative_time (&legal_expiration),
+    GNUNET_PQ_query_param_absolute_time (&now),
+    GNUNET_PQ_query_param_end
+  };
+
+  check_connection (pg);
+  PREPARE (pg,
+           "delete_contract_terms",
+           "DELETE FROM merchant_contract_terms"
+           " WHERE order_id=$2"
+           "   AND merchant_serial="
+           "     (SELECT merchant_serial"
+           "        FROM merchant_instances"
+           "        WHERE merchant_id=$1)"
+           "   AND ( ( (pay_deadline < $4) AND"
+           "           (NOT paid) ) OR"
+           "         (creation_time + $3 < $4) )");
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "delete_contract_terms",
+                                             params);
+}
diff --git a/src/backenddb/pg_delete_contract_terms.h 
b/src/backenddb/pg_delete_contract_terms.h
new file mode 100644
index 00000000..ce74a3c5
--- /dev/null
+++ b/src/backenddb/pg_delete_contract_terms.h
@@ -0,0 +1,47 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_delete_contract_terms.h
+ * @brief implementation of the delete_contract_terms function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_DELETE_CONTRACT_TERMS_H
+#define PG_DELETE_CONTRACT_TERMS_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Delete information about a contract. Note that the transaction must
+ * enforce that the contract is not awaiting payment anymore AND was not
+ * paid, or is past the legal expiration.
+ *
+ * @param cls closure
+ * @param instance_id instance to delete order of
+ * @param order_id order to delete
+ * @param legal_expiration how long do we need to keep (paid) contracts on
+ *          file for legal reasons (i.e. taxation)
+ * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
+ *           if locks prevent deletion OR order unknown
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_delete_contract_terms (void *cls,
+                              const char *instance_id,
+                              const char *order_id,
+                              struct GNUNET_TIME_Relative legal_expiration);
+
+#endif
diff --git a/src/backenddb/pg_delete_order.c b/src/backenddb/pg_delete_order.c
new file mode 100644
index 00000000..e058be3b
--- /dev/null
+++ b/src/backenddb/pg_delete_order.c
@@ -0,0 +1,87 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_delete_order.c
+ * @brief Implementation of the delete_order function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_delete_order.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_delete_order (void *cls,
+                     const char *instance_id,
+                     const char *order_id,
+                     bool force)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_string (order_id),
+    GNUNET_PQ_query_param_absolute_time (&now),
+    GNUNET_PQ_query_param_bool (force),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_QueryParam params2[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_string (order_id),
+    GNUNET_PQ_query_param_end
+  };
+  enum GNUNET_DB_QueryStatus qs;
+
+  check_connection (pg);
+  PREPARE (pg,
+           "delete_order",
+           "WITH ms AS"
+           "(SELECT merchant_serial "
+           "   FROM merchant_instances"
+           "  WHERE merchant_id=$1)"
+           ", mc AS"
+           "(SELECT paid"
+           "   FROM merchant_contract_terms"
+           "   JOIN ms USING (merchant_serial)"
+           "  WHERE order_id=$2) "
+           "DELETE"
+           " FROM merchant_orders mo"
+           " WHERE order_id=$2"
+           "   AND merchant_serial=(SELECT merchant_serial FROM ms)"
+           "   AND (  (pay_deadline < $3)"
+           "       OR (NOT EXISTS (SELECT paid FROM mc))"
+           "       OR ($4 AND (FALSE=(SELECT paid FROM mc))) );");
+  qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                           "delete_order",
+                                           params);
+  if ( (qs <= 0) || (! force))
+    return qs;
+  PREPARE (pg,
+           "delete_contract",
+           "DELETE"
+           " FROM merchant_contract_terms"
+           " WHERE order_id=$2 AND"
+           "   merchant_serial="
+           "     (SELECT merchant_serial "
+           "        FROM merchant_instances"
+           "        WHERE merchant_id=$1)"
+           "   AND NOT paid;");
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "delete_contract",
+                                             params2);
+}
diff --git a/src/backenddb/pg_delete_order.h b/src/backenddb/pg_delete_order.h
new file mode 100644
index 00000000..58f3e5bb
--- /dev/null
+++ b/src/backenddb/pg_delete_order.h
@@ -0,0 +1,45 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_delete_order.h
+ * @brief implementation of the delete_order function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_DELETE_ORDER_H
+#define PG_DELETE_ORDER_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Delete information about an order.  Note that the transaction must
+ * enforce that the order is not awaiting payment anymore.
+ *
+ * @param cls closure
+ * @param instance_id instance to delete order of
+ * @param order_id order to delete
+ * @param force delete claimed but unpaid orders as well
+ * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
+ *           if pending payment prevents deletion OR order unknown
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_delete_order (void *cls,
+                     const char *instance_id,
+                     const char *order_id,
+                     bool force);
+
+#endif
diff --git a/src/backenddb/pg_expire_locks.c b/src/backenddb/pg_expire_locks.c
new file mode 100644
index 00000000..4b12ba04
--- /dev/null
+++ b/src/backenddb/pg_expire_locks.c
@@ -0,0 +1,84 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_expire_locks.c
+ * @brief Implementation of the expire_locks function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_expire_locks.h"
+#include "pg_helper.h"
+
+void
+TMH_PG_expire_locks (void *cls)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_absolute_time (&now),
+    GNUNET_PQ_query_param_end
+  };
+  enum GNUNET_DB_QueryStatus qs1;
+  enum GNUNET_DB_QueryStatus qs2;
+  enum GNUNET_DB_QueryStatus qs3;
+
+  check_connection (pg);
+  PREPARE (pg,
+           "unlock_products",
+           "DELETE FROM merchant_inventory_locks"
+           " WHERE expiration < $1");
+  qs1 = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                            "unlock_products",
+                                            params);
+  if (qs1 < 0)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  PREPARE (pg,
+           "unlock_orders",
+           "DELETE FROM merchant_orders"
+           " WHERE pay_deadline < $1");
+  qs2 = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                            "unlock_orders",
+                                            params);
+  if (qs2 < 0)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  PREPARE (pg,
+           "unlock_contracts",
+           "DELETE FROM merchant_contract_terms"
+           " WHERE NOT paid"
+           "   AND pay_deadline < $1");
+  qs3 = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                            "unlock_contracts",
+                                            params);
+  if (qs3 < 0)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Released %d+%d+%d locks\n",
+              qs1,
+              qs2,
+              qs3);
+}
diff --git a/src/backenddb/pg_expire_locks.h b/src/backenddb/pg_expire_locks.h
new file mode 100644
index 00000000..6eac73de
--- /dev/null
+++ b/src/backenddb/pg_expire_locks.h
@@ -0,0 +1,38 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_expire_locks.h
+ * @brief implementation of the expire_locks function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_EXPIRE_LOCKS_H
+#define PG_EXPIRE_LOCKS_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Release all expired product locks, including
+ * those from expired offers -- across all
+ * instances.
+ *
+ * @param cls closure
+ */
+void
+TMH_PG_expire_locks (void *cls);
+
+#endif
diff --git a/src/backenddb/pg_insert_contract_terms.c 
b/src/backenddb/pg_insert_contract_terms.c
new file mode 100644
index 00000000..2bc6ab86
--- /dev/null
+++ b/src/backenddb/pg_insert_contract_terms.c
@@ -0,0 +1,132 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_insert_contract_terms.c
+ * @brief Implementation of the insert_contract_terms function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_insert_contract_terms.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_contract_terms (
+  void *cls,
+  const char *instance_id,
+  const char *order_id,
+  json_t *contract_terms,
+  uint64_t *order_serial)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_TIME_Timestamp pay_deadline;
+  struct GNUNET_TIME_Timestamp refund_deadline;
+  const char *fulfillment_url;
+  struct TALER_PrivateContractHashP h_contract_terms;
+
+  if (GNUNET_OK !=
+      TALER_JSON_contract_hash (contract_terms,
+                                &h_contract_terms))
+  {
+    GNUNET_break (0);
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  }
+
+  {
+    struct GNUNET_JSON_Specification spec[] = {
+      GNUNET_JSON_spec_timestamp ("pay_deadline",
+                                  &pay_deadline),
+      GNUNET_JSON_spec_timestamp ("refund_deadline",
+                                  &refund_deadline),
+      GNUNET_JSON_spec_end ()
+    };
+    enum GNUNET_GenericReturnValue res;
+
+    res = TALER_MHD_parse_json_data (NULL,
+                                     contract_terms,
+                                     spec);
+    if (GNUNET_OK != res)
+    {
+      GNUNET_break (0);
+      return GNUNET_DB_STATUS_HARD_ERROR;
+    }
+  }
+
+  fulfillment_url =
+    json_string_value (json_object_get (contract_terms,
+                                        "fulfillment_url"));
+  check_connection (pg);
+  {
+    struct GNUNET_PQ_QueryParam params[] = {
+      GNUNET_PQ_query_param_string (instance_id),
+      GNUNET_PQ_query_param_string (order_id),
+      TALER_PQ_query_param_json (contract_terms),
+      GNUNET_PQ_query_param_auto_from_type (&h_contract_terms),
+      GNUNET_PQ_query_param_timestamp (&pay_deadline),
+      GNUNET_PQ_query_param_timestamp (&refund_deadline),
+      (NULL == fulfillment_url)
+      ? GNUNET_PQ_query_param_null ()
+      : GNUNET_PQ_query_param_string (fulfillment_url),
+      GNUNET_PQ_query_param_end
+    };
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      GNUNET_PQ_result_spec_uint64 ("order_serial",
+                                    order_serial),
+      GNUNET_PQ_result_spec_end
+    };
+    PREPARE (pg,
+             "insert_contract_terms",
+             "INSERT INTO merchant_contract_terms"
+             "(order_serial"
+             ",merchant_serial"
+             ",order_id"
+             ",contract_terms"
+             ",h_contract_terms"
+             ",creation_time"
+             ",pay_deadline"
+             ",refund_deadline"
+             ",fulfillment_url"
+             ",claim_token"
+             ",pos_key"
+             ",pos_algorithm)"
+             "SELECT"
+             " mo.order_serial"
+             ",mo.merchant_serial"
+             ",mo.order_id"
+             ",$3"  /* contract_terms */
+             ",$4"  /* h_contract_terms */
+             ",mo.creation_time"
+             ",$5" /* pay_deadline */
+             ",$6" /* refund_deadline */
+             ",$7" /* fulfillment_url */
+             ",mo.claim_token"
+             ",mo.pos_key"
+             ",mo.pos_algorithm"
+             " FROM merchant_orders mo"
+             " WHERE order_id=$2"
+             "   AND merchant_serial="
+             "     (SELECT merchant_serial"
+             "        FROM merchant_instances"
+             "        WHERE merchant_id=$1)"
+             " RETURNING order_serial");
+    return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                     "insert_contract_terms",
+                                                     params,
+                                                     rs);
+  }
+}
diff --git a/src/backenddb/pg_insert_contract_terms.h 
b/src/backenddb/pg_insert_contract_terms.h
new file mode 100644
index 00000000..8f22f5b8
--- /dev/null
+++ b/src/backenddb/pg_insert_contract_terms.h
@@ -0,0 +1,52 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_insert_contract_terms.h
+ * @brief implementation of the insert_contract_terms function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_INSERT_CONTRACT_TERMS_H
+#define PG_INSERT_CONTRACT_TERMS_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Store contract terms given its @a order_id. Note that some attributes are
+ * expected to be calculated inside of the function, like the hash of the
+ * contract terms (to be hashed), the creation_time and pay_deadline (to be
+ * obtained from the merchant_orders table). The "session_id" should be
+ * initially set to the empty string.  The "fulfillment_url" and 
"refund_deadline"
+ * must be extracted from @a contract_terms.
+ *
+ * @param cls closure
+ * @param instance_id instance's identifier
+ * @param order_id order_id used to store
+ * @param contract_terms contract terms to store
+ * @param[out] order_serial set to the serial of the order
+ * @return transaction status, #GNUNET_DB_STATUS_HARD_ERROR if @a 
contract_terms
+ *          is malformed
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_contract_terms (
+  void *cls,
+  const char *instance_id,
+  const char *order_id,
+  json_t *contract_terms,
+  uint64_t *order_serial);
+
+#endif
diff --git a/src/backenddb/pg_insert_order.c b/src/backenddb/pg_insert_order.c
new file mode 100644
index 00000000..7c7ad486
--- /dev/null
+++ b/src/backenddb/pg_insert_order.c
@@ -0,0 +1,82 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_insert_order.c
+ * @brief Implementation of the insert_order function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_insert_order.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_order (void *cls,
+                     const char *instance_id,
+                     const char *order_id,
+                     const struct TALER_MerchantPostDataHashP *h_post_data,
+                     struct GNUNET_TIME_Timestamp pay_deadline,
+                     const struct TALER_ClaimTokenP *claim_token,
+                     const json_t *contract_terms,
+                     const char *pos_key,
+                     enum TALER_MerchantConfirmationAlgorithm pos_algorithm)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_TIME_Timestamp now;
+  uint32_t pos32 = (uint32_t) pos_algorithm;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_string (order_id),
+    GNUNET_PQ_query_param_timestamp (&pay_deadline),
+    GNUNET_PQ_query_param_auto_from_type (claim_token),
+    GNUNET_PQ_query_param_auto_from_type (h_post_data),
+    GNUNET_PQ_query_param_timestamp (&now),
+    TALER_PQ_query_param_json (contract_terms),
+    (NULL == pos_key)
+    ? GNUNET_PQ_query_param_null ()
+    : GNUNET_PQ_query_param_string (pos_key),
+    GNUNET_PQ_query_param_uint32 (&pos32),
+    GNUNET_PQ_query_param_end
+  };
+
+  now = GNUNET_TIME_timestamp_get ();
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "inserting order: order_id: %s, instance_id: %s.\n",
+              order_id,
+              instance_id);
+  check_connection (pg);
+  PREPARE (pg,
+           "insert_order",
+           "INSERT INTO merchant_orders"
+           "(merchant_serial"
+           ",order_id"
+           ",pay_deadline"
+           ",claim_token"
+           ",h_post_data"
+           ",creation_time"
+           ",contract_terms"
+           ",pos_key"
+           ",pos_algorithm)"
+           " SELECT merchant_serial,"
+           " $2, $3, $4, $5, $6, $7, $8, $9"
+           " FROM merchant_instances"
+           " WHERE merchant_id=$1");
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "insert_order",
+                                             params);
+}
diff --git a/src/backenddb/pg_insert_order.h b/src/backenddb/pg_insert_order.h
new file mode 100644
index 00000000..297d9bdf
--- /dev/null
+++ b/src/backenddb/pg_insert_order.h
@@ -0,0 +1,53 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_insert_order.h
+ * @brief implementation of the insert_order function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_INSERT_ORDER_H
+#define PG_INSERT_ORDER_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Insert order into the DB.
+ *
+ * @param cls closure
+ * @param instance_id identifies the instance responsible for the order
+ * @param order_id alphanumeric string that uniquely identifies the proposal
+ * @param h_post_data hash of the POST data for idempotency checks
+ * @param pay_deadline how long does the customer have to pay for the order
+ * @param claim_token token to use for access control
+ * @param contract_terms proposal data to store
+ * @param pos_key encoded key for payment verification
+ * @param pos_algorithm algorithm to compute the payment verification
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_order (void *cls,
+                     const char *instance_id,
+                     const char *order_id,
+                     const struct TALER_MerchantPostDataHashP *h_post_data,
+                     struct GNUNET_TIME_Timestamp pay_deadline,
+                     const struct TALER_ClaimTokenP *claim_token,
+                     const json_t *contract_terms,
+                     const char *pos_key,
+                     enum TALER_MerchantConfirmationAlgorithm pos_algorithm);
+
+#endif
diff --git a/src/backenddb/pg_insert_order_lock.c 
b/src/backenddb/pg_insert_order_lock.c
new file mode 100644
index 00000000..862a6320
--- /dev/null
+++ b/src/backenddb/pg_insert_order_lock.c
@@ -0,0 +1,78 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_insert_order_lock.c
+ * @brief Implementation of the insert_order_lock function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_insert_order_lock.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_order_lock (void *cls,
+                          const char *instance_id,
+                          const char *order_id,
+                          const char *product_id,
+                          uint64_t quantity)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_string (order_id),
+    GNUNET_PQ_query_param_string (product_id),
+    GNUNET_PQ_query_param_uint64 (&quantity),
+    GNUNET_PQ_query_param_end
+  };
+
+  check_connection (pg);
+  PREPARE (pg,
+           "insert_order_lock",
+           "WITH tmp AS"
+           "  (SELECT "
+           "      product_serial"
+           "     ,merchant_serial"
+           "     ,total_stock"
+           "     ,total_sold"
+           "     ,total_lost"
+           "   FROM merchant_inventory"
+           "   WHERE product_id=$3"
+           "     AND merchant_serial="
+           "     (SELECT merchant_serial"
+           "        FROM merchant_instances"
+           "        WHERE merchant_id=$1))"
+           " INSERT INTO merchant_order_locks"
+           " (product_serial"
+           " ,total_locked"
+           " ,order_serial)"
+           " SELECT tmp.product_serial, $4, order_serial"
+           "   FROM merchant_orders"
+           "   JOIN tmp USING(merchant_serial)"
+           "   WHERE order_id=$2 AND"
+           "     tmp.total_stock - tmp.total_sold - tmp.total_lost - $4 >= "
+           "     (SELECT COALESCE(SUM(total_locked), 0)"
+           "        FROM merchant_inventory_locks"
+           "        WHERE product_serial=tmp.product_serial) + "
+           "     (SELECT COALESCE(SUM(total_locked), 0)"
+           "        FROM merchant_order_locks"
+           "        WHERE product_serial=tmp.product_serial)");
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "insert_order_lock",
+                                             params);
+}
diff --git a/src/backenddb/pg_insert_order_lock.h 
b/src/backenddb/pg_insert_order_lock.h
new file mode 100644
index 00000000..c2cc9908
--- /dev/null
+++ b/src/backenddb/pg_insert_order_lock.h
@@ -0,0 +1,47 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_insert_order_lock.h
+ * @brief implementation of the insert_order_lock function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_INSERT_ORDER_LOCK_H
+#define PG_INSERT_ORDER_LOCK_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Lock inventory stock to a particular order.
+ *
+ * @param cls closure
+ * @param instance_id identifies the instance responsible for the order
+ * @param order_id alphanumeric string that uniquely identifies the order
+ * @param product_id uniquely identifies the product to be locked
+ * @param quantity how many units should be locked to the @a order_id
+ * @return transaction status,
+ *   #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS means there are insufficient stocks
+ *   #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT indicates success
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_insert_order_lock (void *cls,
+                          const char *instance_id,
+                          const char *order_id,
+                          const char *product_id,
+                          uint64_t quantity);
+
+#endif
diff --git a/src/backenddb/pg_lookup_contract_terms.c 
b/src/backenddb/pg_lookup_contract_terms.c
new file mode 100644
index 00000000..e1f24ac4
--- /dev/null
+++ b/src/backenddb/pg_lookup_contract_terms.c
@@ -0,0 +1,82 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_contract_terms.c
+ * @brief Implementation of the lookup_contract_terms function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_lookup_contract_terms.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_contract_terms (
+  void *cls,
+  const char *instance_id,
+  const char *order_id,
+  json_t **contract_terms,
+  uint64_t *order_serial,
+  bool *paid,
+  struct TALER_ClaimTokenP *claim_token)
+{
+  struct PostgresClosure *pg = cls;
+  enum GNUNET_DB_QueryStatus qs;
+  struct TALER_ClaimTokenP ct;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_string (order_id),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    /* contract_terms must be first! */
+    TALER_PQ_result_spec_json ("contract_terms",
+                               contract_terms),
+    GNUNET_PQ_result_spec_uint64 ("order_serial",
+                                  order_serial),
+    GNUNET_PQ_result_spec_bool ("paid",
+                                paid),
+    GNUNET_PQ_result_spec_auto_from_type ("claim_token",
+                                          &ct),
+    GNUNET_PQ_result_spec_end
+  };
+
+  check_connection (pg);
+  PREPARE (pg,
+           "lookup_contract_terms",
+           "SELECT"
+           " contract_terms"
+           ",order_serial"
+           ",claim_token"
+           ",paid"
+           " FROM merchant_contract_terms"
+           " WHERE order_id=$2"
+           "   AND merchant_serial="
+           "     (SELECT merchant_serial"
+           "        FROM merchant_instances"
+           "        WHERE merchant_id=$1)");
+  qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                 "lookup_contract_terms",
+                                                 params,
+                                                 (NULL != contract_terms)
+                                                   ? rs
+                                                   : &rs[1]);
+  if (NULL != claim_token)
+    *claim_token = ct;
+  return qs;
+}
diff --git a/src/backenddb/pg_lookup_contract_terms.h 
b/src/backenddb/pg_lookup_contract_terms.h
new file mode 100644
index 00000000..2ab1bb16
--- /dev/null
+++ b/src/backenddb/pg_lookup_contract_terms.h
@@ -0,0 +1,50 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_contract_terms.h
+ * @brief implementation of the lookup_contract_terms function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_LOOKUP_CONTRACT_TERMS_H
+#define PG_LOOKUP_CONTRACT_TERMS_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Retrieve contract terms given its @a order_id
+ *
+ * @param cls closure
+ * @param instance_id instance's identifier
+ * @param order_id order_id used to lookup.
+ * @param[out] contract_terms where to store the result, NULL to only check 
for existence
+ * @param[out] order_serial set to the order's serial number
+ * @param[out] paid set to true if the order is fully paid
+ * @param[out] claim_token set to token to use for access control
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_contract_terms (
+  void *cls,
+  const char *instance_id,
+  const char *order_id,
+  json_t **contract_terms,
+  uint64_t *order_serial,
+  bool *paid,
+  struct TALER_ClaimTokenP *claim_token);
+
+#endif
diff --git a/src/backenddb/pg_lookup_contract_terms2.c 
b/src/backenddb/pg_lookup_contract_terms2.c
new file mode 100644
index 00000000..1fbb02ea
--- /dev/null
+++ b/src/backenddb/pg_lookup_contract_terms2.c
@@ -0,0 +1,96 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_contract_terms2.c
+ * @brief Implementation of the lookup_contract_terms2 function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_lookup_contract_terms2.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_contract_terms2 (
+  void *cls,
+  const char *instance_id,
+  const char *order_id,
+  json_t **contract_terms,
+  uint64_t *order_serial,
+  bool *paid,
+  struct TALER_ClaimTokenP *claim_token,
+  char **pos_key,
+  enum TALER_MerchantConfirmationAlgorithm *pos_algorithm)
+{
+  struct PostgresClosure *pg = cls;
+  enum GNUNET_DB_QueryStatus qs;
+  struct TALER_ClaimTokenP ct;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_string (order_id),
+    GNUNET_PQ_query_param_end
+  };
+  uint32_t pos32;
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    /* contract_terms must be first! */
+    TALER_PQ_result_spec_json ("contract_terms",
+                               contract_terms),
+    GNUNET_PQ_result_spec_uint64 ("order_serial",
+                                  order_serial),
+    GNUNET_PQ_result_spec_bool ("paid",
+                                paid),
+    GNUNET_PQ_result_spec_auto_from_type ("claim_token",
+                                          &ct),
+    GNUNET_PQ_result_spec_allow_null (
+      GNUNET_PQ_result_spec_string ("pos_key",
+                                    pos_key),
+      NULL),
+    GNUNET_PQ_result_spec_allow_null (
+      GNUNET_PQ_result_spec_uint32 ("pos_algorithm",
+                                    &pos32),
+      NULL),
+    GNUNET_PQ_result_spec_end
+  };
+
+  check_connection (pg);
+  PREPARE (pg,
+           "lookup_contract_terms2",
+           "SELECT"
+           " contract_terms"
+           ",order_serial"
+           ",claim_token"
+           ",paid"
+           ",pos_key"
+           ",pos_algorithm"
+           " FROM merchant_contract_terms"
+           " WHERE order_id=$2"
+           "   AND merchant_serial="
+           "     (SELECT merchant_serial"
+           "        FROM merchant_instances"
+           "        WHERE merchant_id=$1)");
+  qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                 "lookup_contract_terms2",
+                                                 params,
+                                                 (NULL != contract_terms)
+                                                   ? rs
+                                                   : &rs[1]);
+  *pos_algorithm = (enum TALER_MerchantConfirmationAlgorithm) pos32;
+  if (NULL != claim_token)
+    *claim_token = ct;
+  return qs;
+}
diff --git a/src/backenddb/pg_lookup_contract_terms2.h 
b/src/backenddb/pg_lookup_contract_terms2.h
new file mode 100644
index 00000000..6c1c8514
--- /dev/null
+++ b/src/backenddb/pg_lookup_contract_terms2.h
@@ -0,0 +1,54 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_contract_terms2.h
+ * @brief implementation of the lookup_contract_terms2 function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_LOOKUP_CONTRACT_TERMS2_H
+#define PG_LOOKUP_CONTRACT_TERMS2_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Retrieve contract terms given its @a order_id
+ *
+ * @param cls closure
+ * @param instance_id instance's identifier
+ * @param order_id order_id used to lookup.
+ * @param[out] contract_terms where to store the result, NULL to only check 
for existence
+ * @param[out] order_serial set to the order's serial number
+ * @param[out] paid set to true if the order is fully paid
+ * @param[out] claim_token set to the claim token, NULL to only check for 
existence
+ * @param[out] pos_key encoded key for payment verification
+ * @param[out] pos_algorithm algorithm to compute the payment verification
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_contract_terms2 (
+  void *cls,
+  const char *instance_id,
+  const char *order_id,
+  json_t **contract_terms,
+  uint64_t *order_serial,
+  bool *paid,
+  struct TALER_ClaimTokenP *claim_token,
+  char **pos_key,
+  enum TALER_MerchantConfirmationAlgorithm *pos_algorithm);
+
+#endif
diff --git a/src/backenddb/pg_lookup_order.c b/src/backenddb/pg_lookup_order.c
new file mode 100644
index 00000000..6df7456c
--- /dev/null
+++ b/src/backenddb/pg_lookup_order.c
@@ -0,0 +1,96 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_order.c
+ * @brief Implementation of the lookup_order function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_lookup_order.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_order (void *cls,
+                     const char *instance_id,
+                     const char *order_id,
+                     struct TALER_ClaimTokenP *claim_token,
+                     struct TALER_MerchantPostDataHashP *h_post_data,
+                     json_t **contract_terms)
+{
+  struct PostgresClosure *pg = cls;
+  json_t *j;
+  struct TALER_ClaimTokenP ct;
+  enum GNUNET_DB_QueryStatus qs;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_string (order_id),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    TALER_PQ_result_spec_json ("contract_terms",
+                               &j),
+    GNUNET_PQ_result_spec_auto_from_type ("claim_token",
+                                          &ct),
+    GNUNET_PQ_result_spec_auto_from_type ("h_post_data",
+                                          h_post_data),
+    GNUNET_PQ_result_spec_end
+  };
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Finding contract term, order_id: '%s', instance_id: '%s'.\n",
+              order_id,
+              instance_id);
+  check_connection (pg);
+  PREPARE (pg,
+           "lookup_order",
+           "SELECT"
+           " contract_terms"
+           ",claim_token"
+           ",h_post_data"
+           ",pos_key"
+           " FROM merchant_orders"
+           " WHERE merchant_orders.merchant_serial="
+           "     (SELECT merchant_serial "
+           "        FROM merchant_instances"
+           "        WHERE merchant_id=$1)"
+           "   AND merchant_orders.order_id=$2");
+  qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                 "lookup_order",
+                                                 params,
+                                                 rs);
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+  {
+    if (NULL != contract_terms)
+      *contract_terms = j;
+    else
+      json_decref (j);
+    if (NULL != claim_token)
+      *claim_token = ct;
+  }
+  else
+  {
+    /* just to be safe: NULL it */
+    if (NULL != contract_terms)
+      *contract_terms = NULL;
+    if (NULL != claim_token)
+      *claim_token = (struct TALER_ClaimTokenP) { 0 }
+    ;
+  }
+  return qs;
+}
diff --git a/src/backenddb/pg_lookup_order.h b/src/backenddb/pg_lookup_order.h
new file mode 100644
index 00000000..7ca60869
--- /dev/null
+++ b/src/backenddb/pg_lookup_order.h
@@ -0,0 +1,49 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_order.h
+ * @brief implementation of the lookup_order function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_LOOKUP_ORDER_H
+#define PG_LOOKUP_ORDER_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Retrieve order given its @a order_id and the @a instance_id.
+ *
+ * @param cls closure
+ * @param instance_id instance to obtain order of
+ * @param order_id order id used to perform the lookup
+ * @param[out] claim_token the claim token generated for the order,
+ *             NULL to only test if the order exists
+ * @param[out] h_post_data set to the hash of the POST data that created the 
order
+ * @param[out] contract_terms where to store the retrieved contract terms,
+ *             NULL to only test if the order exists
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_order (void *cls,
+                     const char *instance_id,
+                     const char *order_id,
+                     struct TALER_ClaimTokenP *claim_token,
+                     struct TALER_MerchantPostDataHashP *h_post_data,
+                     json_t **contract_terms);
+
+#endif
diff --git a/src/backenddb/pg_lookup_order_summary.c 
b/src/backenddb/pg_lookup_order_summary.c
new file mode 100644
index 00000000..3a2a4e16
--- /dev/null
+++ b/src/backenddb/pg_lookup_order_summary.c
@@ -0,0 +1,75 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_order_summary.c
+ * @brief Implementation of the lookup_order_summary function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_lookup_order_summary.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_order_summary (void *cls,
+                             const char *instance_id,
+                             const char *order_id,
+                             struct GNUNET_TIME_Timestamp *timestamp,
+                             uint64_t *order_serial)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_string (order_id),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_uint64 ("order_serial",
+                                  order_serial),
+    GNUNET_PQ_result_spec_timestamp ("creation_time",
+                                     timestamp),
+    GNUNET_PQ_result_spec_end
+  };
+
+  check_connection (pg);
+  PREPARE (pg,
+           "lookup_order_summary",
+           "(SELECT"
+           " creation_time"
+           ",order_serial"
+           " FROM merchant_contract_terms"
+           " WHERE merchant_contract_terms.merchant_serial="
+           "     (SELECT merchant_serial "
+           "        FROM merchant_instances"
+           "        WHERE merchant_id=$1)"
+           "   AND merchant_contract_terms.order_id=$2)"
+           "UNION"
+           "(SELECT"
+           " creation_time"
+           ",order_serial"
+           " FROM merchant_orders"
+           " WHERE merchant_orders.merchant_serial="
+           "     (SELECT merchant_serial "
+           "        FROM merchant_instances"
+           "        WHERE merchant_id=$1)"
+           "   AND merchant_orders.order_id=$2)");
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "lookup_order_summary",
+                                                   params,
+                                                   rs);
+}
diff --git a/src/backenddb/pg_lookup_order_summary.h 
b/src/backenddb/pg_lookup_order_summary.h
new file mode 100644
index 00000000..5827aa66
--- /dev/null
+++ b/src/backenddb/pg_lookup_order_summary.h
@@ -0,0 +1,45 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_order_summary.h
+ * @brief implementation of the lookup_order_summary function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_LOOKUP_ORDER_SUMMARY_H
+#define PG_LOOKUP_ORDER_SUMMARY_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Retrieve order summary given its @a order_id and the @a instance_id.
+ *
+ * @param cls closure
+ * @param instance_id instance to obtain order of
+ * @param order_id order id used to perform the lookup
+ * @param[out] timestamp when was the order created
+ * @param[out] order_serial under which serial do we keep this order
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_order_summary (void *cls,
+                             const char *instance_id,
+                             const char *order_id,
+                             struct GNUNET_TIME_Timestamp *timestamp,
+                             uint64_t *order_serial);
+
+#endif
diff --git a/src/backenddb/pg_lookup_orders.c b/src/backenddb/pg_lookup_orders.c
new file mode 100644
index 00000000..437ca8ca
--- /dev/null
+++ b/src/backenddb/pg_lookup_orders.c
@@ -0,0 +1,926 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_orders.c
+ * @brief Implementation of the lookup_orders function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_lookup_orders.h"
+#include "pg_helper.h"
+
+/**
+ * Context used for TMH_PG_lookup_orders().
+ */
+struct LookupOrdersContext
+{
+  /**
+   * Function to call with the results.
+   */
+  TALER_MERCHANTDB_OrdersCallback cb;
+
+  /**
+   * Closure for @a cb.
+   */
+  void *cb_cls;
+
+  /**
+   * Did database result extraction fail?
+   */
+  bool extract_failed;
+};
+
+
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results about orders.
+ *
+ * @param[in,out] cls of type `struct LookupOrdersContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+lookup_orders_cb (void *cls,
+                  PGresult *result,
+                  unsigned int num_results)
+{
+  struct LookupOrdersContext *plc = cls;
+
+  for (unsigned int i = 0; i < num_results; i++)
+  {
+    char *order_id;
+    uint64_t order_serial;
+    struct GNUNET_TIME_Timestamp ts;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      GNUNET_PQ_result_spec_string ("order_id",
+                                    &order_id),
+      GNUNET_PQ_result_spec_uint64 ("order_serial",
+                                    &order_serial),
+      GNUNET_PQ_result_spec_timestamp ("creation_time",
+                                       &ts),
+      GNUNET_PQ_result_spec_end
+    };
+
+    if (GNUNET_OK !=
+        GNUNET_PQ_extract_result (result,
+                                  rs,
+                                  i))
+    {
+      GNUNET_break (0);
+      plc->extract_failed = true;
+      return;
+    }
+    plc->cb (plc->cb_cls,
+             order_id,
+             order_serial,
+             ts);
+    GNUNET_PQ_cleanup_result (rs);
+  }
+}
+
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_orders (void *cls,
+                      const char *instance_id,
+                      const struct TALER_MERCHANTDB_OrderFilter *of,
+                      TALER_MERCHANTDB_OrdersCallback cb,
+                      void *cb_cls)
+{
+  struct PostgresClosure *pg = cls;
+  struct LookupOrdersContext plc = {
+    .cb = cb,
+    .cb_cls = cb_cls
+  };
+  uint64_t limit = (of->delta > 0) ? of->delta : -of->delta;
+  uint8_t paid;
+  uint8_t refunded;
+  uint8_t wired;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_uint64 (&limit),
+    GNUNET_PQ_query_param_uint64 (&of->start_row),
+    GNUNET_PQ_query_param_timestamp (&of->date),
+    GNUNET_PQ_query_param_auto_from_type (&paid),
+    GNUNET_PQ_query_param_auto_from_type (&refunded),
+    GNUNET_PQ_query_param_auto_from_type (&wired),
+    GNUNET_PQ_query_param_end
+  };
+  enum GNUNET_DB_QueryStatus qs;
+  char stmt[128];
+
+  paid = (TALER_EXCHANGE_YNA_YES == of->paid);
+  refunded = (TALER_EXCHANGE_YNA_YES == of->refunded);
+  wired = (TALER_EXCHANGE_YNA_YES == of->wired);
+  /* painfully many cases..., note that "_xxx" being present in 'stmt' merely
+     means that we filter by that variable, the value we filter for is
+     computed above */
+  GNUNET_snprintf (stmt,
+                   sizeof (stmt),
+                   "lookup_orders_%s%s%s%s",
+                   (of->delta > 0) ? "inc" : "dec",
+                   (TALER_EXCHANGE_YNA_ALL == of->paid) ? "" : "_paid",
+                   (TALER_EXCHANGE_YNA_ALL == of->refunded) ? "" :
+                   "_refunded",
+                   (TALER_EXCHANGE_YNA_ALL == of->wired) ? "" : "_wired");
+  PREPARE (pg,
+          "lookup_orders_inc",
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+          ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+          ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+          " FROM merchant_orders"
+          " WHERE merchant_orders.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial > $3"
+          "   AND"
+          "    creation_time > $4"
+          " ORDER BY order_serial ASC"
+          " LIMIT $2)"
+          "UNION " /* union ensures elements are distinct! */
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+          ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+          ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+          " FROM merchant_contract_terms"
+          " WHERE merchant_contract_terms.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial > $3"
+          "   AND"
+          "    creation_time > $4"
+          " ORDER BY order_serial ASC"
+          " LIMIT $2)"
+          " ORDER BY order_serial ASC"
+          " LIMIT $2");
+  PREPARE (pg,
+          "lookup_orders_inc_paid",
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+          ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+          " FROM merchant_orders"
+          " WHERE merchant_orders.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial > $3"
+          "   AND"
+          "    creation_time > $4"
+          "   AND"
+          "    NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
+          "   AND"
+          "    order_serial NOT IN"
+          "     (SELECT order_serial"
+          "      FROM merchant_contract_terms)" /* only select unclaimed 
orders */
+          " ORDER BY order_serial ASC"
+          " LIMIT $2)"
+          "UNION " /* union ensures elements are distinct! */
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+          ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+          " FROM merchant_contract_terms"
+          " WHERE merchant_contract_terms.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial > $3"
+          "   AND"
+          "    creation_time > $4"
+          "   AND"
+          "    BOOL($5) = paid"
+          " ORDER BY order_serial ASC"
+          " LIMIT $2)"
+          " ORDER BY order_serial ASC"
+          " LIMIT $2");
+  PREPARE (pg,
+          "lookup_orders_inc_refunded",
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+          ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+          " FROM merchant_orders"
+          " WHERE merchant_orders.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial > $3"
+          "   AND"
+          "    creation_time > $4"
+          "   AND"
+          "    NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
+          "   AND"
+          "    order_serial NOT IN"
+          "     (SELECT order_serial"
+          "      FROM merchant_contract_terms)" /* only select unclaimed 
orders */
+          " ORDER BY order_serial ASC"
+          " LIMIT $2)"
+          "UNION " /* union ensures elements are distinct! */
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+          ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+          " FROM merchant_contract_terms"
+          " WHERE merchant_contract_terms.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial > $3"
+          "   AND"
+          "    creation_time > $4"
+          "   AND"
+          "    CAST($6 as BOOL) = (order_serial IN"
+          "     (SELECT order_serial "
+          "      FROM merchant_refunds))"
+          " ORDER BY order_serial ASC"
+          " LIMIT $2)"
+          " ORDER BY order_serial ASC"
+          " LIMIT $2");
+  PREPARE (pg,
+          "lookup_orders_inc_wired",
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+          ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+          " FROM merchant_orders"
+          " WHERE merchant_orders.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial > $3"
+          "   AND"
+          "    creation_time > $4"
+          "   AND"
+          "    NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
+          "   AND"
+          "    order_serial NOT IN"
+          "     (SELECT order_serial"
+          "      FROM merchant_contract_terms)" /* only select unclaimed 
orders */
+          " ORDER BY order_serial ASC"
+          " LIMIT $2)"
+          "UNION " /* union ensures elements are distinct! */
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+          ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+          " FROM merchant_contract_terms"
+          " WHERE merchant_contract_terms.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial > $3"
+          "   AND"
+          "    creation_time > $4"
+          "   AND"
+          "    BOOL($7) = wired"
+          " ORDER BY order_serial ASC"
+          " LIMIT $2)"
+          " ORDER BY order_serial ASC"
+          " LIMIT $2");
+  PREPARE (pg,
+          "lookup_orders_inc_paid_refunded",
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+          " FROM merchant_orders"
+          " WHERE merchant_orders.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial > $3"
+          "   AND"
+          "    creation_time > $4"
+          "   AND"
+          "    NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
+          "   AND"
+          "    NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
+          "   AND"
+          "    order_serial NOT IN"
+          "     (SELECT order_serial"
+          "      FROM merchant_contract_terms)" /* only select unclaimed 
orders */
+          " ORDER BY order_serial ASC"
+          " LIMIT $2)"
+          "UNION " /* union ensures elements are distinct! */
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+          " FROM merchant_contract_terms"
+          " WHERE merchant_contract_terms.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial > $3"
+          "   AND"
+          "    creation_time > $4"
+          "   AND"
+          "    BOOL($5) = paid"
+          "   AND"
+          "    BOOL($6) = (order_serial IN"
+          "     (SELECT order_serial "
+          "      FROM merchant_refunds))"
+          " ORDER BY order_serial ASC"
+          " LIMIT $2)"
+          " ORDER BY order_serial ASC"
+          " LIMIT $2");
+  PREPARE (pg,
+          "lookup_orders_inc_paid_wired",
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+          " FROM merchant_orders"
+          " WHERE merchant_orders.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial > $3"
+          "   AND"
+          "    creation_time > $4"
+          "   AND"
+          "    NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
+          "   AND"
+          "    NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
+          "   AND"
+          "    order_serial NOT IN"
+          "     (SELECT order_serial"
+          "      FROM merchant_contract_terms)" /* only select unclaimed 
orders */
+          " ORDER BY order_serial ASC"
+          " LIMIT $2)"
+          "UNION " /* union ensures elements are distinct! */
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+          " FROM merchant_contract_terms"
+          " WHERE merchant_contract_terms.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial > $3"
+          "   AND"
+          "    creation_time > $4"
+          "   AND"
+          "    BOOL($5) = paid"
+          "   AND"
+          "    BOOL($7) = wired"
+          " ORDER BY order_serial ASC"
+          " LIMIT $2)"
+          " ORDER BY order_serial ASC"
+          " LIMIT $2");
+  PREPARE (pg,
+          "lookup_orders_inc_refunded_wired",
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+          " FROM merchant_orders"
+          " WHERE merchant_orders.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial > $3"
+          "   AND"
+          "    creation_time > $4"
+          "   AND"
+          "    NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
+          "   AND"
+          "    NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
+          "   AND"
+          "    order_serial NOT IN"
+          "     (SELECT order_serial"
+          "      FROM merchant_contract_terms)" /* only select unclaimed 
orders */
+          " ORDER BY order_serial ASC"
+          " LIMIT $2)"
+          "UNION " /* union ensures elements are distinct! */
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+          " FROM merchant_contract_terms"
+          " WHERE merchant_contract_terms.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial > $3"
+          "   AND"
+          "    creation_time > $4"
+          "   AND"
+          "    BOOL($6) = (order_serial IN"
+          "     (SELECT order_serial "
+          "      FROM merchant_refunds))"
+          "   AND"
+          "    BOOL($7) = wired"
+          " ORDER BY order_serial ASC"
+          " LIMIT $2)"
+          " ORDER BY order_serial ASC"
+          " LIMIT $2");
+  PREPARE (pg,
+          "lookup_orders_inc_paid_refunded_wired",
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          " FROM merchant_orders"
+          " WHERE merchant_orders.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial > $3"
+          "   AND"
+          "    creation_time > $4"
+          "   AND"
+          "    NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
+          "   AND"
+          "    NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
+          "   AND"
+          "    NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
+          "   AND"
+          "    order_serial NOT IN"
+          "     (SELECT order_serial"
+          "      FROM merchant_contract_terms)" /* only select unclaimed 
orders */
+          " ORDER BY order_serial ASC"
+          " LIMIT $2)"
+          "UNION " /* union ensures elements are distinct! */
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          " FROM merchant_contract_terms"
+          " WHERE merchant_contract_terms.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial > $3"
+          "   AND"
+          "    creation_time > $4"
+          "   AND"
+          "    BOOL($5) = paid"
+          "   AND"
+          "    BOOL($6) = (order_serial IN"
+          "     (SELECT order_serial "
+          "      FROM merchant_refunds))"
+          "   AND"
+          "    BOOL($7) = wired"
+          " ORDER BY order_serial ASC"
+          " LIMIT $2)"
+          " ORDER BY order_serial ASC"
+          " LIMIT $2");
+  PREPARE (pg,
+          "lookup_orders_dec",
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+          ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+          ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+          " FROM merchant_orders"
+          " WHERE merchant_orders.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial < $3"
+          "   AND"
+          "    creation_time < $4"
+          " ORDER BY order_serial DESC"
+          " LIMIT $2)"
+          "UNION " /* union ensures elements are distinct! */
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+          ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+          ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+          " FROM merchant_contract_terms"
+          " WHERE merchant_contract_terms.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial < $3"
+          "   AND"
+          "    creation_time < $4"
+          " ORDER BY order_serial DESC"
+          " LIMIT $2)"
+          " ORDER BY order_serial DESC"
+          " LIMIT $2");
+  PREPARE (pg,
+          "lookup_orders_dec_paid",
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+          ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+          " FROM merchant_orders"
+          " WHERE merchant_orders.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial < $3"
+          "   AND"
+          "    creation_time < $4"
+          "   AND"
+          "    NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
+          "   AND"
+          "    order_serial NOT IN"
+          "     (SELECT order_serial"
+          "      FROM merchant_contract_terms)" /* only select unclaimed 
orders */
+          " ORDER BY order_serial DESC"
+          " LIMIT $2)"
+          "UNION " /* union ensures elements are distinct! */
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+          ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+          " FROM merchant_contract_terms"
+          " WHERE merchant_contract_terms.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial < $3"
+          "   AND"
+          "    creation_time < $4"
+          "   AND"
+          "    BOOL($5) = paid"
+          " ORDER BY order_serial DESC"
+          " LIMIT $2)"
+          " ORDER BY order_serial DESC"
+          " LIMIT $2");
+  PREPARE (pg,
+          "lookup_orders_dec_refunded",
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+          ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+          " FROM merchant_orders"
+          " WHERE merchant_orders.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial < $3"
+          "   AND"
+          "    creation_time < $4"
+          "   AND"
+          "    NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
+          "   AND"
+          "    order_serial NOT IN"
+          "     (SELECT order_serial"
+          "      FROM merchant_contract_terms)" /* only select unclaimed 
orders */
+          " ORDER BY order_serial DESC"
+          " LIMIT $2)"
+          "UNION " /* union ensures elements are distinct! */
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+          ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+          " FROM merchant_contract_terms"
+          " WHERE merchant_contract_terms.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial < $3"
+          "   AND"
+          "    creation_time < $4"
+          "   AND"
+          "    BOOL($6) = (order_serial IN"
+          "     (SELECT order_serial "
+          "      FROM merchant_refunds))"
+          " ORDER BY order_serial DESC"
+          " LIMIT $2)"
+          " ORDER BY order_serial DESC"
+          " LIMIT $2");
+  PREPARE (pg,
+          "lookup_orders_dec_wired",
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+          ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+          " FROM merchant_orders"
+          " WHERE merchant_orders.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial < $3"
+          "   AND"
+          "    creation_time < $4"
+          "   AND"
+          "    NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
+          "   AND"
+          "    order_serial NOT IN"
+          "     (SELECT order_serial"
+          "      FROM merchant_contract_terms)" /* only select unclaimed 
orders */
+          " ORDER BY order_serial DESC"
+          " LIMIT $2)"
+          "UNION " /* union ensures elements are distinct! */
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+          ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+          " FROM merchant_contract_terms"
+          " WHERE merchant_contract_terms.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial < $3"
+          "   AND"
+          "    creation_time < $4"
+          "   AND"
+          "    BOOL($7) = wired"
+          " ORDER BY order_serial DESC"
+          " LIMIT $2)"
+          " ORDER BY order_serial DESC"
+          " LIMIT $2");
+  PREPARE (pg,
+          "lookup_orders_dec_paid_refunded",
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+          " FROM merchant_orders"
+          " WHERE merchant_orders.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial < $3"
+          "   AND"
+          "    creation_time < $4"
+          "   AND"
+          "    NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
+          "   AND"
+          "    NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
+          "   AND"
+          "    order_serial NOT IN"
+          "     (SELECT order_serial"
+          "      FROM merchant_contract_terms)" /* only select unclaimed 
orders */
+          " ORDER BY order_serial DESC"
+          " LIMIT $2)"
+          "UNION " /* union ensures elements are distinct! */
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */
+          " FROM merchant_contract_terms"
+          " WHERE merchant_contract_terms.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial < $3"
+          "   AND"
+          "    creation_time < $4"
+          "   AND"
+          "    BOOL($5) = paid"
+          "   AND"
+          "    BOOL($6) = (order_serial IN"
+          "     (SELECT order_serial "
+          "      FROM merchant_refunds))"
+          " ORDER BY order_serial DESC"
+          " LIMIT $2)"
+          " ORDER BY order_serial DESC"
+          " LIMIT $2");
+  PREPARE (pg,
+          "lookup_orders_dec_paid_wired",
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+          " FROM merchant_orders"
+          " WHERE merchant_orders.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial < $3"
+          "   AND"
+          "    creation_time < $4"
+          "   AND"
+          "    NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
+          "   AND"
+          "    NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
+          "   AND"
+          "    order_serial NOT IN"
+          "     (SELECT order_serial"
+          "      FROM merchant_contract_terms)" /* only select unclaimed 
orders */
+          " ORDER BY order_serial DESC"
+          " LIMIT $2)"
+          "UNION " /* union ensures elements are distinct! */
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */
+          " FROM merchant_contract_terms"
+          " WHERE merchant_contract_terms.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial < $3"
+          "   AND"
+          "    creation_time < $4"
+          "   AND"
+          "    BOOL($5) = paid"
+          "   AND"
+          "    BOOL($7) = wired"
+          " ORDER BY order_serial DESC"
+          " LIMIT $2)"
+          " ORDER BY order_serial DESC"
+          " LIMIT $2");
+  PREPARE (pg,
+          "lookup_orders_dec_refunded_wired",
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+          " FROM merchant_orders"
+          " WHERE merchant_orders.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial < $3"
+          "   AND"
+          "    creation_time < $4"
+          "   AND"
+          "    NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
+          "   AND"
+          "    NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
+          "   AND"
+          "    order_serial NOT IN"
+          "     (SELECT order_serial"
+          "      FROM merchant_contract_terms)" /* only select unclaimed 
orders */
+          " ORDER BY order_serial DESC"
+          " LIMIT $2)"
+          "UNION " /* union ensures elements are distinct! */
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */
+          " FROM merchant_contract_terms"
+          " WHERE merchant_contract_terms.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial < $3"
+          "   AND"
+          "    creation_time < $4"
+          "   AND"
+          "    BOOL($6) = (order_serial IN"
+          "     (SELECT order_serial "
+          "      FROM merchant_refunds))"
+          "   AND"
+          "    BOOL($7) = wired"
+          " ORDER BY order_serial DESC"
+          " LIMIT $2)"
+          " ORDER BY order_serial DESC"
+          " LIMIT $2");
+  PREPARE (pg,
+          "lookup_orders_dec_paid_refunded_wired",
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          " FROM merchant_orders"
+          " WHERE merchant_orders.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial < $3"
+          "   AND"
+          "    creation_time < $4"
+          "   AND"
+          "    NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */
+          "   AND"
+          "    NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */
+          "   AND"
+          "    NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */
+          "   AND"
+          "    order_serial NOT IN"
+          "     (SELECT order_serial"
+          "      FROM merchant_contract_terms)" /* only select unclaimed 
orders */
+          " ORDER BY order_serial DESC"
+          " LIMIT $2)"
+          "UNION " /* union ensures elements are distinct! */
+          "(SELECT"
+          " order_id"
+          ",order_serial"
+          ",creation_time"
+          " FROM merchant_contract_terms"
+          " WHERE merchant_contract_terms.merchant_serial="
+          "     (SELECT merchant_serial "
+          "        FROM merchant_instances"
+          "        WHERE merchant_id=$1)"
+          "   AND"
+          "    order_serial < $3"
+          "   AND"
+          "    creation_time < $4"
+          "   AND"
+          "    BOOL($5) = paid"
+          "   AND"
+          "    BOOL($6) = (order_serial IN"
+          "     (SELECT order_serial "
+
+          "      FROM merchant_refunds))"
+          "   AND"
+          "    BOOL($7) = wired"
+          " ORDER BY order_serial DESC"
+          " LIMIT $2)"
+          " ORDER BY order_serial DESC"
+          " LIMIT $2");
+  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+                                             stmt,
+                                             params,
+                                             &lookup_orders_cb,
+                                             &plc);
+  if (plc.extract_failed)
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  return qs;
+}
diff --git a/src/backenddb/pg_lookup_orders.h b/src/backenddb/pg_lookup_orders.h
new file mode 100644
index 00000000..4b00f18b
--- /dev/null
+++ b/src/backenddb/pg_lookup_orders.h
@@ -0,0 +1,45 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_lookup_orders.h
+ * @brief implementation of the lookup_orders function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_LOOKUP_ORDERS_H
+#define PG_LOOKUP_ORDERS_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Retrieve orders given the @a instance_id.
+ *
+ * @param cls closure
+ * @param instance_id instance to obtain order of
+ * @param of filter to apply when looking up orders
+ * @param cb callback to pass all the orders that are found
+ * @param cb_cls closure for @a cb
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_lookup_orders (void *cls,
+                      const char *instance_id,
+                      const struct TALER_MERCHANTDB_OrderFilter *of,
+                      TALER_MERCHANTDB_OrdersCallback cb,
+                      void *cb_cls);
+
+#endif
diff --git a/src/backenddb/pg_unlock_inventory.c 
b/src/backenddb/pg_unlock_inventory.c
new file mode 100644
index 00000000..5f4d8a7b
--- /dev/null
+++ b/src/backenddb/pg_unlock_inventory.c
@@ -0,0 +1,47 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_unlock_inventory.c
+ * @brief Implementation of the unlock_inventory function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_unlock_inventory.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_unlock_inventory (void *cls,
+                         const struct GNUNET_Uuid *uuid)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (uuid),
+    GNUNET_PQ_query_param_end
+  };
+
+  check_connection (pg);
+  PREPARE (pg,
+           "unlock_inventory",
+           "DELETE"
+           " FROM merchant_inventory_locks"
+           " WHERE lock_uuid=$1");
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "unlock_inventory",
+                                             params);
+}
diff --git a/src/backenddb/pg_unlock_inventory.h 
b/src/backenddb/pg_unlock_inventory.h
new file mode 100644
index 00000000..cec734e8
--- /dev/null
+++ b/src/backenddb/pg_unlock_inventory.h
@@ -0,0 +1,42 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_unlock_inventory.h
+ * @brief implementation of the unlock_inventory function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_UNLOCK_INVENTORY_H
+#define PG_UNLOCK_INVENTORY_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Release an inventory lock by UUID. Releases ALL stocks locked under
+ * the given UUID.
+ *
+ * @param cls closure
+ * @param uuid the UUID to release locks for
+ * @return transaction status,
+ *   #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS means there are no locks under @a 
uuid
+ *   #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT indicates success
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_unlock_inventory (void *cls,
+                         const struct GNUNET_Uuid *uuid);
+
+#endif
diff --git a/src/backenddb/pg_update_contract_terms.c 
b/src/backenddb/pg_update_contract_terms.c
new file mode 100644
index 00000000..51e449a0
--- /dev/null
+++ b/src/backenddb/pg_update_contract_terms.c
@@ -0,0 +1,103 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_update_contract_terms.c
+ * @brief Implementation of the update_contract_terms function for Postgres
+ * @author Iván Ávalos
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_update_contract_terms.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_update_contract_terms (void *cls,
+                              const char *instance_id,
+                              const char *order_id,
+                              json_t *contract_terms)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_TIME_Timestamp pay_deadline;
+  struct GNUNET_TIME_Timestamp refund_deadline;
+  const char *fulfillment_url = NULL;
+  struct TALER_PrivateContractHashP h_contract_terms;
+
+  if (GNUNET_OK !=
+      TALER_JSON_contract_hash (contract_terms,
+                                &h_contract_terms))
+  {
+    GNUNET_break (0);
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  }
+
+  {
+    struct GNUNET_JSON_Specification spec[] = {
+      GNUNET_JSON_spec_timestamp ("pay_deadline",
+                                  &pay_deadline),
+      GNUNET_JSON_spec_timestamp ("refund_deadline",
+                                  &refund_deadline),
+      GNUNET_JSON_spec_mark_optional (
+        GNUNET_JSON_spec_string ("fulfillment_url",
+                                 &fulfillment_url),
+        NULL),
+      GNUNET_JSON_spec_end ()
+    };
+    enum GNUNET_GenericReturnValue res;
+
+    res = TALER_MHD_parse_json_data (NULL,
+                                     contract_terms,
+                                     spec);
+    if (GNUNET_OK != res)
+    {
+      GNUNET_break (0);
+      return GNUNET_DB_STATUS_HARD_ERROR;
+    }
+  }
+
+  check_connection (pg);
+  {
+    struct GNUNET_PQ_QueryParam params[] = {
+      GNUNET_PQ_query_param_string (instance_id),
+      GNUNET_PQ_query_param_string (order_id),
+      TALER_PQ_query_param_json (contract_terms),
+      GNUNET_PQ_query_param_auto_from_type (&h_contract_terms),
+      GNUNET_PQ_query_param_timestamp (&pay_deadline),
+      GNUNET_PQ_query_param_timestamp (&refund_deadline),
+      (NULL == fulfillment_url)
+      ? GNUNET_PQ_query_param_null ()
+      : GNUNET_PQ_query_param_string (fulfillment_url),
+      GNUNET_PQ_query_param_end
+    };
+    PREPARE (pg,
+             "update_contract_terms",
+             "UPDATE merchant_contract_terms SET"
+             " contract_terms=$3"
+             ",h_contract_terms=$4"
+             ",pay_deadline=$5"
+             ",refund_deadline=$6"
+             ",fulfillment_url=$7"
+             " WHERE order_id=$2"
+             "   AND merchant_serial="
+             "     (SELECT merchant_serial"
+             "        FROM merchant_instances"
+             "        WHERE merchant_id=$1)");
+    return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                               "update_contract_terms",
+                                               params);
+  }
+}
diff --git a/src/backenddb/pg_update_contract_terms.h 
b/src/backenddb/pg_update_contract_terms.h
new file mode 100644
index 00000000..fe428dc0
--- /dev/null
+++ b/src/backenddb/pg_update_contract_terms.h
@@ -0,0 +1,49 @@
+/*
+   This file is part of TALER
+   Copyright (C) 2022 Taler Systems SA
+
+   TALER is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_update_contract_terms.h
+ * @brief implementation of the update_contract_terms function for Postgres
+ * @author Iván Ávalos
+ */
+#ifndef PG_UPDATE_CONTRACT_TERMS_H
+#define PG_UPDATE_CONTRACT_TERMS_H
+
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler_merchantdb_plugin.h"
+
+/**
+ * Update the contract terms stored for @a order_id. Note that some attributes 
are
+ * expected to be calculated inside of the function, like the hash of the
+ * contract terms (to be hashed), the creation_time and pay_deadline (to be
+ * obtained from the merchant_orders table). The "session_id" should be
+ * initially set to the empty string.  The "fulfillment_url" and 
"refund_deadline"
+ * must be extracted from @a contract_terms.
+ *
+ * @param cls closure
+ * @param instance_id instance's identifier
+ * @param order_id order_id used to store
+ * @param contract_terms contract to store
+ * @return transaction status, #GNUNET_DB_STATUS_HARD_ERROR if @a 
contract_terms
+ *          is malformed
+ */
+enum GNUNET_DB_QueryStatus
+TMH_PG_update_contract_terms (void *cls,
+                              const char *instance_id,
+                              const char *order_id,
+                              json_t *contract_terms);
+
+#endif
diff --git a/src/backenddb/plugin_merchantdb_postgres.c 
b/src/backenddb/plugin_merchantdb_postgres.c
index 0e5f921f..757a303c 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -59,6 +59,19 @@
 #include "pg_insert_product.h"
 #include "pg_update_product.h"
 #include "pg_lock_product.h"
+#include "pg_expire_locks.h"
+#include "pg_delete_order.h"
+#include "pg_lookup_order.h"
+#include "pg_lookup_order_summary.h"
+#include "pg_lookup_orders.h"
+#include "pg_insert_order.h"
+#include "pg_unlock_inventory.h"
+#include "pg_insert_order_lock.h"
+#include "pg_lookup_contract_terms2.h"
+#include "pg_lookup_contract_terms.h"
+#include "pg_insert_contract_terms.h"
+#include "pg_update_contract_terms.h"
+#include "pg_delete_contract_terms.h"
 #include "pg_set_transfer_status_to_confirmed.h"
 
 
@@ -337,262 +350,69 @@ postgres_commit (void *cls)
 
 
 /**
- * Release all expired product locks, including
- * those from expired offers -- across all
- * instances.
- *
- * @param cls closure
- */
-static void
-postgres_expire_locks (void *cls)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_absolute_time (&now),
-    GNUNET_PQ_query_param_end
-  };
-  enum GNUNET_DB_QueryStatus qs1;
-  enum GNUNET_DB_QueryStatus qs2;
-  enum GNUNET_DB_QueryStatus qs3;
-
-  check_connection (pg);
-  qs1 = GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                            "unlock_products",
-                                            params);
-  if (qs1 < 0)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  qs2 = GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                            "unlock_orders",
-                                            params);
-  if (qs2 < 0)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  qs3 = GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                            "unlock_contracts",
-                                            params);
-  if (qs3 < 0)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Released %d+%d+%d locks\n",
-              qs1,
-              qs2,
-              qs3);
-}
-
-
-/**
- * Delete information about an order.  Note that the transaction must
- * enforce that the order is not awaiting payment anymore.
- *
- * @param cls closure
- * @param instance_id instance to delete order of
- * @param order_id order to delete
- * @param force delete claimed but unpaid orders as well
- * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
- *           if pending payment prevents deletion OR order unknown
- */
-static enum GNUNET_DB_QueryStatus
-postgres_delete_order (void *cls,
-                       const char *instance_id,
-                       const char *order_id,
-                       bool force)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_string (order_id),
-    GNUNET_PQ_query_param_absolute_time (&now),
-    GNUNET_PQ_query_param_bool (force),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_QueryParam params2[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_string (order_id),
-    GNUNET_PQ_query_param_end
-  };
-  enum GNUNET_DB_QueryStatus qs;
-
-  check_connection (pg);
-  qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                           "delete_order",
-                                           params);
-  if ( (qs <= 0) || (! force))
-    return qs;
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "delete_contract",
-                                             params2);
-}
-
-
-/**
- * Retrieve order given its @a order_id and the @a instance_id.
- *
- * @param cls closure
- * @param instance_id instance to obtain order of
- * @param order_id order id used to perform the lookup
- * @param[out] claim_token the claim token generated for the order,
- *             NULL to only test if the order exists
- * @param[out] h_post_data set to the hash of the POST data that created the 
order
- * @param[out] contract_terms where to store the retrieved contract terms,
- *             NULL to only test if the order exists
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_order (void *cls,
-                       const char *instance_id,
-                       const char *order_id,
-                       struct TALER_ClaimTokenP *claim_token,
-                       struct TALER_MerchantPostDataHashP *h_post_data,
-                       json_t **contract_terms)
-{
-  struct PostgresClosure *pg = cls;
-  json_t *j;
-  struct TALER_ClaimTokenP ct;
-  enum GNUNET_DB_QueryStatus qs;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_string (order_id),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    TALER_PQ_result_spec_json ("contract_terms",
-                               &j),
-    GNUNET_PQ_result_spec_auto_from_type ("claim_token",
-                                          &ct),
-    GNUNET_PQ_result_spec_auto_from_type ("h_post_data",
-                                          h_post_data),
-    GNUNET_PQ_result_spec_end
-  };
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Finding contract term, order_id: '%s', instance_id: '%s'.\n",
-              order_id,
-              instance_id);
-  check_connection (pg);
-  qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                 "lookup_order",
-                                                 params,
-                                                 rs);
-  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
-  {
-    if (NULL != contract_terms)
-      *contract_terms = j;
-    else
-      json_decref (j);
-    if (NULL != claim_token)
-      *claim_token = ct;
-  }
-  else
-  {
-    /* just to be safe: NULL it */
-    if (NULL != contract_terms)
-      *contract_terms = NULL;
-    if (NULL != claim_token)
-      *claim_token = (struct TALER_ClaimTokenP) { 0 }
-    ;
-  }
-  return qs;
-}
-
-
-/**
- * Retrieve order summary given its @a order_id and the @a instance_id.
- *
- * @param cls closure
- * @param instance_id instance to obtain order of
- * @param order_id order id used to perform the lookup
- * @param[out] timestamp when was the order created
- * @param[out] order_serial under which serial do we keep this order
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_order_summary (void *cls,
-                               const char *instance_id,
-                               const char *order_id,
-                               struct GNUNET_TIME_Timestamp *timestamp,
-                               uint64_t *order_serial)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_string (order_id),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_uint64 ("order_serial",
-                                  order_serial),
-    GNUNET_PQ_result_spec_timestamp ("creation_time",
-                                     timestamp),
-    GNUNET_PQ_result_spec_end
-  };
-
-  check_connection (pg);
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   "lookup_order_summary",
-                                                   params,
-                                                   rs);
-}
-
-
-/**
- * Context used for postgres_lookup_orders().
+ * Closure for #lookup_deposits_cb().
  */
-struct LookupOrdersContext
+struct LookupDepositsContext
 {
   /**
-   * Function to call with the results.
+   * Function to call with results.
    */
-  TALER_MERCHANTDB_OrdersCallback cb;
+  TALER_MERCHANTDB_DepositsCallback cb;
 
   /**
-   * Closure for @a cb.
+   * Closure for @e cls.
    */
   void *cb_cls;
 
   /**
-   * Did database result extraction fail?
+   * Plugin context.
    */
-  bool extract_failed;
+  struct PostgresClosure *pg;
+
+  /**
+   * 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 about orders.
+ * that has returned @a num_results results.
  *
- * @param[in,out] cls of type `struct LookupOrdersContext *`
+ * @param[in,out] cls of type `struct LookupDepositsContext *`
  * @param result the postgres result
  * @param num_results the number of results in @a result
  */
 static void
-lookup_orders_cb (void *cls,
-                  PGresult *result,
-                  unsigned int num_results)
+lookup_deposits_cb (void *cls,
+                    PGresult *result,
+                    unsigned int num_results)
 {
-  struct LookupOrdersContext *plc = cls;
+  struct LookupDepositsContext *ldc = cls;
+  struct PostgresClosure *pg = ldc->pg;
 
-  for (unsigned int i = 0; i < num_results; i++)
+  for (unsigned int i = 0; i<num_results; i++)
   {
-    char *order_id;
-    uint64_t order_serial;
-    struct GNUNET_TIME_Timestamp ts;
+    struct TALER_CoinSpendPublicKeyP coin_pub;
+    struct TALER_Amount amount_with_fee;
+    struct TALER_Amount deposit_fee;
+    struct TALER_Amount refund_fee;
+    struct TALER_Amount wire_fee;
+    char *exchange_url;
     struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_string ("order_id",
-                                    &order_id),
-      GNUNET_PQ_result_spec_uint64 ("order_serial",
-                                    &order_serial),
-      GNUNET_PQ_result_spec_timestamp ("creation_time",
-                                       &ts),
+      GNUNET_PQ_result_spec_string ("exchange_url",
+                                    &exchange_url),
+      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_AMOUNT ("wire_fee",
+                                   &wire_fee),
       GNUNET_PQ_result_spec_end
     };
 
@@ -602,553 +422,583 @@ lookup_orders_cb (void *cls,
                                   i))
     {
       GNUNET_break (0);
-      plc->extract_failed = true;
+      ldc->qs = GNUNET_DB_STATUS_HARD_ERROR;
       return;
     }
-    plc->cb (plc->cb_cls,
-             order_id,
-             order_serial,
-             ts);
+    ldc->cb (ldc->cb_cls,
+             exchange_url,
+             &coin_pub,
+             &amount_with_fee,
+             &deposit_fee,
+             &refund_fee,
+             &wire_fee);
     GNUNET_PQ_cleanup_result (rs);
   }
+  ldc->qs = num_results;
 }
 
 
 /**
- * Retrieve orders given the @a instance_id.
+ * Lookup information about coins that were successfully deposited for a
+ * given contract.
  *
  * @param cls closure
- * @param instance_id instance to obtain order of
- * @param of filter to apply when looking up orders
- * @param cb callback to pass all the orders that are found
+ * @param instance_id instance to lookup deposits for
+ * @param h_contract_terms proposal data's hashcode
+ * @param cb function to call with payment data
  * @param cb_cls closure for @a cb
  * @return transaction status
  */
 static enum GNUNET_DB_QueryStatus
-postgres_lookup_orders (void *cls,
-                        const char *instance_id,
-                        const struct TALER_MERCHANTDB_OrderFilter *of,
-                        TALER_MERCHANTDB_OrdersCallback cb,
-                        void *cb_cls)
+postgres_lookup_deposits (
+  void *cls,
+  const char *instance_id,
+  const struct TALER_PrivateContractHashP *h_contract_terms,
+  TALER_MERCHANTDB_DepositsCallback cb,
+  void *cb_cls)
 {
   struct PostgresClosure *pg = cls;
-  struct LookupOrdersContext plc = {
-    .cb = cb,
-    .cb_cls = cb_cls
-  };
-  uint64_t limit = (of->delta > 0) ? of->delta : -of->delta;
-  uint8_t paid;
-  uint8_t refunded;
-  uint8_t wired;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_uint64 (&limit),
-    GNUNET_PQ_query_param_uint64 (&of->start_row),
-    GNUNET_PQ_query_param_timestamp (&of->date),
-    GNUNET_PQ_query_param_auto_from_type (&paid),
-    GNUNET_PQ_query_param_auto_from_type (&refunded),
-    GNUNET_PQ_query_param_auto_from_type (&wired),
+    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
     GNUNET_PQ_query_param_end
   };
+  struct LookupDepositsContext ldc = {
+    .cb = cb,
+    .cb_cls = cb_cls,
+    .pg = pg
+  };
   enum GNUNET_DB_QueryStatus qs;
-  char stmt[128];
 
-  paid = (TALER_EXCHANGE_YNA_YES == of->paid);
-  refunded = (TALER_EXCHANGE_YNA_YES == of->refunded);
-  wired = (TALER_EXCHANGE_YNA_YES == of->wired);
-  /* painfully many cases..., note that "_xxx" being present in 'stmt' merely
-     means that we filter by that variable, the value we filter for is
-     computed above */
-  GNUNET_snprintf (stmt,
-                   sizeof (stmt),
-                   "lookup_orders_%s%s%s%s",
-                   (of->delta > 0) ? "inc" : "dec",
-                   (TALER_EXCHANGE_YNA_ALL == of->paid) ? "" : "_paid",
-                   (TALER_EXCHANGE_YNA_ALL == of->refunded) ? "" :
-                   "_refunded",
-                   (TALER_EXCHANGE_YNA_ALL == of->wired) ? "" : "_wired");
+  /* no preflight check here, run in its own transaction by the caller! */
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Finding deposits for h_contract_terms '%s'\n",
+              GNUNET_h2s (&h_contract_terms->hash));
+  check_connection (pg);
   qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
-                                             stmt,
+                                             "lookup_deposits",
                                              params,
-                                             &lookup_orders_cb,
-                                             &plc);
-  if (plc.extract_failed)
-    return GNUNET_DB_STATUS_HARD_ERROR;
-  return qs;
+                                             &lookup_deposits_cb,
+                                             &ldc);
+  if (qs <= 0)
+    return qs;
+  return ldc.qs;
 }
 
 
 /**
- * Insert order into the DB.
+ * Insert an exchange signing key into our database.
  *
  * @param cls closure
- * @param instance_id identifies the instance responsible for the order
- * @param order_id alphanumeric string that uniquely identifies the proposal
- * @param h_post_data hash of the POST data for idempotency checks
- * @param pay_deadline how long does the customer have to pay for the order
- * @param claim_token token to use for access control
- * @param contract_terms proposal data to store
- * @param pos_key encoded key for payment verification
- * @param pos_algorithm algorithm to compute the payment verification
- * @return transaction status
+ * @param master_pub exchange master public key used for @a master_sig
+ * @param exchange_pub exchange signing key to insert
+ * @param start_date when does the signing key become valid
+ * @param expire_date when does the signing key stop being used
+ * @param end_date when does the signing key become void as proof
+ * @param master_sig signature of @a master_pub over the @a exchange_pub and 
the dates
  */
 static enum GNUNET_DB_QueryStatus
-postgres_insert_order (void *cls,
-                       const char *instance_id,
-                       const char *order_id,
-                       const struct TALER_MerchantPostDataHashP *h_post_data,
-                       struct GNUNET_TIME_Timestamp pay_deadline,
-                       const struct TALER_ClaimTokenP *claim_token,
-                       const json_t *contract_terms,
-                       const char *pos_key,
-                       enum TALER_MerchantConfirmationAlgorithm pos_algorithm)
+postgres_insert_exchange_signkey (
+  void *cls,
+  const struct TALER_MasterPublicKeyP *master_pub,
+  const struct TALER_ExchangePublicKeyP *exchange_pub,
+  struct GNUNET_TIME_Timestamp start_date,
+  struct GNUNET_TIME_Timestamp expire_date,
+  struct GNUNET_TIME_Timestamp end_date,
+  const struct TALER_MasterSignatureP *master_sig)
 {
   struct PostgresClosure *pg = cls;
-  struct GNUNET_TIME_Timestamp now;
-  uint32_t pos32 = (uint32_t) pos_algorithm;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_string (order_id),
-    GNUNET_PQ_query_param_timestamp (&pay_deadline),
-    GNUNET_PQ_query_param_auto_from_type (claim_token),
-    GNUNET_PQ_query_param_auto_from_type (h_post_data),
-    GNUNET_PQ_query_param_timestamp (&now),
-    TALER_PQ_query_param_json (contract_terms),
-    (NULL == pos_key)
-    ? GNUNET_PQ_query_param_null ()
-    : GNUNET_PQ_query_param_string (pos_key),
-    GNUNET_PQ_query_param_uint32 (&pos32),
+    GNUNET_PQ_query_param_auto_from_type (master_pub),
+    GNUNET_PQ_query_param_auto_from_type (exchange_pub),
+    GNUNET_PQ_query_param_timestamp (&start_date),
+    GNUNET_PQ_query_param_timestamp (&expire_date),
+    GNUNET_PQ_query_param_timestamp (&end_date),
+    GNUNET_PQ_query_param_auto_from_type (master_sig),
     GNUNET_PQ_query_param_end
   };
 
-  now = GNUNET_TIME_timestamp_get ();
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "inserting order: order_id: %s, instance_id: %s.\n",
-              order_id,
-              instance_id);
   check_connection (pg);
+  postgres_preflight (pg);
   return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "insert_order",
+                                             "insert_exchange_signkey",
                                              params);
+
 }
 
 
 /**
- * Release an inventory lock by UUID. Releases ALL stocks locked under
- * the given UUID.
+ * Insert payment confirmation from the exchange into the database.
  *
  * @param cls closure
- * @param uuid the UUID to release locks for
- * @return transaction status,
- *   #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS means there are no locks under @a 
uuid
- *   #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT indicates success
- */
-static enum GNUNET_DB_QueryStatus
-postgres_unlock_inventory (void *cls,
-                           const struct GNUNET_Uuid *uuid)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (uuid),
-    GNUNET_PQ_query_param_end
+ * @param instance_id instance to lookup deposits for
+ * @param deposit_timestamp time when the exchange generated the deposit 
confirmation
+ * @param h_contract_terms proposal data's hashcode
+ * @param coin_pub public key of the coin
+ * @param exchange_url URL of the exchange that issued @a coin_pub
+ * @param amount_with_fee amount the exchange will deposit for this coin
+ * @param deposit_fee fee the exchange will charge for this coin
+ * @param wire_fee wire fee the exchange charges
+ * @param refund_fee fee the exchange charges to refund this coin
+ * @param h_wire hash of the wire details of the target account of the merchant
+ * @param exchange_sig signature from exchange that coin was accepted
+ * @param exchange_pub signgin key that was used for @a exchange_sig
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_insert_deposit (
+  void *cls,
+  const char *instance_id,
+  struct GNUNET_TIME_Timestamp deposit_timestamp,
+  const struct TALER_PrivateContractHashP *h_contract_terms,
+  const struct TALER_CoinSpendPublicKeyP *coin_pub,
+  const char *exchange_url,
+  const struct TALER_Amount *amount_with_fee,
+  const struct TALER_Amount *deposit_fee,
+  const struct TALER_Amount *refund_fee,
+  const struct TALER_Amount *wire_fee,
+  const struct TALER_MerchantWireHashP *h_wire,
+  const struct TALER_ExchangeSignatureP *exchange_sig,
+  const struct TALER_ExchangePublicKeyP *exchange_pub)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+    GNUNET_PQ_query_param_timestamp (&deposit_timestamp), /* $3 */
+    GNUNET_PQ_query_param_auto_from_type (coin_pub),
+    GNUNET_PQ_query_param_string (exchange_url),
+    TALER_PQ_query_param_amount (amount_with_fee), /* $6/$7 */
+    TALER_PQ_query_param_amount (deposit_fee),  /* $8, $9 */
+    TALER_PQ_query_param_amount (refund_fee), /* $10, $11 */
+    TALER_PQ_query_param_amount (wire_fee),  /* $12, $13 */
+    GNUNET_PQ_query_param_auto_from_type (h_wire), /* $14 */
+    GNUNET_PQ_query_param_auto_from_type (exchange_sig), /* $15 */
+    GNUNET_PQ_query_param_auto_from_type (exchange_pub), /* $16 */
+    GNUNET_PQ_query_param_end
   };
 
+  /* no preflight check here, run in transaction by caller! */
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Storing deposit for instance `%s' h_contract_terms `%s', 
coin_pub: `%s', amount_with_fee: %s\n",
+              instance_id,
+              GNUNET_h2s (&h_contract_terms->hash),
+              TALER_B2S (coin_pub),
+              TALER_amount2s (amount_with_fee));
   check_connection (pg);
   return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "unlock_inventory",
+                                             "insert_deposit",
                                              params);
+
 }
 
 
 /**
- * Lock inventory stock to a particular order.
+ * Closure for #lookup_refunds_cb().
+ */
+struct LookupRefundsContext
+{
+  /**
+   * Function to call for each refund.
+   */
+  TALER_MERCHANTDB_RefundCallback rc;
+
+  /**
+   * Closure for @e rc.
+   */
+  void *rc_cls;
+
+  /**
+   * Plugin context.
+   */
+  struct PostgresClosure *pg;
+
+  /**
+   * 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 closure
- * @param instance_id identifies the instance responsible for the order
- * @param order_id alphanumeric string that uniquely identifies the order
- * @param product_id uniquely identifies the product to be locked
- * @param quantity how many units should be locked to the @a order_id
- * @return transaction status,
- *   #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS means there are insufficient stocks
- *   #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT indicates success
+ * @param cls of type `struct LookupRefundsContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
  */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_order_lock (void *cls,
-                            const char *instance_id,
-                            const char *order_id,
-                            const char *product_id,
-                            uint64_t quantity)
+static void
+lookup_refunds_cb (void *cls,
+                   PGresult *result,
+                   unsigned int num_results)
 {
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_string (order_id),
-    GNUNET_PQ_query_param_string (product_id),
-    GNUNET_PQ_query_param_uint64 (&quantity),
-    GNUNET_PQ_query_param_end
-  };
+  struct LookupRefundsContext *lrc = cls;
+  struct PostgresClosure *pg = lrc->pg;
 
-  check_connection (pg);
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "insert_order_lock",
-                                             params);
+  for (unsigned int i = 0; i<num_results; i++)
+  {
+    struct TALER_CoinSpendPublicKeyP coin_pub;
+    struct TALER_Amount refund_amount;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+                                            &coin_pub),
+      TALER_PQ_RESULT_SPEC_AMOUNT ("refund_amount",
+                                   &refund_amount),
+      GNUNET_PQ_result_spec_end
+    };
+
+    if (GNUNET_OK !=
+        GNUNET_PQ_extract_result (result,
+                                  rs,
+                                  i))
+    {
+      GNUNET_break (0);
+      lrc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+      return;
+    }
+    lrc->rc (lrc->rc_cls,
+             &coin_pub,
+             &refund_amount);
+    GNUNET_PQ_cleanup_result (rs); /* technically useless here */
+  }
+  lrc->qs = num_results;
 }
 
 
 /**
- * Retrieve contract terms given its @a order_id
+ * Obtain refunds associated with a contract.
  *
- * @param cls closure
- * @param instance_id instance's identifier
- * @param order_id order_id used to lookup.
- * @param[out] contract_terms where to store the result, NULL to only check 
for existence
- * @param[out] order_serial set to the order's serial number
- * @param[out] paid set to true if the order is fully paid
- * @param[out] claim_token set to the claim token, NULL to only check for 
existence
- * @param[out] pos_key encoded key for payment verification
- * @param[out] pos_algorithm algorithm to compute the payment verification
+ * @param cls closure, typically a connection to the db
+ * @param instance_id instance to lookup refunds for
+ * @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_lookup_contract_terms2 (
+postgres_lookup_refunds (
   void *cls,
   const char *instance_id,
-  const char *order_id,
-  json_t **contract_terms,
-  uint64_t *order_serial,
-  bool *paid,
-  struct TALER_ClaimTokenP *claim_token,
-  char **pos_key,
-  enum TALER_MerchantConfirmationAlgorithm *pos_algorithm)
+  const struct TALER_PrivateContractHashP *h_contract_terms,
+  TALER_MERCHANTDB_RefundCallback rc,
+  void *rc_cls)
 {
   struct PostgresClosure *pg = cls;
-  enum GNUNET_DB_QueryStatus qs;
-  struct TALER_ClaimTokenP ct;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_string (order_id),
+    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
     GNUNET_PQ_query_param_end
   };
-  uint32_t pos32;
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    /* contract_terms must be first! */
-    TALER_PQ_result_spec_json ("contract_terms",
-                               contract_terms),
-    GNUNET_PQ_result_spec_uint64 ("order_serial",
-                                  order_serial),
-    GNUNET_PQ_result_spec_bool ("paid",
-                                paid),
-    GNUNET_PQ_result_spec_auto_from_type ("claim_token",
-                                          &ct),
-    GNUNET_PQ_result_spec_allow_null (
-      GNUNET_PQ_result_spec_string ("pos_key",
-                                    pos_key),
-      NULL),
-    GNUNET_PQ_result_spec_allow_null (
-      GNUNET_PQ_result_spec_uint32 ("pos_algorithm",
-                                    &pos32),
-      NULL),
-    GNUNET_PQ_result_spec_end
+  struct LookupRefundsContext lrc = {
+    .rc = rc,
+    .rc_cls = rc_cls,
+    .pg = pg
   };
+  enum GNUNET_DB_QueryStatus qs;
 
+  /* no preflight check here, run in transaction by caller! */
+  TALER_LOG_DEBUG ("Looking for refund of h_contract_terms %s at `%s'\n",
+                   GNUNET_h2s (&h_contract_terms->hash),
+                   instance_id);
   check_connection (pg);
-  qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                 "lookup_contract_terms2",
-                                                 params,
-                                                 (NULL != contract_terms)
-                                                   ? rs
-                                                   : &rs[1]);
-  *pos_algorithm = (enum TALER_MerchantConfirmationAlgorithm) pos32;
-  if (NULL != claim_token)
-    *claim_token = ct;
-  return qs;
+  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+                                             "lookup_refunds",
+                                             params,
+                                             &lookup_refunds_cb,
+                                             &lrc);
+  if (0 >= qs)
+    return qs;
+  return lrc.qs;
 }
 
 
 /**
- * Retrieve contract terms given its @a order_id
+ * Mark contract as paid and store the current @a session_id
+ * for which the contract was paid. Deletes the underlying order
+ * and marks the locked stocks of the order as sold.
  *
  * @param cls closure
- * @param instance_id instance's identifier
- * @param order_id order_id used to lookup.
- * @param[out] contract_terms where to store the result, NULL to only check 
for existence
- * @param[out] order_serial set to the order's serial number
- * @param[out] paid set to true if the order is fully paid
- * @param[out] claim_token set to token to use for access control
+ * @param instance_id instance to mark contract as paid for
+ * @param h_contract_terms hash of the contract that is now paid
+ * @param session_id the session that paid the contract
  * @return transaction status
  */
 static enum GNUNET_DB_QueryStatus
-postgres_lookup_contract_terms (
+postgres_mark_contract_paid (
   void *cls,
   const char *instance_id,
-  const char *order_id,
-  json_t **contract_terms,
-  uint64_t *order_serial,
-  bool *paid,
-  struct TALER_ClaimTokenP *claim_token)
+  const struct TALER_PrivateContractHashP *h_contract_terms,
+  const char *session_id)
 {
   struct PostgresClosure *pg = cls;
-  enum GNUNET_DB_QueryStatus qs;
-  struct TALER_ClaimTokenP ct;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_string (order_id),
+    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+    GNUNET_PQ_query_param_string (session_id),
     GNUNET_PQ_query_param_end
   };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    /* contract_terms must be first! */
-    TALER_PQ_result_spec_json ("contract_terms",
-                               contract_terms),
-    GNUNET_PQ_result_spec_uint64 ("order_serial",
-                                  order_serial),
-    GNUNET_PQ_result_spec_bool ("paid",
-                                paid),
-    GNUNET_PQ_result_spec_auto_from_type ("claim_token",
-                                          &ct),
-    GNUNET_PQ_result_spec_end
+  struct GNUNET_PQ_QueryParam uparams[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+    GNUNET_PQ_query_param_end
   };
+  enum GNUNET_DB_QueryStatus qs;
 
-  check_connection (pg);
-  qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                 "lookup_contract_terms",
-                                                 params,
-                                                 (NULL != contract_terms)
-                                                   ? rs
-                                                   : &rs[1]);
-  if (NULL != claim_token)
-    *claim_token = ct;
-  return qs;
+  /* Session ID must always be given by the caller. */
+  GNUNET_assert (NULL != session_id);
+
+  /* no preflight check here, run in transaction by caller! */
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Marking h_contract_terms '%s' of %s as paid for session `%s'\n",
+              GNUNET_h2s (&h_contract_terms->hash),
+              instance_id,
+              session_id);
+  qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                           "mark_contract_paid",
+                                           params);
+  if (qs <= 0)
+    return qs;
+  qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                           "mark_inventory_sold",
+                                           uparams);
+  if (qs < 0)
+    return qs; /* 0: no inventory management, that's OK! */
+  /* ON DELETE CASCADE deletes from merchant_order_locks */
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "delete_completed_order",
+                                             uparams);
 }
 
 
 /**
- * Store contract terms given its @a order_id. Note that some attributes are
- * expected to be calculated inside of the function, like the hash of the
- * contract terms (to be hashed), the creation_time and pay_deadline (to be
- * obtained from the merchant_orders table). The "session_id" should be
- * initially set to the empty string.  The "fulfillment_url" and 
"refund_deadline"
- * must be extracted from @a contract_terms.
+ * Function called during aborts to refund a coin. Marks the
+ * respective coin as refunded.
  *
  * @param cls closure
- * @param instance_id instance's identifier
- * @param order_id order_id used to store
- * @param contract_terms contract terms to store
- * @param[out] order_serial set to the serial of the order
- * @return transaction status, #GNUNET_DB_STATUS_HARD_ERROR if @a 
contract_terms
- *          is malformed
+ * @param instance_id instance to refund payment for
+ * @param h_contract_terms hash of the contract to refund coin for
+ * @param refund_timestamp timestamp of the refund
+ * @param coin_pub public key of the coin to refund (fully)
+ * @param reason text justifying the refund
+ * @return transaction status
+ *        #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a coin_pub is unknown to us;
+ *        #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if the request is valid,
+ *        regardless of whether it actually increased the refund
  */
 static enum GNUNET_DB_QueryStatus
-postgres_insert_contract_terms (
-  void *cls,
-  const char *instance_id,
-  const char *order_id,
-  json_t *contract_terms,
-  uint64_t *order_serial)
+postgres_refund_coin (void *cls,
+                      const char *instance_id,
+                      const struct TALER_PrivateContractHashP 
*h_contract_terms,
+                      struct GNUNET_TIME_Timestamp refund_timestamp,
+                      const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                      const char *reason)
 {
   struct PostgresClosure *pg = cls;
-  struct GNUNET_TIME_Timestamp pay_deadline;
-  struct GNUNET_TIME_Timestamp refund_deadline;
-  const char *fulfillment_url;
-  struct TALER_PrivateContractHashP h_contract_terms;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+    GNUNET_PQ_query_param_timestamp (&refund_timestamp),
+    GNUNET_PQ_query_param_auto_from_type (coin_pub),
+    GNUNET_PQ_query_param_string (reason),
+    GNUNET_PQ_query_param_end
+  };
 
-  if (GNUNET_OK !=
-      TALER_JSON_contract_hash (contract_terms,
-                                &h_contract_terms))
-  {
-    GNUNET_break (0);
-    return GNUNET_DB_STATUS_HARD_ERROR;
-  }
-
-  {
-    struct GNUNET_JSON_Specification spec[] = {
-      GNUNET_JSON_spec_timestamp ("pay_deadline",
-                                  &pay_deadline),
-      GNUNET_JSON_spec_timestamp ("refund_deadline",
-                                  &refund_deadline),
-      GNUNET_JSON_spec_end ()
-    };
-    enum GNUNET_GenericReturnValue res;
-
-    res = TALER_MHD_parse_json_data (NULL,
-                                     contract_terms,
-                                     spec);
-    if (GNUNET_OK != res)
-    {
-      GNUNET_break (0);
-      return GNUNET_DB_STATUS_HARD_ERROR;
-    }
-  }
-
-  fulfillment_url =
-    json_string_value (json_object_get (contract_terms,
-                                        "fulfillment_url"));
-  check_connection (pg);
-  {
-    struct GNUNET_PQ_QueryParam params[] = {
-      GNUNET_PQ_query_param_string (instance_id),
-      GNUNET_PQ_query_param_string (order_id),
-      TALER_PQ_query_param_json (contract_terms),
-      GNUNET_PQ_query_param_auto_from_type (&h_contract_terms),
-      GNUNET_PQ_query_param_timestamp (&pay_deadline),
-      GNUNET_PQ_query_param_timestamp (&refund_deadline),
-      (NULL == fulfillment_url)
-      ? GNUNET_PQ_query_param_null ()
-      : GNUNET_PQ_query_param_string (fulfillment_url),
-      GNUNET_PQ_query_param_end
-    };
-    struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_uint64 ("order_serial",
-                                    order_serial),
-      GNUNET_PQ_result_spec_end
-    };
-
-    return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                     "insert_contract_terms",
-                                                     params,
-                                                     rs);
-  }
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "refund_coin",
+                                             params);
 }
 
 
 /**
- * Update the contract terms stored for @a order_id. Note that some attributes 
are
- * expected to be calculated inside of the function, like the hash of the
- * contract terms (to be hashed), the creation_time and pay_deadline (to be
- * obtained from the merchant_orders table). The "session_id" should be
- * initially set to the empty string.  The "fulfillment_url" and 
"refund_deadline"
- * must be extracted from @a contract_terms.
+ * Retrieve contract terms given its @a order_id
  *
  * @param cls closure
  * @param instance_id instance's identifier
- * @param order_id order_id used to store
- * @param contract_terms contract to store
- * @return transaction status, #GNUNET_DB_STATUS_HARD_ERROR if @a 
contract_terms
- *          is malformed
+ * @param order_id order to lookup contract for
+ * @param[out] h_contract_terms set to the hash of the contract.
+ * @param[out] paid set to the payment status of the contract
+ * @return transaction status
  */
 static enum GNUNET_DB_QueryStatus
-postgres_update_contract_terms (void *cls,
-                                const char *instance_id,
-                                const char *order_id,
-                                json_t *contract_terms)
+postgres_lookup_order_status (
+  void *cls,
+  const char *instance_id,
+  const char *order_id,
+  struct TALER_PrivateContractHashP *h_contract_terms,
+  bool *paid)
 {
   struct PostgresClosure *pg = cls;
-  struct GNUNET_TIME_Timestamp pay_deadline;
-  struct GNUNET_TIME_Timestamp refund_deadline;
-  const char *fulfillment_url = NULL;
-  struct TALER_PrivateContractHashP h_contract_terms;
-
-  if (GNUNET_OK !=
-      TALER_JSON_contract_hash (contract_terms,
-                                &h_contract_terms))
-  {
-    GNUNET_break (0);
-    return GNUNET_DB_STATUS_HARD_ERROR;
-  }
-
-  {
-    struct GNUNET_JSON_Specification spec[] = {
-      GNUNET_JSON_spec_timestamp ("pay_deadline",
-                                  &pay_deadline),
-      GNUNET_JSON_spec_timestamp ("refund_deadline",
-                                  &refund_deadline),
-      GNUNET_JSON_spec_mark_optional (
-        GNUNET_JSON_spec_string ("fulfillment_url",
-                                 &fulfillment_url),
-        NULL),
-      GNUNET_JSON_spec_end ()
-    };
-    enum GNUNET_GenericReturnValue res;
-
-    res = TALER_MHD_parse_json_data (NULL,
-                                     contract_terms,
-                                     spec);
-    if (GNUNET_OK != res)
-    {
-      GNUNET_break (0);
-      return GNUNET_DB_STATUS_HARD_ERROR;
-    }
-  }
+  uint8_t paid8;
+  enum GNUNET_DB_QueryStatus qs;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_string (order_id),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
+                                          h_contract_terms),
+    GNUNET_PQ_result_spec_auto_from_type ("paid",
+                                          &paid8),
+    GNUNET_PQ_result_spec_end
+  };
 
   check_connection (pg);
-  {
-    struct GNUNET_PQ_QueryParam params[] = {
-      GNUNET_PQ_query_param_string (instance_id),
-      GNUNET_PQ_query_param_string (order_id),
-      TALER_PQ_query_param_json (contract_terms),
-      GNUNET_PQ_query_param_auto_from_type (&h_contract_terms),
-      GNUNET_PQ_query_param_timestamp (&pay_deadline),
-      GNUNET_PQ_query_param_timestamp (&refund_deadline),
-      (NULL == fulfillment_url)
-      ? GNUNET_PQ_query_param_null ()
-      : GNUNET_PQ_query_param_string (fulfillment_url),
-      GNUNET_PQ_query_param_end
-    };
-
-    return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                               "update_contract_terms",
-                                               params);
-  }
+  qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                 "lookup_order_status",
+                                                 params,
+                                                 rs);
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+    *paid = (0 != paid8);
+  else
+    *paid = false; /* just to be safe(r) */
+  return qs;
 }
 
 
 /**
- * Delete information about a contract. Note that the transaction must
- * enforce that the contract is not awaiting payment anymore AND was not
- * paid, or is past the legal expiration.
+ * Retrieve contract terms given its @a order_serial
  *
  * @param cls closure
- * @param instance_id instance to delete order of
- * @param order_id order to delete
- * @param legal_expiration how long do we need to keep (paid) contracts on
- *          file for legal reasons (i.e. taxation)
- * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
- *           if locks prevent deletion OR order unknown
+ * @param instance_id instance's identifier
+ * @param order_serial serial ID of the order to look up
+ * @param[out] order_id set to ID of the order
+ * @param[out] h_contract_terms set to the hash of the contract.
+ * @param[out] paid set to the payment status of the contract
+ * @return transaction status
  */
 static enum GNUNET_DB_QueryStatus
-postgres_delete_contract_terms (void *cls,
-                                const char *instance_id,
-                                const char *order_id,
-                                struct GNUNET_TIME_Relative legal_expiration)
+postgres_lookup_order_status_by_serial (void *cls,
+                                        const char *instance_id,
+                                        uint64_t order_serial,
+                                        char **order_id,
+                                        struct TALER_PrivateContractHashP *
+                                        h_contract_terms,
+                                        bool *paid)
 {
   struct PostgresClosure *pg = cls;
-  struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+  uint8_t paid8;
+  enum GNUNET_DB_QueryStatus qs;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_string (order_id),
-    GNUNET_PQ_query_param_relative_time (&legal_expiration),
-    GNUNET_PQ_query_param_absolute_time (&now),
+    GNUNET_PQ_query_param_uint64 (&order_serial),
     GNUNET_PQ_query_param_end
   };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
+                                          h_contract_terms),
+    GNUNET_PQ_result_spec_auto_from_type ("paid",
+                                          &paid8),
+    GNUNET_PQ_result_spec_string ("order_id",
+                                  order_id),
+    GNUNET_PQ_result_spec_end
+  };
 
   check_connection (pg);
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "delete_contract_terms",
-                                             params);
+  qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                 
"lookup_order_status_by_serial",
+                                                 params,
+                                                 rs);
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+    *paid = (0 != paid8);
+  else
+    *paid = false; /* just to be safe(r) */
+  return qs;
 }
 
 
 /**
- * Closure for #lookup_deposits_cb().
+ * Retrieve payment and wire status for a given @a order_serial and session ID.
+ *
+ * @param cls closure
+ * @param order_serial identifies the order
+ * @param session_id session for which to check the payment status, NULL for 
any
+ * @param[out] paid set to the payment status of the contract
+ * @param[out] wired set to the wire transfer status of the exchange payment
+ * @return transaction status
  */
-struct LookupDepositsContext
+static enum GNUNET_DB_QueryStatus
+postgres_lookup_payment_status (void *cls,
+                                uint64_t order_serial,
+                                const char *session_id,
+                                bool *paid,
+                                bool *wired)
+{
+  struct PostgresClosure *pg = cls;
+  uint8_t paid8;
+  uint8_t wired8;
+  enum GNUNET_DB_QueryStatus qs;
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_auto_from_type ("paid",
+                                          &paid8),
+    GNUNET_PQ_result_spec_auto_from_type ("wired",
+                                          &wired8),
+    GNUNET_PQ_result_spec_end
+  };
+  check_connection (pg);
+  if (NULL == session_id)
+  {
+    struct GNUNET_PQ_QueryParam params[] = {
+      GNUNET_PQ_query_param_uint64 (&order_serial),
+      GNUNET_PQ_query_param_end
+    };
+
+    qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "lookup_payment_status",
+                                                   params,
+                                                   rs);
+  }
+  else
+  {
+    struct GNUNET_PQ_QueryParam params[] = {
+      GNUNET_PQ_query_param_uint64 (&order_serial),
+      GNUNET_PQ_query_param_string (session_id),
+      GNUNET_PQ_query_param_end
+    };
+
+    qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   
"lookup_payment_status_session_id",
+                                                   params,
+                                                   rs);
+  }
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+  {
+    *paid = (0 != paid8);
+    *wired = (0 != wired8);
+  }
+  else
+  {
+    *paid = false; /* just to be safe(r) */
+    *wired = false; /* just to be safe(r) */
+  }
+  return qs;
+}
+
+
+/**
+ * Closure for lookup_deposits_by_order_cb().
+ */
+struct LookupDepositsByOrderContext
 {
+
   /**
-   * Function to call with results.
+   * Plugin context.
    */
-  TALER_MERCHANTDB_DepositsCallback cb;
+  struct PostgresClosure *pg;
 
   /**
-   * Closure for @e cls.
+   * Function to call with all results.
    */
-  void *cb_cls;
+  TALER_MERCHANTDB_DepositedCoinsCallback cb;
 
   /**
-   * Plugin context.
+   * Closure for @e cb.
    */
-  struct PostgresClosure *pg;
+  void *cb_cls;
 
   /**
-   * Transaction status (set).
+   * Set to the query result.
    */
   enum GNUNET_DB_QueryStatus qs;
 };
@@ -1158,39 +1008,39 @@ struct LookupDepositsContext
  * Function to be called with the results of a SELECT statement
  * that has returned @a num_results results.
  *
- * @param[in,out] cls of type `struct LookupDepositsContext *`
+ * @param cls of type `struct LookupDepositsByOrderContext *`
  * @param result the postgres result
  * @param num_results the number of results in @a result
  */
 static void
-lookup_deposits_cb (void *cls,
-                    PGresult *result,
-                    unsigned int num_results)
+lookup_deposits_by_order_cb (void *cls,
+                             PGresult *result,
+                             unsigned int num_results)
 {
-  struct LookupDepositsContext *ldc = cls;
-  struct PostgresClosure *pg = ldc->pg;
+  struct LookupDepositsByOrderContext *ldoc = cls;
+  struct PostgresClosure *pg = ldoc->pg;
 
   for (unsigned int i = 0; i<num_results; i++)
   {
+    uint64_t deposit_serial;
+    char *exchange_url;
+    struct TALER_MerchantWireHashP h_wire;
     struct TALER_CoinSpendPublicKeyP coin_pub;
     struct TALER_Amount amount_with_fee;
     struct TALER_Amount deposit_fee;
-    struct TALER_Amount refund_fee;
-    struct TALER_Amount wire_fee;
-    char *exchange_url;
     struct GNUNET_PQ_ResultSpec rs[] = {
+      GNUNET_PQ_result_spec_uint64 ("deposit_serial",
+                                    &deposit_serial),
       GNUNET_PQ_result_spec_string ("exchange_url",
                                     &exchange_url),
-      GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
-                                            &coin_pub),
+      GNUNET_PQ_result_spec_auto_from_type ("h_wire",
+                                            &h_wire),
       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_AMOUNT ("wire_fee",
-                                   &wire_fee),
+      GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+                                            &coin_pub),
       GNUNET_PQ_result_spec_end
     };
 
@@ -1200,199 +1050,83 @@ lookup_deposits_cb (void *cls,
                                   i))
     {
       GNUNET_break (0);
-      ldc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+      ldoc->qs = GNUNET_DB_STATUS_HARD_ERROR;
       return;
     }
-    ldc->cb (ldc->cb_cls,
-             exchange_url,
-             &coin_pub,
-             &amount_with_fee,
-             &deposit_fee,
-             &refund_fee,
-             &wire_fee);
-    GNUNET_PQ_cleanup_result (rs);
+    ldoc->cb (ldoc->cb_cls,
+              deposit_serial,
+              exchange_url,
+              &h_wire,
+              &amount_with_fee,
+              &deposit_fee,
+              &coin_pub);
+    GNUNET_PQ_cleanup_result (rs); /* technically useless here */
   }
-  ldc->qs = num_results;
+  ldoc->qs = num_results;
 }
 
 
 /**
- * Lookup information about coins that were successfully deposited for a
- * given contract.
+ * Retrieve details about coins that were deposited for an order.
  *
  * @param cls closure
- * @param instance_id instance to lookup deposits for
- * @param h_contract_terms proposal data's hashcode
- * @param cb function to call with payment data
+ * @param order_serial identifies the order
+ * @param cb function to call for each deposited coin
  * @param cb_cls closure for @a cb
  * @return transaction status
  */
 static enum GNUNET_DB_QueryStatus
-postgres_lookup_deposits (
-  void *cls,
-  const char *instance_id,
-  const struct TALER_PrivateContractHashP *h_contract_terms,
-  TALER_MERCHANTDB_DepositsCallback cb,
-  void *cb_cls)
+postgres_lookup_deposits_by_order (void *cls,
+                                   uint64_t order_serial,
+                                   TALER_MERCHANTDB_DepositedCoinsCallback cb,
+                                   void *cb_cls)
 {
   struct PostgresClosure *pg = cls;
+  struct LookupDepositsByOrderContext ldoc = {
+    .pg = pg,
+    .cb = cb,
+    .cb_cls = cb_cls
+  };
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+    GNUNET_PQ_query_param_uint64 (&order_serial),
     GNUNET_PQ_query_param_end
   };
-  struct LookupDepositsContext ldc = {
-    .cb = cb,
-    .cb_cls = cb_cls,
-    .pg = pg
-  };
   enum GNUNET_DB_QueryStatus qs;
 
-  /* no preflight check here, run in its own transaction by the caller! */
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Finding deposits for h_contract_terms '%s'\n",
-              GNUNET_h2s (&h_contract_terms->hash));
-  check_connection (pg);
   qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
-                                             "lookup_deposits",
+                                             "lookup_deposits_by_order",
                                              params,
-                                             &lookup_deposits_cb,
-                                             &ldc);
-  if (qs <= 0)
+                                             &lookup_deposits_by_order_cb,
+                                             &ldoc);
+  if (qs < 0)
     return qs;
-  return ldc.qs;
-}
-
-
-/**
- * Insert an exchange signing key into our database.
- *
- * @param cls closure
- * @param master_pub exchange master public key used for @a master_sig
- * @param exchange_pub exchange signing key to insert
- * @param start_date when does the signing key become valid
- * @param expire_date when does the signing key stop being used
- * @param end_date when does the signing key become void as proof
- * @param master_sig signature of @a master_pub over the @a exchange_pub and 
the dates
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_exchange_signkey (
-  void *cls,
-  const struct TALER_MasterPublicKeyP *master_pub,
-  const struct TALER_ExchangePublicKeyP *exchange_pub,
-  struct GNUNET_TIME_Timestamp start_date,
-  struct GNUNET_TIME_Timestamp expire_date,
-  struct GNUNET_TIME_Timestamp end_date,
-  const struct TALER_MasterSignatureP *master_sig)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (master_pub),
-    GNUNET_PQ_query_param_auto_from_type (exchange_pub),
-    GNUNET_PQ_query_param_timestamp (&start_date),
-    GNUNET_PQ_query_param_timestamp (&expire_date),
-    GNUNET_PQ_query_param_timestamp (&end_date),
-    GNUNET_PQ_query_param_auto_from_type (master_sig),
-    GNUNET_PQ_query_param_end
-  };
-
-  check_connection (pg);
-  postgres_preflight (pg);
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "insert_exchange_signkey",
-                                             params);
-
+  return ldoc.qs;
 }
 
 
 /**
- * Insert payment confirmation from the exchange into the database.
- *
- * @param cls closure
- * @param instance_id instance to lookup deposits for
- * @param deposit_timestamp time when the exchange generated the deposit 
confirmation
- * @param h_contract_terms proposal data's hashcode
- * @param coin_pub public key of the coin
- * @param exchange_url URL of the exchange that issued @a coin_pub
- * @param amount_with_fee amount the exchange will deposit for this coin
- * @param deposit_fee fee the exchange will charge for this coin
- * @param wire_fee wire fee the exchange charges
- * @param refund_fee fee the exchange charges to refund this coin
- * @param h_wire hash of the wire details of the target account of the merchant
- * @param exchange_sig signature from exchange that coin was accepted
- * @param exchange_pub signgin key that was used for @a exchange_sig
- * @return transaction status
+ * Closure for lookup_deposits_by_order_cb().
  */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_deposit (
-  void *cls,
-  const char *instance_id,
-  struct GNUNET_TIME_Timestamp deposit_timestamp,
-  const struct TALER_PrivateContractHashP *h_contract_terms,
-  const struct TALER_CoinSpendPublicKeyP *coin_pub,
-  const char *exchange_url,
-  const struct TALER_Amount *amount_with_fee,
-  const struct TALER_Amount *deposit_fee,
-  const struct TALER_Amount *refund_fee,
-  const struct TALER_Amount *wire_fee,
-  const struct TALER_MerchantWireHashP *h_wire,
-  const struct TALER_ExchangeSignatureP *exchange_sig,
-  const struct TALER_ExchangePublicKeyP *exchange_pub)
+struct LookupTransferDetailsByOrderContext
 {
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
-    GNUNET_PQ_query_param_timestamp (&deposit_timestamp), /* $3 */
-    GNUNET_PQ_query_param_auto_from_type (coin_pub),
-    GNUNET_PQ_query_param_string (exchange_url),
-    TALER_PQ_query_param_amount (amount_with_fee), /* $6/$7 */
-    TALER_PQ_query_param_amount (deposit_fee),  /* $8, $9 */
-    TALER_PQ_query_param_amount (refund_fee), /* $10, $11 */
-    TALER_PQ_query_param_amount (wire_fee),  /* $12, $13 */
-    GNUNET_PQ_query_param_auto_from_type (h_wire), /* $14 */
-    GNUNET_PQ_query_param_auto_from_type (exchange_sig), /* $15 */
-    GNUNET_PQ_query_param_auto_from_type (exchange_pub), /* $16 */
-    GNUNET_PQ_query_param_end
-  };
-
-  /* no preflight check here, run in transaction by caller! */
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Storing deposit for instance `%s' h_contract_terms `%s', 
coin_pub: `%s', amount_with_fee: %s\n",
-              instance_id,
-              GNUNET_h2s (&h_contract_terms->hash),
-              TALER_B2S (coin_pub),
-              TALER_amount2s (amount_with_fee));
-  check_connection (pg);
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "insert_deposit",
-                                             params);
 
-}
-
-
-/**
- * Closure for #lookup_refunds_cb().
- */
-struct LookupRefundsContext
-{
   /**
-   * Function to call for each refund.
+   * Plugin context.
    */
-  TALER_MERCHANTDB_RefundCallback rc;
+  struct PostgresClosure *pg;
 
   /**
-   * Closure for @e rc.
+   * Function to call with all results.
    */
-  void *rc_cls;
+  TALER_MERCHANTDB_OrderTransferDetailsCallback cb;
 
   /**
-   * Plugin context.
+   * Closure for @e cb.
    */
-  struct PostgresClosure *pg;
+  void *cb_cls;
 
   /**
-   * Transaction result.
+   * Set to the query result.
    */
   enum GNUNET_DB_QueryStatus qs;
 };
@@ -1402,27 +1136,42 @@ struct LookupRefundsContext
  * Function to be called with the results of a SELECT statement
  * that has returned @a num_results results.
  *
- * @param cls of type `struct LookupRefundsContext *`
+ * @param cls of type `struct LookupTransferDetailsByOrderContext *`
  * @param result the postgres result
  * @param num_results the number of results in @a result
  */
 static void
-lookup_refunds_cb (void *cls,
-                   PGresult *result,
-                   unsigned int num_results)
+lookup_transfer_details_by_order_cb (void *cls,
+                                     PGresult *result,
+                                     unsigned int num_results)
 {
-  struct LookupRefundsContext *lrc = cls;
-  struct PostgresClosure *pg = lrc->pg;
+  struct LookupTransferDetailsByOrderContext *ltdo = cls;
+  struct PostgresClosure *pg = ltdo->pg;
 
   for (unsigned int i = 0; i<num_results; i++)
   {
-    struct TALER_CoinSpendPublicKeyP coin_pub;
-    struct TALER_Amount refund_amount;
+    struct TALER_WireTransferIdentifierRawP wtid;
+    char *exchange_url;
+    uint64_t deposit_serial;
+    struct GNUNET_TIME_Timestamp execution_time;
+    struct TALER_Amount deposit_value;
+    struct TALER_Amount deposit_fee;
+    uint8_t transfer_confirmed;
     struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
-                                            &coin_pub),
-      TALER_PQ_RESULT_SPEC_AMOUNT ("refund_amount",
-                                   &refund_amount),
+      GNUNET_PQ_result_spec_uint64 ("deposit_serial",
+                                    &deposit_serial),
+      GNUNET_PQ_result_spec_timestamp ("deposit_timestamp",
+                                       &execution_time),
+      GNUNET_PQ_result_spec_string ("exchange_url",
+                                    &exchange_url),
+      GNUNET_PQ_result_spec_auto_from_type ("wtid",
+                                            &wtid),
+      TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_value",
+                                   &deposit_value),
+      TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_fee",
+                                   &deposit_fee),
+      GNUNET_PQ_result_spec_auto_from_type ("transfer_confirmed",
+                                            &transfer_confirmed),
       GNUNET_PQ_result_spec_end
     };
 
@@ -1432,481 +1181,259 @@ lookup_refunds_cb (void *cls,
                                   i))
     {
       GNUNET_break (0);
-      lrc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+      ltdo->qs = GNUNET_DB_STATUS_HARD_ERROR;
       return;
     }
-    lrc->rc (lrc->rc_cls,
-             &coin_pub,
-             &refund_amount);
+    ltdo->cb (ltdo->cb_cls,
+              &wtid,
+              exchange_url,
+              execution_time,
+              &deposit_value,
+              &deposit_fee,
+              (0 != transfer_confirmed));
     GNUNET_PQ_cleanup_result (rs); /* technically useless here */
   }
-  lrc->qs = num_results;
+  ltdo->qs = num_results;
 }
 
 
 /**
- * Obtain refunds associated with a contract.
+ * Retrieve wire transfer details for all deposits associated with
+ * a given @a order_serial.
  *
- * @param cls closure, typically a connection to the db
- * @param instance_id instance to lookup refunds for
- * @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
+ * @param cls closure
+ * @param order_serial identifies the order
+ * @param cb function called with the wire transfer details
+ * @param cb_cls closure for @a cb
  * @return transaction status
  */
 static enum GNUNET_DB_QueryStatus
-postgres_lookup_refunds (
+postgres_lookup_transfer_details_by_order (
   void *cls,
-  const char *instance_id,
-  const struct TALER_PrivateContractHashP *h_contract_terms,
-  TALER_MERCHANTDB_RefundCallback rc,
-  void *rc_cls)
+  uint64_t order_serial,
+  TALER_MERCHANTDB_OrderTransferDetailsCallback cb,
+  void *cb_cls)
 {
   struct PostgresClosure *pg = cls;
+  struct LookupTransferDetailsByOrderContext ltdo = {
+    .pg = pg,
+    .cb = cb,
+    .cb_cls = cb_cls
+  };
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+    GNUNET_PQ_query_param_uint64 (&order_serial),
     GNUNET_PQ_query_param_end
   };
-  struct LookupRefundsContext lrc = {
-    .rc = rc,
-    .rc_cls = rc_cls,
-    .pg = pg
-  };
   enum GNUNET_DB_QueryStatus qs;
 
-  /* no preflight check here, run in transaction by caller! */
-  TALER_LOG_DEBUG ("Looking for refund of h_contract_terms %s at `%s'\n",
-                   GNUNET_h2s (&h_contract_terms->hash),
-                   instance_id);
-  check_connection (pg);
-  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
-                                             "lookup_refunds",
-                                             params,
-                                             &lookup_refunds_cb,
-                                             &lrc);
-  if (0 >= qs)
+  qs = GNUNET_PQ_eval_prepared_multi_select (
+    pg->conn,
+    "lookup_transfer_details_by_order",
+    params,
+    &lookup_transfer_details_by_order_cb,
+    &ltdo);
+  if (qs < 0)
     return qs;
-  return lrc.qs;
+  return ltdo.qs;
 }
 
 
 /**
- * Mark contract as paid and store the current @a session_id
- * for which the contract was paid. Deletes the underlying order
- * and marks the locked stocks of the order as sold.
+ * Insert wire transfer details for a deposit.
  *
  * @param cls closure
- * @param instance_id instance to mark contract as paid for
- * @param h_contract_terms hash of the contract that is now paid
- * @param session_id the session that paid the contract
+ * @param deposit_serial serial number of the deposit
+ * @param dd deposit transfer data from the exchange to store
  * @return transaction status
  */
 static enum GNUNET_DB_QueryStatus
-postgres_mark_contract_paid (
+postgres_insert_deposit_to_transfer (
   void *cls,
-  const char *instance_id,
-  const struct TALER_PrivateContractHashP *h_contract_terms,
-  const char *session_id)
+  uint64_t deposit_serial,
+  const struct TALER_EXCHANGE_DepositData *dd)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
-    GNUNET_PQ_query_param_string (session_id),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_QueryParam uparams[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+    GNUNET_PQ_query_param_uint64 (&deposit_serial),
+    TALER_PQ_query_param_amount (&dd->coin_contribution),
+    GNUNET_PQ_query_param_timestamp (&dd->execution_time),
+    GNUNET_PQ_query_param_auto_from_type (&dd->exchange_sig),
+    GNUNET_PQ_query_param_auto_from_type (&dd->exchange_pub),
+    GNUNET_PQ_query_param_auto_from_type (&dd->wtid),
     GNUNET_PQ_query_param_end
   };
-  enum GNUNET_DB_QueryStatus qs;
 
-  /* Session ID must always be given by the caller. */
-  GNUNET_assert (NULL != session_id);
-
-  /* no preflight check here, run in transaction by caller! */
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Marking h_contract_terms '%s' of %s as paid for session `%s'\n",
-              GNUNET_h2s (&h_contract_terms->hash),
-              instance_id,
-              session_id);
-  qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                           "mark_contract_paid",
-                                           params);
-  if (qs <= 0)
-    return qs;
-  qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                           "mark_inventory_sold",
-                                           uparams);
-  if (qs < 0)
-    return qs; /* 0: no inventory management, that's OK! */
-  /* ON DELETE CASCADE deletes from merchant_order_locks */
   return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "delete_completed_order",
-                                             uparams);
+                                             "insert_deposit_to_transfer",
+                                             params);
 }
 
 
 /**
- * Function called during aborts to refund a coin. Marks the
- * respective coin as refunded.
+ * Set 'wired' status for an order to 'true'.
  *
  * @param cls closure
- * @param instance_id instance to refund payment for
- * @param h_contract_terms hash of the contract to refund coin for
- * @param refund_timestamp timestamp of the refund
- * @param coin_pub public key of the coin to refund (fully)
- * @param reason text justifying the refund
+ * @param order_serial serial number of the order
  * @return transaction status
- *        #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a coin_pub is unknown to us;
- *        #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if the request is valid,
- *        regardless of whether it actually increased the refund
  */
 static enum GNUNET_DB_QueryStatus
-postgres_refund_coin (void *cls,
-                      const char *instance_id,
-                      const struct TALER_PrivateContractHashP 
*h_contract_terms,
-                      struct GNUNET_TIME_Timestamp refund_timestamp,
-                      const struct TALER_CoinSpendPublicKeyP *coin_pub,
-                      const char *reason)
+postgres_mark_order_wired (void *cls,
+                           uint64_t order_serial)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
-    GNUNET_PQ_query_param_timestamp (&refund_timestamp),
-    GNUNET_PQ_query_param_auto_from_type (coin_pub),
-    GNUNET_PQ_query_param_string (reason),
+    GNUNET_PQ_query_param_uint64 (&order_serial),
     GNUNET_PQ_query_param_end
   };
 
   return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "refund_coin",
+                                             "mark_order_wired",
                                              params);
 }
 
 
 /**
- * Retrieve contract terms given its @a order_id
- *
- * @param cls closure
- * @param instance_id instance's identifier
- * @param order_id order to lookup contract for
- * @param[out] h_contract_terms set to the hash of the contract.
- * @param[out] paid set to the payment status of the contract
- * @return transaction status
+ * Closure for #process_refund_cb().
  */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_order_status (
-  void *cls,
-  const char *instance_id,
-  const char *order_id,
-  struct TALER_PrivateContractHashP *h_contract_terms,
-  bool *paid)
+struct FindRefundContext
 {
-  struct PostgresClosure *pg = cls;
-  uint8_t paid8;
-  enum GNUNET_DB_QueryStatus qs;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_string (order_id),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
-                                          h_contract_terms),
-    GNUNET_PQ_result_spec_auto_from_type ("paid",
-                                          &paid8),
-    GNUNET_PQ_result_spec_end
-  };
 
-  check_connection (pg);
-  qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                 "lookup_order_status",
-                                                 params,
-                                                 rs);
-  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
-    *paid = (0 != paid8);
-  else
-    *paid = false; /* just to be safe(r) */
-  return qs;
-}
+  /**
+   * Plugin context.
+   */
+  struct PostgresClosure *pg;
 
+  /**
+   * Updated to reflect total amount refunded so far.
+   */
+  struct TALER_Amount refunded_amount;
 
-/**
- * Retrieve contract terms given its @a order_serial
- *
- * @param cls closure
- * @param instance_id instance's identifier
- * @param order_serial serial ID of the order to look up
- * @param[out] order_id set to ID of the order
- * @param[out] h_contract_terms set to the hash of the contract.
- * @param[out] paid set to the payment status of the contract
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_order_status_by_serial (void *cls,
-                                        const char *instance_id,
-                                        uint64_t order_serial,
-                                        char **order_id,
-                                        struct TALER_PrivateContractHashP *
-                                        h_contract_terms,
-                                        bool *paid)
-{
-  struct PostgresClosure *pg = cls;
-  uint8_t paid8;
-  enum GNUNET_DB_QueryStatus qs;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_uint64 (&order_serial),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
-                                          h_contract_terms),
-    GNUNET_PQ_result_spec_auto_from_type ("paid",
-                                          &paid8),
-    GNUNET_PQ_result_spec_string ("order_id",
-                                  order_id),
-    GNUNET_PQ_result_spec_end
-  };
+  /**
+   * Set to the largest refund transaction ID encountered.
+   */
+  uint64_t max_rtransaction_id;
 
-  check_connection (pg);
-  qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                 
"lookup_order_status_by_serial",
-                                                 params,
-                                                 rs);
-  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
-    *paid = (0 != paid8);
-  else
-    *paid = false; /* just to be safe(r) */
-  return qs;
-}
+  /**
+   * Set to true on hard errors.
+   */
+  bool err;
+};
 
 
 /**
- * Retrieve payment and wire status for a given @a order_serial and session ID.
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results.
  *
- * @param cls closure
- * @param order_serial identifies the order
- * @param session_id session for which to check the payment status, NULL for 
any
- * @param[out] paid set to the payment status of the contract
- * @param[out] wired set to the wire transfer status of the exchange payment
- * @return transaction status
+ * @param cls closure, our `struct FindRefundContext`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
  */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_payment_status (void *cls,
-                                uint64_t order_serial,
-                                const char *session_id,
-                                bool *paid,
-                                bool *wired)
+static void
+process_refund_cb (void *cls,
+                   PGresult *result,
+                   unsigned int num_results)
 {
-  struct PostgresClosure *pg = cls;
-  uint8_t paid8;
-  uint8_t wired8;
-  enum GNUNET_DB_QueryStatus qs;
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_auto_from_type ("paid",
-                                          &paid8),
-    GNUNET_PQ_result_spec_auto_from_type ("wired",
-                                          &wired8),
-    GNUNET_PQ_result_spec_end
-  };
-  check_connection (pg);
-  if (NULL == session_id)
-  {
-    struct GNUNET_PQ_QueryParam params[] = {
-      GNUNET_PQ_query_param_uint64 (&order_serial),
-      GNUNET_PQ_query_param_end
-    };
+  struct FindRefundContext *ictx = cls;
+  struct PostgresClosure *pg = ictx->pg;
 
-    qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   "lookup_payment_status",
-                                                   params,
-                                                   rs);
-  }
-  else
+  for (unsigned int i = 0; i<num_results; i++)
   {
-    struct GNUNET_PQ_QueryParam params[] = {
-      GNUNET_PQ_query_param_uint64 (&order_serial),
-      GNUNET_PQ_query_param_string (session_id),
-      GNUNET_PQ_query_param_end
+    /* Sum up existing refunds */
+    struct TALER_Amount acc;
+    uint64_t rtransaction_id;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      TALER_PQ_RESULT_SPEC_AMOUNT ("refund_amount",
+                                   &acc),
+      GNUNET_PQ_result_spec_uint64 ("rtransaction_id",
+                                    &rtransaction_id),
+      GNUNET_PQ_result_spec_end
     };
 
-    qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   
"lookup_payment_status_session_id",
-                                                   params,
-                                                   rs);
-  }
-  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
-  {
-    *paid = (0 != paid8);
-    *wired = (0 != wired8);
-  }
-  else
-  {
-    *paid = false; /* just to be safe(r) */
-    *wired = false; /* just to be safe(r) */
+    if (GNUNET_OK !=
+        GNUNET_PQ_extract_result (result,
+                                  rs,
+                                  i))
+    {
+      GNUNET_break (0);
+      ictx->err = true;
+      return;
+    }
+    if (0 >
+        TALER_amount_add (&ictx->refunded_amount,
+                          &ictx->refunded_amount,
+                          &acc))
+    {
+      GNUNET_break (0);
+      ictx->err = true;
+      return;
+    }
+    ictx->max_rtransaction_id = GNUNET_MAX (ictx->max_rtransaction_id,
+                                            rtransaction_id);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Found refund of %s\n",
+                TALER_amount2s (&acc));
   }
-  return qs;
 }
 
 
 /**
- * Closure for lookup_deposits_by_order_cb().
+ * Closure for #process_deposits_for_refund_cb().
  */
-struct LookupDepositsByOrderContext
+struct InsertRefundContext
 {
-
   /**
-   * Plugin context.
+   * Used to provide a connection to the db
    */
   struct PostgresClosure *pg;
 
   /**
-   * Function to call with all results.
+   * Amount to which increase the refund for this contract
    */
-  TALER_MERCHANTDB_DepositedCoinsCallback cb;
+  const struct TALER_Amount *refund;
 
   /**
-   * Closure for @e cb.
+   * Human-readable reason behind this refund
    */
-  void *cb_cls;
+  const char *reason;
 
   /**
-   * Set to the query result.
+   * Transaction status code.
    */
-  enum GNUNET_DB_QueryStatus qs;
+  enum TALER_MERCHANTDB_RefundStatus rs;
 };
 
 
 /**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
- *
- * @param cls of type `struct LookupDepositsByOrderContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_deposits_by_order_cb (void *cls,
-                             PGresult *result,
-                             unsigned int num_results)
-{
-  struct LookupDepositsByOrderContext *ldoc = cls;
-  struct PostgresClosure *pg = ldoc->pg;
-
-  for (unsigned int i = 0; i<num_results; i++)
-  {
-    uint64_t deposit_serial;
-    char *exchange_url;
-    struct TALER_MerchantWireHashP h_wire;
-    struct TALER_CoinSpendPublicKeyP coin_pub;
-    struct TALER_Amount amount_with_fee;
-    struct TALER_Amount deposit_fee;
-    struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_uint64 ("deposit_serial",
-                                    &deposit_serial),
-      GNUNET_PQ_result_spec_string ("exchange_url",
-                                    &exchange_url),
-      GNUNET_PQ_result_spec_auto_from_type ("h_wire",
-                                            &h_wire),
-      TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
-                                   &amount_with_fee),
-      TALER_PQ_RESULT_SPEC_AMOUNT ("deposit_fee",
-                                   &deposit_fee),
-      GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
-                                            &coin_pub),
-      GNUNET_PQ_result_spec_end
-    };
-
-    if (GNUNET_OK !=
-        GNUNET_PQ_extract_result (result,
-                                  rs,
-                                  i))
-    {
-      GNUNET_break (0);
-      ldoc->qs = GNUNET_DB_STATUS_HARD_ERROR;
-      return;
-    }
-    ldoc->cb (ldoc->cb_cls,
-              deposit_serial,
-              exchange_url,
-              &h_wire,
-              &amount_with_fee,
-              &deposit_fee,
-              &coin_pub);
-    GNUNET_PQ_cleanup_result (rs); /* technically useless here */
-  }
-  ldoc->qs = num_results;
-}
-
-
-/**
- * Retrieve details about coins that were deposited for an order.
- *
- * @param cls closure
- * @param order_serial identifies the order
- * @param cb function to call for each deposited coin
- * @param cb_cls closure for @a cb
- * @return transaction status
+ * Data extracted per coin.
  */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_deposits_by_order (void *cls,
-                                   uint64_t order_serial,
-                                   TALER_MERCHANTDB_DepositedCoinsCallback cb,
-                                   void *cb_cls)
+struct RefundCoinData
 {
-  struct PostgresClosure *pg = cls;
-  struct LookupDepositsByOrderContext ldoc = {
-    .pg = pg,
-    .cb = cb,
-    .cb_cls = cb_cls
-  };
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_uint64 (&order_serial),
-    GNUNET_PQ_query_param_end
-  };
-  enum GNUNET_DB_QueryStatus qs;
-
-  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
-                                             "lookup_deposits_by_order",
-                                             params,
-                                             &lookup_deposits_by_order_cb,
-                                             &ldoc);
-  if (qs < 0)
-    return qs;
-  return ldoc.qs;
-}
 
-
-/**
- * Closure for lookup_deposits_by_order_cb().
- */
-struct LookupTransferDetailsByOrderContext
-{
+  /**
+   * Public key of a coin.
+   */
+  struct TALER_CoinSpendPublicKeyP coin_pub;
 
   /**
-   * Plugin context.
+   * Amount deposited for this coin.
    */
-  struct PostgresClosure *pg;
+  struct TALER_Amount deposited_with_fee;
 
   /**
-   * Function to call with all results.
+   * Amount refunded already for this coin.
    */
-  TALER_MERCHANTDB_OrderTransferDetailsCallback cb;
+  struct TALER_Amount refund_amount;
 
   /**
-   * Closure for @e cb.
+   * Order serial (actually not really per-coin).
    */
-  void *cb_cls;
+  uint64_t order_serial;
 
   /**
-   * Set to the query result.
+   * Maximum rtransaction_id for this coin so far.
    */
-  enum GNUNET_DB_QueryStatus qs;
+  uint64_t max_rtransaction_id;
+
 };
 
 
@@ -1914,44 +1441,42 @@ struct LookupTransferDetailsByOrderContext
  * Function to be called with the results of a SELECT statement
  * that has returned @a num_results results.
  *
- * @param cls of type `struct LookupTransferDetailsByOrderContext *`
+ * @param cls closure, our `struct InsertRefundContext`
  * @param result the postgres result
  * @param num_results the number of results in @a result
  */
 static void
-lookup_transfer_details_by_order_cb (void *cls,
-                                     PGresult *result,
-                                     unsigned int num_results)
+process_deposits_for_refund_cb (void *cls,
+                                PGresult *result,
+                                unsigned int num_results)
 {
-  struct LookupTransferDetailsByOrderContext *ltdo = cls;
-  struct PostgresClosure *pg = ltdo->pg;
+  struct InsertRefundContext *ctx = cls;
+  struct PostgresClosure *pg = ctx->pg;
+  struct TALER_Amount current_refund;
+  struct RefundCoinData rcd[GNUNET_NZL (num_results)];
+  struct GNUNET_TIME_Timestamp now;
 
+  now = GNUNET_TIME_timestamp_get ();
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_amount_set_zero (ctx->refund->currency,
+                                        &current_refund));
+  memset (rcd, 0, sizeof (rcd));
+  /* Pass 1:  Collect amount of existing refunds into current_refund.
+   * Also store existing refunded amount for each deposit in deposit_refund. */
   for (unsigned int i = 0; i<num_results; i++)
   {
-    struct TALER_WireTransferIdentifierRawP wtid;
-    char *exchange_url;
-    uint64_t deposit_serial;
-    struct GNUNET_TIME_Timestamp execution_time;
-    struct TALER_Amount deposit_value;
-    struct TALER_Amount deposit_fee;
-    uint8_t transfer_confirmed;
     struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_uint64 ("deposit_serial",
-                                    &deposit_serial),
-      GNUNET_PQ_result_spec_timestamp ("deposit_timestamp",
-                                       &execution_time),
-      GNUNET_PQ_result_spec_string ("exchange_url",
-                                    &exchange_url),
-      GNUNET_PQ_result_spec_auto_from_type ("wtid",
-                                            &wtid),
-      TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_value",
-                                   &deposit_value),
-      TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_fee",
-                                   &deposit_fee),
-      GNUNET_PQ_result_spec_auto_from_type ("transfer_confirmed",
-                                            &transfer_confirmed),
-      GNUNET_PQ_result_spec_end
-    };
+      GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+                                            &rcd[i].coin_pub),
+      GNUNET_PQ_result_spec_uint64 ("order_serial",
+                                    &rcd[i].order_serial),
+      TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
+                                   &rcd[i].deposited_with_fee),
+      GNUNET_PQ_result_spec_end
+    };
+    struct FindRefundContext ictx = {
+      .pg = pg
+    };
 
     if (GNUNET_OK !=
         GNUNET_PQ_extract_result (result,
@@ -1959,142 +1484,284 @@ lookup_transfer_details_by_order_cb (void *cls,
                                   i))
     {
       GNUNET_break (0);
-      ltdo->qs = GNUNET_DB_STATUS_HARD_ERROR;
+      ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
       return;
     }
-    ltdo->cb (ltdo->cb_cls,
-              &wtid,
-              exchange_url,
-              execution_time,
-              &deposit_value,
-              &deposit_fee,
-              (0 != transfer_confirmed));
-    GNUNET_PQ_cleanup_result (rs); /* technically useless here */
+
+    {
+      enum GNUNET_DB_QueryStatus ires;
+      struct GNUNET_PQ_QueryParam params[] = {
+        GNUNET_PQ_query_param_auto_from_type (&rcd[i].coin_pub),
+        GNUNET_PQ_query_param_uint64 (&rcd[i].order_serial),
+        GNUNET_PQ_query_param_end
+      };
+
+      GNUNET_assert (GNUNET_OK ==
+                     TALER_amount_set_zero (ctx->refund->currency,
+                                            &ictx.refunded_amount));
+      ires = GNUNET_PQ_eval_prepared_multi_select (ctx->pg->conn,
+                                                   "find_refunds_by_coin",
+                                                   params,
+                                                   &process_refund_cb,
+                                                   &ictx);
+      if ( (ictx.err) ||
+           (GNUNET_DB_STATUS_HARD_ERROR == ires) )
+      {
+        GNUNET_break (0);
+        ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
+        return;
+      }
+      if (GNUNET_DB_STATUS_SOFT_ERROR == ires)
+      {
+        ctx->rs = TALER_MERCHANTDB_RS_SOFT_ERROR;
+        return;
+      }
+    }
+    if (0 >
+        TALER_amount_add (&current_refund,
+                          &current_refund,
+                          &ictx.refunded_amount))
+    {
+      GNUNET_break (0);
+      ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
+      return;
+    }
+    rcd[i].refund_amount = ictx.refunded_amount;
+    rcd[i].max_rtransaction_id = ictx.max_rtransaction_id;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Existing refund for coin %s is %s\n",
+                TALER_B2S (&rcd[i].coin_pub),
+                TALER_amount2s (&ictx.refunded_amount));
   }
-  ltdo->qs = num_results;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Total existing refund is %s\n",
+              TALER_amount2s (&current_refund));
+
+  /* stop immediately if we are 'done' === amount already
+   * refunded.  */
+  if (0 >= TALER_amount_cmp (ctx->refund,
+                             &current_refund))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Existing refund of %s at or above requested refund. Finished 
early.\n",
+                TALER_amount2s (&current_refund));
+    ctx->rs = TALER_MERCHANTDB_RS_SUCCESS;
+    return;
+  }
+
+  /* Phase 2:  Try to increase current refund until it matches desired refund 
*/
+  for (unsigned int i = 0; i<num_results; i++)
+  {
+    const struct TALER_Amount *increment;
+    struct TALER_Amount left;
+    struct TALER_Amount remaining_refund;
+
+    /* How much of the coin is left after the existing refunds? */
+    if (0 >
+        TALER_amount_subtract (&left,
+                               &rcd[i].deposited_with_fee,
+                               &rcd[i].refund_amount))
+    {
+      GNUNET_break (0);
+      ctx->rs = TALER_MERCHANTDB_RS_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 (&rcd[i].coin_pub));
+      continue;
+    }
+
+    rcd[i].max_rtransaction_id++;
+    /* How much of the refund is still to be paid back? */
+    if (0 >
+        TALER_amount_subtract (&remaining_refund,
+                               ctx->refund,
+                               &current_refund))
+    {
+      GNUNET_break (0);
+      ctx->rs = TALER_MERCHANTDB_RS_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 (0 >
+        TALER_amount_add (&current_refund,
+                          &current_refund,
+                          increment))
+    {
+      GNUNET_break (0);
+      ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
+      return;
+    }
+
+    /* actually run the refund */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Coin %s deposit amount is %s\n",
+                TALER_B2S (&rcd[i].coin_pub),
+                TALER_amount2s (&rcd[i].deposited_with_fee));
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Coin %s refund will be incremented by %s\n",
+                TALER_B2S (&rcd[i].coin_pub),
+                TALER_amount2s (increment));
+    {
+      enum GNUNET_DB_QueryStatus qs;
+      struct GNUNET_PQ_QueryParam params[] = {
+        GNUNET_PQ_query_param_uint64 (&rcd[i].order_serial),
+        GNUNET_PQ_query_param_uint64 (&rcd[i].max_rtransaction_id), /* already 
inc'ed */
+        GNUNET_PQ_query_param_timestamp (&now),
+        GNUNET_PQ_query_param_auto_from_type (&rcd[i].coin_pub),
+        GNUNET_PQ_query_param_string (ctx->reason),
+        TALER_PQ_query_param_amount (increment),
+        GNUNET_PQ_query_param_end
+      };
+
+      check_connection (pg);
+      qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                               "insert_refund",
+                                               params);
+      switch (qs)
+      {
+      case GNUNET_DB_STATUS_HARD_ERROR:
+        GNUNET_break (0);
+        ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
+        return;
+      case GNUNET_DB_STATUS_SOFT_ERROR:
+        ctx->rs = TALER_MERCHANTDB_RS_SOFT_ERROR;
+        return;
+      default:
+        ctx->rs = (enum TALER_MERCHANTDB_RefundStatus) qs;
+        break;
+      }
+    }
+
+    /* stop immediately if we are done */
+    if (0 == TALER_amount_cmp (ctx->refund,
+                               &current_refund))
+    {
+      ctx->rs = TALER_MERCHANTDB_RS_SUCCESS;
+      return;
+    }
+  }
+
+  /**
+   * We end up here if not 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_WARNING,
+              "The refund of %s is bigger than the order's value\n",
+              TALER_amount2s (ctx->refund));
+  ctx->rs = TALER_MERCHANTDB_RS_TOO_HIGH;
 }
 
 
 /**
- * Retrieve wire transfer details for all deposits associated with
- * a given @a order_serial.
+ * Function called when some backoffice staff decides to award or
+ * increase the refund on an existing contract.  This function
+ * MUST be called from within a transaction scope setup by the
+ * caller as it executes multiple SQL statements.
  *
  * @param cls closure
- * @param order_serial identifies the order
- * @param cb function called with the wire transfer details
- * @param cb_cls closure for @a cb
+ * @param instance_id instance identifier
+ * @param order_id the order to increase the refund for
+ * @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_NO_RESULTS if @a refund is ABOVE the 
amount we
+ *        were originally paid and thus the transaction failed;
+ *        #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if the request is valid,
+ *        regardless of whether it actually increased the refund beyond
+ *        what was already refunded (idempotency!)
  */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_transfer_details_by_order (
-  void *cls,
-  uint64_t order_serial,
-  TALER_MERCHANTDB_OrderTransferDetailsCallback cb,
-  void *cb_cls)
+static enum TALER_MERCHANTDB_RefundStatus
+postgres_increase_refund (void *cls,
+                          const char *instance_id,
+                          const char *order_id,
+                          const struct TALER_Amount *refund,
+                          const char *reason)
 {
   struct PostgresClosure *pg = cls;
-  struct LookupTransferDetailsByOrderContext ltdo = {
-    .pg = pg,
-    .cb = cb,
-    .cb_cls = cb_cls
-  };
+  enum GNUNET_DB_QueryStatus qs;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_uint64 (&order_serial),
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_string (order_id),
     GNUNET_PQ_query_param_end
   };
-  enum GNUNET_DB_QueryStatus qs;
+  struct InsertRefundContext ctx = {
+    .pg = pg,
+    .refund = refund,
+    .reason = reason
+  };
 
-  qs = GNUNET_PQ_eval_prepared_multi_select (
-    pg->conn,
-    "lookup_transfer_details_by_order",
-    params,
-    &lookup_transfer_details_by_order_cb,
-    &ltdo);
-  if (qs < 0)
-    return qs;
-  return ltdo.qs;
-}
-
-
-/**
- * Insert wire transfer details for a deposit.
- *
- * @param cls closure
- * @param deposit_serial serial number of the deposit
- * @param dd deposit transfer data from the exchange to store
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_deposit_to_transfer (
-  void *cls,
-  uint64_t deposit_serial,
-  const struct TALER_EXCHANGE_DepositData *dd)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_uint64 (&deposit_serial),
-    TALER_PQ_query_param_amount (&dd->coin_contribution),
-    GNUNET_PQ_query_param_timestamp (&dd->execution_time),
-    GNUNET_PQ_query_param_auto_from_type (&dd->exchange_sig),
-    GNUNET_PQ_query_param_auto_from_type (&dd->exchange_pub),
-    GNUNET_PQ_query_param_auto_from_type (&dd->wtid),
-    GNUNET_PQ_query_param_end
-  };
-
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "insert_deposit_to_transfer",
-                                             params);
-}
-
-
-/**
- * Set 'wired' status for an order to 'true'.
- *
- * @param cls closure
- * @param order_serial serial number of the order
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_mark_order_wired (void *cls,
-                           uint64_t order_serial)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_uint64 (&order_serial),
-    GNUNET_PQ_query_param_end
-  };
-
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "mark_order_wired",
-                                             params);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Asked to refund %s on order %s\n",
+              TALER_amount2s (refund),
+              order_id);
+  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+                                             "find_deposits_for_refund",
+                                             params,
+                                             &process_deposits_for_refund_cb,
+                                             &ctx);
+  switch (qs)
+  {
+  case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+    /* never paid, means we clearly cannot refund anything */
+    return TALER_MERCHANTDB_RS_NO_SUCH_ORDER;
+  case GNUNET_DB_STATUS_SOFT_ERROR:
+    return TALER_MERCHANTDB_RS_SOFT_ERROR;
+  case GNUNET_DB_STATUS_HARD_ERROR:
+    return TALER_MERCHANTDB_RS_HARD_ERROR;
+  default:
+    /* Got one or more deposits */
+    return ctx.rs;
+  }
 }
 
 
 /**
- * Closure for #process_refund_cb().
+ * Closure for #lookup_refunds_detailed_cb().
  */
-struct FindRefundContext
+struct LookupRefundsDetailedContext
 {
-
   /**
-   * Plugin context.
+   * Function to call for each refund.
    */
-  struct PostgresClosure *pg;
+  TALER_MERCHANTDB_RefundDetailCallback rc;
 
   /**
-   * Updated to reflect total amount refunded so far.
+   * Closure for @e rc.
    */
-  struct TALER_Amount refunded_amount;
+  void *rc_cls;
 
   /**
-   * Set to the largest refund transaction ID encountered.
+   * Plugin context.
    */
-  uint64_t max_rtransaction_id;
+  struct PostgresClosure *pg;
 
   /**
-   * Set to true on hard errors.
+   * Transaction result.
    */
-  bool err;
+  enum GNUNET_DB_QueryStatus qs;
 };
 
 
@@ -2102,28 +1769,45 @@ struct FindRefundContext
  * 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 cls of type `struct GetRefundsContext *`
  * @param result the postgres result
  * @param num_results the number of results in @a result
  */
 static void
-process_refund_cb (void *cls,
-                   PGresult *result,
-                   unsigned int num_results)
+lookup_refunds_detailed_cb (void *cls,
+                            PGresult *result,
+                            unsigned int num_results)
 {
-  struct FindRefundContext *ictx = cls;
-  struct PostgresClosure *pg = ictx->pg;
+  struct LookupRefundsDetailedContext *lrdc = cls;
+  struct PostgresClosure *pg = lrdc->pg;
 
   for (unsigned int i = 0; i<num_results; i++)
   {
-    /* Sum up existing refunds */
-    struct TALER_Amount acc;
+    uint64_t refund_serial;
+    struct GNUNET_TIME_Timestamp timestamp;
+    struct TALER_CoinSpendPublicKeyP coin_pub;
     uint64_t rtransaction_id;
+    struct TALER_Amount refund_amount;
+    char *reason;
+    char *exchange_url;
+    uint8_t pending8;
     struct GNUNET_PQ_ResultSpec rs[] = {
-      TALER_PQ_RESULT_SPEC_AMOUNT ("refund_amount",
-                                   &acc),
+      GNUNET_PQ_result_spec_uint64 ("refund_serial",
+                                    &refund_serial),
+      GNUNET_PQ_result_spec_timestamp ("refund_timestamp",
+                                       &timestamp),
+      GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+                                            &coin_pub),
+      GNUNET_PQ_result_spec_string ("exchange_url",
+                                    &exchange_url),
       GNUNET_PQ_result_spec_uint64 ("rtransaction_id",
                                     &rtransaction_id),
+      GNUNET_PQ_result_spec_string ("reason",
+                                    &reason),
+      TALER_PQ_RESULT_SPEC_AMOUNT ("refund_amount",
+                                   &refund_amount),
+      GNUNET_PQ_result_spec_auto_from_type ("pending",
+                                            &pending8),
       GNUNET_PQ_result_spec_end
     };
 
@@ -2133,1040 +1817,946 @@ process_refund_cb (void *cls,
                                   i))
     {
       GNUNET_break (0);
-      ictx->err = true;
-      return;
-    }
-    if (0 >
-        TALER_amount_add (&ictx->refunded_amount,
-                          &ictx->refunded_amount,
-                          &acc))
-    {
-      GNUNET_break (0);
-      ictx->err = true;
+      lrdc->qs = GNUNET_DB_STATUS_HARD_ERROR;
       return;
     }
-    ictx->max_rtransaction_id = GNUNET_MAX (ictx->max_rtransaction_id,
-                                            rtransaction_id);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Found refund of %s\n",
-                TALER_amount2s (&acc));
+    lrdc->rc (lrdc->rc_cls,
+              refund_serial,
+              timestamp,
+              &coin_pub,
+              exchange_url,
+              rtransaction_id,
+              reason,
+              &refund_amount,
+              0 != pending8);
+    GNUNET_PQ_cleanup_result (rs);
   }
+  lrdc->qs = num_results;
 }
 
 
 /**
- * Closure for #process_deposits_for_refund_cb().
+ * Obtain detailed refund data associated with a contract.
+ *
+ * @param cls closure, typically a connection to the db
+ * @param instance_id instance to lookup refunds for
+ * @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
  */
-struct InsertRefundContext
+static enum GNUNET_DB_QueryStatus
+postgres_lookup_refunds_detailed (
+  void *cls,
+  const char *instance_id,
+  const struct TALER_PrivateContractHashP *h_contract_terms,
+  TALER_MERCHANTDB_RefundDetailCallback rc,
+  void *rc_cls)
 {
-  /**
-   * 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;
-
-  /**
-   * Human-readable reason behind this refund
-   */
-  const char *reason;
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+    GNUNET_PQ_query_param_end
+  };
+  struct LookupRefundsDetailedContext lrdc = {
+    .rc  = rc,
+    .rc_cls = rc_cls,
+    .pg = pg
+  };
+  enum GNUNET_DB_QueryStatus qs;
 
-  /**
-   * Transaction status code.
-   */
-  enum TALER_MERCHANTDB_RefundStatus rs;
-};
+  /* no preflight check here, run in transaction by caller! */
+  TALER_LOG_DEBUG ("Looking for refund %s + %s\n",
+                   GNUNET_h2s (&h_contract_terms->hash),
+                   instance_id);
+  check_connection (pg);
+  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+                                             "lookup_refunds_detailed",
+                                             params,
+                                             &lookup_refunds_detailed_cb,
+                                             &lrdc);
+  if (0 >= qs)
+    return qs;
+  return lrdc.qs;
+}
 
 
 /**
- * Data extracted per coin.
+ * Insert refund proof data from the exchange into the database.
+ *
+ * @param cls closure
+ * @param refund_serial serial number of the refund
+ * @param exchange_sig signature from exchange that coin was refunded
+ * @param exchange_pub signing key that was used for @a exchange_sig
+ * @return transaction status
  */
-struct RefundCoinData
+static enum GNUNET_DB_QueryStatus
+postgres_insert_refund_proof (
+  void *cls,
+  uint64_t refund_serial,
+  const struct TALER_ExchangeSignatureP *exchange_sig,
+  const struct TALER_ExchangePublicKeyP *exchange_pub)
 {
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_uint64 (&refund_serial),
+    GNUNET_PQ_query_param_auto_from_type (exchange_sig),
+    GNUNET_PQ_query_param_auto_from_type (exchange_pub),
+    GNUNET_PQ_query_param_end
+  };
 
-  /**
-   * Public key of a coin.
-   */
-  struct TALER_CoinSpendPublicKeyP coin_pub;
-
-  /**
-   * Amount deposited for this coin.
-   */
-  struct TALER_Amount deposited_with_fee;
-
-  /**
-   * Amount refunded already for this coin.
-   */
-  struct TALER_Amount refund_amount;
-
-  /**
-   * Order serial (actually not really per-coin).
-   */
-  uint64_t order_serial;
-
-  /**
-   * Maximum rtransaction_id for this coin so far.
-   */
-  uint64_t max_rtransaction_id;
-
-};
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "insert_refund_proof",
+                                             params);
+}
 
 
 /**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
+ * Lookup refund proof data.
  *
- * @param cls closure, our `struct InsertRefundContext`
- * @param result the postgres result
- * @param num_results the number of results in @a result
+ * @param cls closure
+ * @param refund_serial serial number of the refund
+ * @param[out] exchange_sig set to signature from exchange
+ * @param[out] exchange_pub signing key that was used for @a exchange_sig
+ * @return transaction status
  */
-static void
-process_deposits_for_refund_cb (void *cls,
-                                PGresult *result,
-                                unsigned int num_results)
+static enum GNUNET_DB_QueryStatus
+postgres_lookup_refund_proof (void *cls,
+                              uint64_t refund_serial,
+                              struct TALER_ExchangeSignatureP *exchange_sig,
+                              struct TALER_ExchangePublicKeyP *exchange_pub)
 {
-  struct InsertRefundContext *ctx = cls;
-  struct PostgresClosure *pg = ctx->pg;
-  struct TALER_Amount current_refund;
-  struct RefundCoinData rcd[GNUNET_NZL (num_results)];
-  struct GNUNET_TIME_Timestamp now;
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_uint64 (&refund_serial),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_auto_from_type ("exchange_sig",
+                                          exchange_sig),
+    GNUNET_PQ_result_spec_auto_from_type ("exchange_pub",
+                                          exchange_pub),
+    GNUNET_PQ_result_spec_end
+  };
 
-  now = GNUNET_TIME_timestamp_get ();
-  GNUNET_assert (GNUNET_OK ==
-                 TALER_amount_set_zero (ctx->refund->currency,
-                                        &current_refund));
-  memset (rcd, 0, sizeof (rcd));
-  /* Pass 1:  Collect amount of existing refunds into current_refund.
-   * Also store existing refunded amount for each deposit in deposit_refund. */
-  for (unsigned int i = 0; i<num_results; i++)
-  {
-    struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
-                                            &rcd[i].coin_pub),
-      GNUNET_PQ_result_spec_uint64 ("order_serial",
-                                    &rcd[i].order_serial),
-      TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
-                                   &rcd[i].deposited_with_fee),
-      GNUNET_PQ_result_spec_end
-    };
-    struct FindRefundContext ictx = {
-      .pg = pg
-    };
+  check_connection (pg);
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "lookup_refund_proof",
+                                                   params,
+                                                   rs);
+}
 
-    if (GNUNET_OK !=
-        GNUNET_PQ_extract_result (result,
-                                  rs,
-                                  i))
-    {
-      GNUNET_break (0);
-      ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
-      return;
-    }
 
-    {
-      enum GNUNET_DB_QueryStatus ires;
-      struct GNUNET_PQ_QueryParam params[] = {
-        GNUNET_PQ_query_param_auto_from_type (&rcd[i].coin_pub),
-        GNUNET_PQ_query_param_uint64 (&rcd[i].order_serial),
-        GNUNET_PQ_query_param_end
-      };
+/**
+ * Retrieve the order ID that was used to pay for a resource within a session.
+ *
+ * @param cls closure
+ * @param instance_id identifying the instance
+ * @param fulfillment_url URL that canonically identifies the resource
+ *        being paid for
+ * @param session_id session id
+ * @param[out] order_id where to store the order ID that was used when
+ *             paying for the resource URL
+ * @return transaction status
+ */
+enum GNUNET_DB_QueryStatus
+postgres_lookup_order_by_fulfillment (void *cls,
+                                      const char *instance_id,
+                                      const char *fulfillment_url,
+                                      const char *session_id,
+                                      char **order_id)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_string (fulfillment_url),
+    GNUNET_PQ_query_param_string (session_id),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_string ("order_id",
+                                  order_id),
+    GNUNET_PQ_result_spec_end
+  };
 
-      GNUNET_assert (GNUNET_OK ==
-                     TALER_amount_set_zero (ctx->refund->currency,
-                                            &ictx.refunded_amount));
-      ires = GNUNET_PQ_eval_prepared_multi_select (ctx->pg->conn,
-                                                   "find_refunds_by_coin",
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   
"lookup_order_by_fulfillment",
                                                    params,
-                                                   &process_refund_cb,
-                                                   &ictx);
-      if ( (ictx.err) ||
-           (GNUNET_DB_STATUS_HARD_ERROR == ires) )
-      {
-        GNUNET_break (0);
-        ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
-        return;
-      }
-      if (GNUNET_DB_STATUS_SOFT_ERROR == ires)
-      {
-        ctx->rs = TALER_MERCHANTDB_RS_SOFT_ERROR;
-        return;
-      }
-    }
-    if (0 >
-        TALER_amount_add (&current_refund,
-                          &current_refund,
-                          &ictx.refunded_amount))
-    {
-      GNUNET_break (0);
-      ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
-      return;
-    }
-    rcd[i].refund_amount = ictx.refunded_amount;
-    rcd[i].max_rtransaction_id = ictx.max_rtransaction_id;
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Existing refund for coin %s is %s\n",
-                TALER_B2S (&rcd[i].coin_pub),
-                TALER_amount2s (&ictx.refunded_amount));
-  }
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Total existing refund is %s\n",
-              TALER_amount2s (&current_refund));
+                                                   rs);
+}
 
-  /* stop immediately if we are 'done' === amount already
-   * refunded.  */
-  if (0 >= TALER_amount_cmp (ctx->refund,
-                             &current_refund))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "Existing refund of %s at or above requested refund. Finished 
early.\n",
-                TALER_amount2s (&current_refund));
-    ctx->rs = TALER_MERCHANTDB_RS_SUCCESS;
-    return;
-  }
 
-  /* Phase 2:  Try to increase current refund until it matches desired refund 
*/
-  for (unsigned int i = 0; i<num_results; i++)
-  {
-    const struct TALER_Amount *increment;
-    struct TALER_Amount left;
-    struct TALER_Amount remaining_refund;
+/**
+ * Insert information about a wire transfer the merchant has received.
+ *
+ * @param cls closure
+ * @param instance_id the instance that received the transfer
+ * @param exchange_url which exchange made the transfer
+ * @param wtid identifier of the wire transfer
+ * @param credit_amount how much did we receive
+ * @param payto_uri what is the merchant's bank account that received the 
transfer
+ * @param confirmed whether the transfer was confirmed by the merchant or
+ *                  was merely claimed by the exchange at this point
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_insert_transfer (
+  void *cls,
+  const char *instance_id,
+  const char *exchange_url,
+  const struct TALER_WireTransferIdentifierRawP *wtid,
+  const struct TALER_Amount *credit_amount,
+  const char *payto_uri,
+  bool confirmed)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (exchange_url),
+    GNUNET_PQ_query_param_auto_from_type (wtid),
+    TALER_PQ_query_param_amount (credit_amount),
+    GNUNET_PQ_query_param_string (payto_uri),
+    GNUNET_PQ_query_param_bool (confirmed),
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_end
+  };
 
-    /* How much of the coin is left after the existing refunds? */
-    if (0 >
-        TALER_amount_subtract (&left,
-                               &rcd[i].deposited_with_fee,
-                               &rcd[i].refund_amount))
-    {
-      GNUNET_break (0);
-      ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
-      return;
-    }
+  check_connection (pg);
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "insert_transfer",
+                                             params);
+}
 
-    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 (&rcd[i].coin_pub));
-      continue;
-    }
 
-    rcd[i].max_rtransaction_id++;
-    /* How much of the refund is still to be paid back? */
-    if (0 >
-        TALER_amount_subtract (&remaining_refund,
-                               ctx->refund,
-                               &current_refund))
-    {
-      GNUNET_break (0);
-      ctx->rs = TALER_MERCHANTDB_RS_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 (0 >
-        TALER_amount_add (&current_refund,
-                          &current_refund,
-                          increment))
-    {
-      GNUNET_break (0);
-      ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
-      return;
-    }
-
-    /* actually run the refund */
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Coin %s deposit amount is %s\n",
-                TALER_B2S (&rcd[i].coin_pub),
-                TALER_amount2s (&rcd[i].deposited_with_fee));
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Coin %s refund will be incremented by %s\n",
-                TALER_B2S (&rcd[i].coin_pub),
-                TALER_amount2s (increment));
-    {
-      enum GNUNET_DB_QueryStatus qs;
-      struct GNUNET_PQ_QueryParam params[] = {
-        GNUNET_PQ_query_param_uint64 (&rcd[i].order_serial),
-        GNUNET_PQ_query_param_uint64 (&rcd[i].max_rtransaction_id), /* already 
inc'ed */
-        GNUNET_PQ_query_param_timestamp (&now),
-        GNUNET_PQ_query_param_auto_from_type (&rcd[i].coin_pub),
-        GNUNET_PQ_query_param_string (ctx->reason),
-        TALER_PQ_query_param_amount (increment),
-        GNUNET_PQ_query_param_end
-      };
-
-      check_connection (pg);
-      qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                               "insert_refund",
-                                               params);
-      switch (qs)
-      {
-      case GNUNET_DB_STATUS_HARD_ERROR:
-        GNUNET_break (0);
-        ctx->rs = TALER_MERCHANTDB_RS_HARD_ERROR;
-        return;
-      case GNUNET_DB_STATUS_SOFT_ERROR:
-        ctx->rs = TALER_MERCHANTDB_RS_SOFT_ERROR;
-        return;
-      default:
-        ctx->rs = (enum TALER_MERCHANTDB_RefundStatus) qs;
-        break;
-      }
-    }
-
-    /* stop immediately if we are done */
-    if (0 == TALER_amount_cmp (ctx->refund,
-                               &current_refund))
-    {
-      ctx->rs = TALER_MERCHANTDB_RS_SUCCESS;
-      return;
-    }
-  }
+/**
+ * Delete information about a transfer. Note that transfers
+ * confirmed by the exchange cannot be deleted anymore.
+ *
+ * @param cls closure
+ * @param instance_id instance to delete transfer of
+ * @param transfer_serial_id transfer to delete
+ * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
+ *           if deletion is prohibited OR transfer is unknown
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_delete_transfer (void *cls,
+                          const char *instance_id,
+                          uint64_t transfer_serial_id)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_uint64 (&transfer_serial_id),
+    GNUNET_PQ_query_param_end
+  };
 
-  /**
-   * We end up here if not 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_WARNING,
-              "The refund of %s is bigger than the order's value\n",
-              TALER_amount2s (ctx->refund));
-  ctx->rs = TALER_MERCHANTDB_RS_TOO_HIGH;
+  check_connection (pg);
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "delete_transfer",
+                                             params);
 }
 
 
 /**
- * Function called when some backoffice staff decides to award or
- * increase the refund on an existing contract.  This function
- * MUST be called from within a transaction scope setup by the
- * caller as it executes multiple SQL statements.
+ * Check if information about a transfer exists with the
+ * backend.  Returns no data, only the query status.
  *
  * @param cls closure
- * @param instance_id instance identifier
- * @param order_id the order to increase the refund for
- * @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_NO_RESULTS if @a refund is ABOVE the 
amount we
- *        were originally paid and thus the transaction failed;
- *        #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if the request is valid,
- *        regardless of whether it actually increased the refund beyond
- *        what was already refunded (idempotency!)
+ * @param instance_id instance to delete transfer of
+ * @param transfer_serial_id transfer to delete
+ * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
+ *           if the transfer record exists
  */
-static enum TALER_MERCHANTDB_RefundStatus
-postgres_increase_refund (void *cls,
-                          const char *instance_id,
-                          const char *order_id,
-                          const struct TALER_Amount *refund,
-                          const char *reason)
+static enum GNUNET_DB_QueryStatus
+postgres_check_transfer_exists (void *cls,
+                                const char *instance_id,
+                                uint64_t transfer_serial_id)
 {
   struct PostgresClosure *pg = cls;
-  enum GNUNET_DB_QueryStatus qs;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_string (order_id),
+    GNUNET_PQ_query_param_uint64 (&transfer_serial_id),
     GNUNET_PQ_query_param_end
   };
-  struct InsertRefundContext ctx = {
-    .pg = pg,
-    .refund = refund,
-    .reason = reason
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_end
   };
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Asked to refund %s on order %s\n",
-              TALER_amount2s (refund),
-              order_id);
-  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
-                                             "find_deposits_for_refund",
-                                             params,
-                                             &process_deposits_for_refund_cb,
-                                             &ctx);
-  switch (qs)
-  {
-  case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
-    /* never paid, means we clearly cannot refund anything */
-    return TALER_MERCHANTDB_RS_NO_SUCH_ORDER;
-  case GNUNET_DB_STATUS_SOFT_ERROR:
-    return TALER_MERCHANTDB_RS_SOFT_ERROR;
-  case GNUNET_DB_STATUS_HARD_ERROR:
-    return TALER_MERCHANTDB_RS_HARD_ERROR;
-  default:
-    /* Got one or more deposits */
-    return ctx.rs;
-  }
+  check_connection (pg);
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "check_transfer_exists",
+                                                   params,
+                                                   rs);
 }
 
 
 /**
- * Closure for #lookup_refunds_detailed_cb().
+ * Lookup account serial by payto URI.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup the account from
+ * @param payto_uri what is the merchant's bank account to lookup
+ * @param[out] account_serial serial number of the account
+ * @return transaction status
  */
-struct LookupRefundsDetailedContext
+static enum GNUNET_DB_QueryStatus
+postgres_lookup_account (void *cls,
+                         const char *instance_id,
+                         const char *payto_uri,
+                         uint64_t *account_serial)
 {
-  /**
-   * Function to call for each refund.
-   */
-  TALER_MERCHANTDB_RefundDetailCallback rc;
-
-  /**
-   * Closure for @e rc.
-   */
-  void *rc_cls;
-
-  /**
-   * Plugin context.
-   */
-  struct PostgresClosure *pg;
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_string (payto_uri),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_uint64 ("account_serial",
+                                  account_serial),
+    GNUNET_PQ_result_spec_end
+  };
 
-  /**
-   * Transaction result.
-   */
-  enum GNUNET_DB_QueryStatus qs;
-};
+  check_connection (pg);
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "lookup_account",
+                                                   params,
+                                                   rs);
+}
 
 
 /**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
+ * Insert information about a wire transfer the merchant has received.
  *
- * @param cls of type `struct GetRefundsContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
+ * @param cls closure
+ * @param instance_id instance to provide transfer details for
+ * @param exchange_url which exchange made the transfer
+ * @param payto_uri what is the merchant's bank account that received the 
transfer
+ * @param wtid identifier of the wire transfer
+ * @param td transfer details to store
+ * @return transaction status,
+ *   #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the @a wtid and @a exchange_uri 
are not known for this @a instance_id
+ *   #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT on success
  */
-static void
-lookup_refunds_detailed_cb (void *cls,
-                            PGresult *result,
-                            unsigned int num_results)
-{
-  struct LookupRefundsDetailedContext *lrdc = cls;
-  struct PostgresClosure *pg = lrdc->pg;
-
-  for (unsigned int i = 0; i<num_results; i++)
-  {
-    uint64_t refund_serial;
-    struct GNUNET_TIME_Timestamp timestamp;
-    struct TALER_CoinSpendPublicKeyP coin_pub;
-    uint64_t rtransaction_id;
-    struct TALER_Amount refund_amount;
-    char *reason;
-    char *exchange_url;
-    uint8_t pending8;
+static enum GNUNET_DB_QueryStatus
+postgres_insert_transfer_details (
+  void *cls,
+  const char *instance_id,
+  const char *exchange_url,
+  const char *payto_uri,
+  const struct TALER_WireTransferIdentifierRawP *wtid,
+  const struct TALER_EXCHANGE_TransferData *td)
+{
+  struct PostgresClosure *pg = cls;
+  enum GNUNET_DB_QueryStatus qs;
+  uint64_t credit_serial;
+  unsigned int retries;
+
+  retries = 0;
+  check_connection (pg);
+RETRY:
+  if (MAX_RETRIES < ++retries)
+    return GNUNET_DB_STATUS_SOFT_ERROR;
+  if (GNUNET_OK !=
+      postgres_start_read_committed (pg,
+                                     "insert transfer details"))
+  {
+    GNUNET_break (0);
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  }
+
+  /* lookup credit serial */
+  {
+    struct GNUNET_PQ_QueryParam params[] = {
+      GNUNET_PQ_query_param_string (exchange_url),
+      GNUNET_PQ_query_param_string (payto_uri),
+      GNUNET_PQ_query_param_string (instance_id),
+      GNUNET_PQ_query_param_auto_from_type (wtid),
+      GNUNET_PQ_query_param_end
+    };
     struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_uint64 ("refund_serial",
-                                    &refund_serial),
-      GNUNET_PQ_result_spec_timestamp ("refund_timestamp",
-                                       &timestamp),
-      GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
-                                            &coin_pub),
-      GNUNET_PQ_result_spec_string ("exchange_url",
-                                    &exchange_url),
-      GNUNET_PQ_result_spec_uint64 ("rtransaction_id",
-                                    &rtransaction_id),
-      GNUNET_PQ_result_spec_string ("reason",
-                                    &reason),
-      TALER_PQ_RESULT_SPEC_AMOUNT ("refund_amount",
-                                   &refund_amount),
-      GNUNET_PQ_result_spec_auto_from_type ("pending",
-                                            &pending8),
+      GNUNET_PQ_result_spec_uint64 ("credit_serial",
+                                    &credit_serial),
       GNUNET_PQ_result_spec_end
     };
 
-    if (GNUNET_OK !=
-        GNUNET_PQ_extract_result (result,
-                                  rs,
-                                  i))
+    qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "lookup_credit_serial",
+                                                   params,
+                                                   rs);
+    if (0 > qs)
     {
-      GNUNET_break (0);
-      lrdc->qs = GNUNET_DB_STATUS_HARD_ERROR;
-      return;
+      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+      postgres_rollback (pg);
+      if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+        goto RETRY;
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                  "'lookup_credit_serial' for account %s and amount %s failed 
with status %d\n",
+                  payto_uri,
+                  TALER_amount2s (&td->total_amount),
+                  qs);
+      return qs;
+    }
+    if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+    {
+      postgres_rollback (pg);
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                  "'lookup_credit_serial' for account %s failed with transfer 
unknown\n",
+                  payto_uri);
+      return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
     }
-    lrdc->rc (lrdc->rc_cls,
-              refund_serial,
-              timestamp,
-              &coin_pub,
-              exchange_url,
-              rtransaction_id,
-              reason,
-              &refund_amount,
-              0 != pending8);
-    GNUNET_PQ_cleanup_result (rs);
   }
-  lrdc->qs = num_results;
+
+  /* update merchant_transfer_signatures table */
+  {
+    struct GNUNET_PQ_QueryParam params[] = {
+      GNUNET_PQ_query_param_uint64 (&credit_serial),
+      TALER_PQ_query_param_amount (&td->total_amount),
+      TALER_PQ_query_param_amount (&td->wire_fee),
+      GNUNET_PQ_query_param_timestamp (&td->execution_time),
+      GNUNET_PQ_query_param_auto_from_type (&td->exchange_sig),
+      GNUNET_PQ_query_param_auto_from_type (&td->exchange_pub),
+      GNUNET_PQ_query_param_end
+    };
+
+    qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "insert_transfer_signature",
+                                             params);
+    if (0 > qs)
+    {
+      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+      postgres_rollback (pg);
+      if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+        goto RETRY;
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                  "'insert_transfer_signature' failed with status %d\n",
+                  qs);
+      return qs;
+    }
+    if (0 == qs)
+    {
+      postgres_rollback (pg);
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                  "'insert_transfer_signature' failed with status %d\n",
+                  qs);
+      return GNUNET_DB_STATUS_HARD_ERROR;
+    }
+  }
+
+  /* Update transfer-coin association table */
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Updating transfer-coin association table\n");
+  for (unsigned int i = 0; i<td->details_length; i++)
+  {
+    const struct TALER_TrackTransferDetails *d = &td->details[i];
+    uint64_t i64 = (uint64_t) i;
+    struct GNUNET_PQ_QueryParam params[] = {
+      GNUNET_PQ_query_param_uint64 (&credit_serial),
+      GNUNET_PQ_query_param_uint64 (&i64),
+      TALER_PQ_query_param_amount (&d->coin_value),
+      TALER_PQ_query_param_amount (&d->coin_fee), /* deposit fee */
+      GNUNET_PQ_query_param_auto_from_type (&d->coin_pub),
+      GNUNET_PQ_query_param_auto_from_type (&d->h_contract_terms),
+      GNUNET_PQ_query_param_string (instance_id),
+      GNUNET_PQ_query_param_end
+    };
+
+    qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "insert_transfer_to_coin_mapping",
+                                             params);
+    if (0 > qs)
+    {
+      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+      postgres_rollback (pg);
+      if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+        goto RETRY;
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                  "'insert_transfer_to_coin_mapping' failed with status %d\n",
+                  qs);
+      return qs;
+    }
+    if (0 == qs)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "'insert_transfer_to_coin_mapping' failed at %u: deposit 
unknown\n",
+                  i);
+    }
+  }
+  /* Update merchant_contract_terms 'wired' status: for all coins
+     that were wired, set the respective order's "wired" status to
+     true, *if* all other deposited coins associated with that order
+     have also been wired (this time or earlier) */
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Updating contract terms 'wired' status\n");
+  for (unsigned int i = 0; i<td->details_length; i++)
+  {
+    const struct TALER_TrackTransferDetails *d = &td->details[i];
+    struct GNUNET_PQ_QueryParam params[] = {
+      GNUNET_PQ_query_param_auto_from_type (&d->coin_pub),
+      GNUNET_PQ_query_param_end
+    };
+
+    qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "update_wired_by_coin_pub",
+                                             params);
+    if (0 > qs)
+    {
+      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+      postgres_rollback (pg);
+      if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+        goto RETRY;
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                  "'update_wired_by_coin_pub' failed with status %d\n",
+                  qs);
+      return qs;
+    }
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Committing transaction...\n");
+  qs = postgres_commit (pg);
+  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+    return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
+  GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+  if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+    goto RETRY;
+  return qs;
 }
 
 
 /**
- * Obtain detailed refund data associated with a contract.
+ * Obtain information about wire fees charged by an exchange,
+ * including signature (so we have proof).
  *
- * @param cls closure, typically a connection to the db
- * @param instance_id instance to lookup refunds for
- * @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
+ * @param cls closure
+ * @param master_pub public key of the exchange
+ * @param wire_method the wire method
+ * @param contract_date date of the contract to use for the lookup
+ * @param[out] fees wire fees charged
+ * @param[out] start_date start of fee being used
+ * @param[out] end_date end of fee being used
+ * @param[out] master_sig signature of exchange over fee structure
+ * @return transaction status code
  */
 static enum GNUNET_DB_QueryStatus
-postgres_lookup_refunds_detailed (
-  void *cls,
-  const char *instance_id,
-  const struct TALER_PrivateContractHashP *h_contract_terms,
-  TALER_MERCHANTDB_RefundDetailCallback rc,
-  void *rc_cls)
+postgres_lookup_wire_fee (void *cls,
+                          const struct TALER_MasterPublicKeyP *master_pub,
+                          const char *wire_method,
+                          struct GNUNET_TIME_Timestamp contract_date,
+                          struct TALER_WireFeeSet *fees,
+                          struct GNUNET_TIME_Timestamp *start_date,
+                          struct GNUNET_TIME_Timestamp *end_date,
+                          struct TALER_MasterSignatureP *master_sig)
 {
   struct PostgresClosure *pg = cls;
+  struct GNUNET_HashCode h_wire_method;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+    GNUNET_PQ_query_param_auto_from_type (master_pub),
+    GNUNET_PQ_query_param_auto_from_type (&h_wire_method),
+    GNUNET_PQ_query_param_timestamp (&contract_date),
     GNUNET_PQ_query_param_end
   };
-  struct LookupRefundsDetailedContext lrdc = {
-    .rc  = rc,
-    .rc_cls = rc_cls,
-    .pg = pg
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
+                                 &fees->wire),
+    TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
+                                 &fees->closing),
+    GNUNET_PQ_result_spec_timestamp ("start_date",
+                                     start_date),
+    GNUNET_PQ_result_spec_timestamp ("end_date",
+                                     end_date),
+    GNUNET_PQ_result_spec_auto_from_type ("master_sig",
+                                          master_sig),
+    GNUNET_PQ_result_spec_end
   };
-  enum GNUNET_DB_QueryStatus qs;
 
-  /* no preflight check here, run in transaction by caller! */
-  TALER_LOG_DEBUG ("Looking for refund %s + %s\n",
-                   GNUNET_h2s (&h_contract_terms->hash),
-                   instance_id);
   check_connection (pg);
-  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
-                                             "lookup_refunds_detailed",
-                                             params,
-                                             &lookup_refunds_detailed_cb,
-                                             &lrdc);
-  if (0 >= qs)
-    return qs;
-  return lrdc.qs;
+  GNUNET_CRYPTO_hash (wire_method,
+                      strlen (wire_method) + 1,
+                      &h_wire_method);
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "lookup_wire_fee",
+                                                   params,
+                                                   rs);
 }
 
 
 /**
- * Insert refund proof data from the exchange into the database.
- *
- * @param cls closure
- * @param refund_serial serial number of the refund
- * @param exchange_sig signature from exchange that coin was refunded
- * @param exchange_pub signing key that was used for @a exchange_sig
- * @return transaction status
+ * Closure for #lookup_deposits_by_contract_and_coin_cb().
  */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_refund_proof (
-  void *cls,
-  uint64_t refund_serial,
-  const struct TALER_ExchangeSignatureP *exchange_sig,
-  const struct TALER_ExchangePublicKeyP *exchange_pub)
+struct LookupDepositsByCnCContext
 {
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_uint64 (&refund_serial),
-    GNUNET_PQ_query_param_auto_from_type (exchange_sig),
-    GNUNET_PQ_query_param_auto_from_type (exchange_pub),
-    GNUNET_PQ_query_param_end
-  };
+  /**
+   * Function to call for each deposit.
+   */
+  TALER_MERCHANTDB_CoinDepositCallback cb;
 
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "insert_refund_proof",
-                                             params);
-}
+  /**
+   * Closure for @e cb.
+   */
+  void *cb_cls;
+
+  /**
+   * Plugin context.
+   */
+  struct PostgresClosure *pg;
+
+  /**
+   * Transaction result.
+   */
+  enum GNUNET_DB_QueryStatus qs;
+};
 
 
 /**
- * Lookup refund proof data.
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results.
  *
- * @param cls closure
- * @param refund_serial serial number of the refund
- * @param[out] exchange_sig set to signature from exchange
- * @param[out] exchange_pub signing key that was used for @a exchange_sig
- * @return transaction status
+ * @param cls of type `struct LookupDepositsByCnCContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
  */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_refund_proof (void *cls,
-                              uint64_t refund_serial,
-                              struct TALER_ExchangeSignatureP *exchange_sig,
-                              struct TALER_ExchangePublicKeyP *exchange_pub)
+static void
+lookup_deposits_by_contract_and_coin_cb (void *cls,
+                                         PGresult *result,
+                                         unsigned int num_results)
 {
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_uint64 (&refund_serial),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_auto_from_type ("exchange_sig",
-                                          exchange_sig),
-    GNUNET_PQ_result_spec_auto_from_type ("exchange_pub",
-                                          exchange_pub),
-    GNUNET_PQ_result_spec_end
-  };
+  struct LookupDepositsByCnCContext *ldcc = cls;
+  struct PostgresClosure *pg = ldcc->pg;
 
-  check_connection (pg);
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   "lookup_refund_proof",
-                                                   params,
-                                                   rs);
+  for (unsigned int i = 0; i<num_results; i++)
+  {
+    char *exchange_url;
+    struct TALER_Amount amount_with_fee;
+    struct TALER_Amount deposit_fee;
+    struct TALER_Amount refund_fee;
+    struct TALER_Amount wire_fee;
+    struct TALER_MerchantWireHashP h_wire;
+    struct GNUNET_TIME_Timestamp deposit_timestamp;
+    struct GNUNET_TIME_Timestamp refund_deadline;
+    struct TALER_ExchangeSignatureP exchange_sig;
+    struct TALER_ExchangePublicKeyP exchange_pub;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      GNUNET_PQ_result_spec_string ("exchange_url",
+                                    &exchange_url),
+      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_AMOUNT ("wire_fee",
+                                   &wire_fee),
+      GNUNET_PQ_result_spec_auto_from_type ("h_wire",
+                                            &h_wire),
+      GNUNET_PQ_result_spec_timestamp ("deposit_timestamp",
+                                       &deposit_timestamp),
+      GNUNET_PQ_result_spec_timestamp ("refund_deadline",
+                                       &refund_deadline),
+      GNUNET_PQ_result_spec_auto_from_type ("exchange_sig",
+                                            &exchange_sig),
+      GNUNET_PQ_result_spec_auto_from_type ("exchange_pub",
+                                            &exchange_pub),
+      GNUNET_PQ_result_spec_end
+    };
+
+    if (GNUNET_OK !=
+        GNUNET_PQ_extract_result (result,
+                                  rs,
+                                  i))
+    {
+      GNUNET_break (0);
+      ldcc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+      return;
+    }
+    ldcc->cb (ldcc->cb_cls,
+              exchange_url,
+              &amount_with_fee,
+              &deposit_fee,
+              &refund_fee,
+              &wire_fee,
+              &h_wire,
+              deposit_timestamp,
+              refund_deadline,
+              &exchange_sig,
+              &exchange_pub);
+    GNUNET_PQ_cleanup_result (rs);
+  }
+  ldcc->qs = num_results;
 }
 
 
 /**
- * Retrieve the order ID that was used to pay for a resource within a session.
+ * Lookup information about coin payments by @a h_contract_terms and
+ * @a coin_pub.
  *
  * @param cls closure
- * @param instance_id identifying the instance
- * @param fulfillment_url URL that canonically identifies the resource
- *        being paid for
- * @param session_id session id
- * @param[out] order_id where to store the order ID that was used when
- *             paying for the resource URL
+ * @param instance_id instance to lookup payments for
+ * @param h_contract_terms proposal data's hashcode
+ * @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 transaction status
  */
-enum GNUNET_DB_QueryStatus
-postgres_lookup_order_by_fulfillment (void *cls,
-                                      const char *instance_id,
-                                      const char *fulfillment_url,
-                                      const char *session_id,
-                                      char **order_id)
+static enum GNUNET_DB_QueryStatus
+postgres_lookup_deposits_by_contract_and_coin (
+  void *cls,
+  const char *instance_id,
+  const struct TALER_PrivateContractHashP *h_contract_terms,
+  const struct TALER_CoinSpendPublicKeyP *coin_pub,
+  TALER_MERCHANTDB_CoinDepositCallback cb,
+  void *cb_cls)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_string (fulfillment_url),
-    GNUNET_PQ_query_param_string (session_id),
+    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
+    GNUNET_PQ_query_param_auto_from_type (coin_pub),
     GNUNET_PQ_query_param_end
   };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_string ("order_id",
-                                  order_id),
-    GNUNET_PQ_result_spec_end
+  struct LookupDepositsByCnCContext ldcc = {
+    .cb  = cb,
+    .cb_cls = cb_cls,
+    .pg = pg
   };
+  enum GNUNET_DB_QueryStatus qs;
 
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   
"lookup_order_by_fulfillment",
-                                                   params,
-                                                   rs);
+  check_connection (pg);
+  qs = GNUNET_PQ_eval_prepared_multi_select (
+    pg->conn,
+    "lookup_deposits_by_contract_and_coin",
+    params,
+    &lookup_deposits_by_contract_and_coin_cb,
+    &ldcc);
+  if (0 >= qs)
+    return qs;
+  return ldcc.qs;
 }
 
 
 /**
- * Insert information about a wire transfer the merchant has received.
+ * Lookup transfer status.
  *
  * @param cls closure
- * @param instance_id the instance that received the transfer
- * @param exchange_url which exchange made the transfer
- * @param wtid identifier of the wire transfer
- * @param credit_amount how much did we receive
- * @param payto_uri what is the merchant's bank account that received the 
transfer
- * @param confirmed whether the transfer was confirmed by the merchant or
- *                  was merely claimed by the exchange at this point
+ * @param instance_id at which instance should we resolve the transfer
+ * @param exchange_url the exchange that made the transfer
+ * @param wtid wire transfer subject
+ * @param[out] total_amount amount that was debited from our
+ *             aggregate balance at the exchange (in total, sum of
+ *             the wire transfer amount and the @a wire_fee)
+ * @param[out] wire_fee the wire fee the exchange charged (only set if @a 
have_exchange_sig is true)
+ * @param[out] exchange_amount the amount the exchange claims was transferred 
(only set if @a have_exchange_sig is true)
+ * @param[out] execution_time when the transfer was executed by the exchange 
(only set if @a have_exchange_sig is true)
+ * @param[out] have_exchange_sig do we have a response from the exchange about 
this transfer
+ * @param[out] verified did we confirm the transfer was OK
  * @return transaction status
  */
 static enum GNUNET_DB_QueryStatus
-postgres_insert_transfer (
+postgres_lookup_transfer (
   void *cls,
   const char *instance_id,
   const char *exchange_url,
   const struct TALER_WireTransferIdentifierRawP *wtid,
-  const struct TALER_Amount *credit_amount,
-  const char *payto_uri,
-  bool confirmed)
+  struct TALER_Amount *total_amount,
+  struct TALER_Amount *wire_fee,
+  struct TALER_Amount *exchange_amount,
+  struct GNUNET_TIME_Timestamp *execution_time,
+  bool *have_exchange_sig,
+  bool *verified)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_string (exchange_url),
     GNUNET_PQ_query_param_auto_from_type (wtid),
-    TALER_PQ_query_param_amount (credit_amount),
-    GNUNET_PQ_query_param_string (payto_uri),
-    GNUNET_PQ_query_param_bool (confirmed),
     GNUNET_PQ_query_param_string (instance_id),
     GNUNET_PQ_query_param_end
   };
+  uint8_t verified8;
+  /** Amount we got actually credited, _excludes_ the wire fee */
+  bool no_sig;
+  struct TALER_Amount credit_amount;
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    TALER_PQ_RESULT_SPEC_AMOUNT ("credit_amount",
+                                 &credit_amount),
+    GNUNET_PQ_result_spec_allow_null (
+      TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
+                                   wire_fee),
+      &no_sig),
+    GNUNET_PQ_result_spec_allow_null (
+      TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_amount",
+                                   exchange_amount),
+      NULL),
+    GNUNET_PQ_result_spec_allow_null (
+      GNUNET_PQ_result_spec_timestamp ("execution_time",
+                                       execution_time),
+      NULL),
+    GNUNET_PQ_result_spec_auto_from_type ("verified",
+                                          &verified8),
+    GNUNET_PQ_result_spec_end
+  };
+  enum GNUNET_DB_QueryStatus qs;
 
   check_connection (pg);
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "insert_transfer",
-                                             params);
+  *execution_time = GNUNET_TIME_UNIT_ZERO_TS;
+  qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                 "lookup_transfer",
+                                                 params,
+                                                 rs);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Lookup transfer returned %d\n",
+              qs);
+  if (qs > 0)
+  {
+    *have_exchange_sig = ! no_sig;
+    *verified = (0 != verified8);
+    if ( (! no_sig) &&
+         (0 >
+          TALER_amount_add (total_amount,
+                            &credit_amount,
+                            wire_fee)) )
+    {
+      GNUNET_break (0);
+      return GNUNET_DB_STATUS_HARD_ERROR;
+    }
+  }
+  else
+  {
+    *verified = false;
+    *have_exchange_sig = false;
+  }
+  return qs;
 }
 
 
 /**
- * Delete information about a transfer. Note that transfers
- * confirmed by the exchange cannot be deleted anymore.
- *
- * @param cls closure
- * @param instance_id instance to delete transfer of
- * @param transfer_serial_id transfer to delete
- * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
- *           if deletion is prohibited OR transfer is unknown
+ * Closure for #lookup_transfer_summary_cb().
  */
-static enum GNUNET_DB_QueryStatus
-postgres_delete_transfer (void *cls,
-                          const char *instance_id,
-                          uint64_t transfer_serial_id)
+struct LookupTransferSummaryContext
 {
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_uint64 (&transfer_serial_id),
-    GNUNET_PQ_query_param_end
-  };
+  /**
+   * Function to call for each order that was aggregated.
+   */
+  TALER_MERCHANTDB_TransferSummaryCallback cb;
 
-  check_connection (pg);
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "delete_transfer",
-                                             params);
-}
+  /**
+   * Closure for @e cb.
+   */
+  void *cb_cls;
+
+  /**
+   * Plugin context.
+   */
+  struct PostgresClosure *pg;
+
+  /**
+   * Transaction result.
+   */
+  enum GNUNET_DB_QueryStatus qs;
+};
 
 
 /**
- * Check if information about a transfer exists with the
- * backend.  Returns no data, only the query status.
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results.
  *
- * @param cls closure
- * @param instance_id instance to delete transfer of
- * @param transfer_serial_id transfer to delete
- * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
- *           if the transfer record exists
+ * @param cls of type `struct LookupTransferSummaryContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
  */
-static enum GNUNET_DB_QueryStatus
-postgres_check_transfer_exists (void *cls,
-                                const char *instance_id,
-                                uint64_t transfer_serial_id)
+static void
+lookup_transfer_summary_cb (void *cls,
+                            PGresult *result,
+                            unsigned int num_results)
 {
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_uint64 (&transfer_serial_id),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_end
-  };
+  struct LookupTransferSummaryContext *ltdc = cls;
+  struct PostgresClosure *pg = ltdc->pg;
 
-  check_connection (pg);
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   "check_transfer_exists",
-                                                   params,
-                                                   rs);
+  for (unsigned int i = 0; i<num_results; i++)
+  {
+    char *order_id;
+    struct TALER_Amount deposit_value;
+    struct TALER_Amount deposit_fee;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      GNUNET_PQ_result_spec_string ("order_id",
+                                    &order_id),
+      TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_value",
+                                   &deposit_value),
+      TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_fee",
+                                   &deposit_fee),
+      GNUNET_PQ_result_spec_end
+    };
+
+    if (GNUNET_OK !=
+        GNUNET_PQ_extract_result (result,
+                                  rs,
+                                  i))
+    {
+      GNUNET_break (0);
+      ltdc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+      return;
+    }
+    ltdc->cb (ltdc->cb_cls,
+              order_id,
+              &deposit_value,
+              &deposit_fee);
+    GNUNET_PQ_cleanup_result (rs);
+  }
+  ltdc->qs = num_results;
 }
 
 
 /**
- * Lookup account serial by payto URI.
+ * Lookup transfer summary.
  *
  * @param cls closure
- * @param instance_id instance to lookup the account from
- * @param payto_uri what is the merchant's bank account to lookup
- * @param[out] account_serial serial number of the account
+ * @param exchange_url the exchange that made the transfer
+ * @param wtid wire transfer subject
+ * @param cb function to call with detailed transfer data
+ * @param cb_cls closure for @a cb
  * @return transaction status
  */
 static enum GNUNET_DB_QueryStatus
-postgres_lookup_account (void *cls,
-                         const char *instance_id,
-                         const char *payto_uri,
-                         uint64_t *account_serial)
+postgres_lookup_transfer_summary (
+  void *cls,
+  const char *exchange_url,
+  const struct TALER_WireTransferIdentifierRawP *wtid,
+  TALER_MERCHANTDB_TransferSummaryCallback cb,
+  void *cb_cls)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_string (payto_uri),
+    GNUNET_PQ_query_param_string (exchange_url),
+    GNUNET_PQ_query_param_auto_from_type (wtid),
     GNUNET_PQ_query_param_end
   };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_uint64 ("account_serial",
-                                  account_serial),
-    GNUNET_PQ_result_spec_end
+  struct LookupTransferSummaryContext ltdc = {
+    .cb  = cb,
+    .cb_cls = cb_cls,
+    .pg = pg
   };
+  enum GNUNET_DB_QueryStatus qs;
 
   check_connection (pg);
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   "lookup_account",
-                                                   params,
-                                                   rs);
+  qs = GNUNET_PQ_eval_prepared_multi_select (
+    pg->conn,
+    "lookup_transfer_summary",
+    params,
+    &lookup_transfer_summary_cb,
+    &ltdc);
+  if (0 >= qs)
+    return qs;
+  return ltdc.qs;
 }
 
 
 /**
- * Insert information about a wire transfer the merchant has received.
- *
- * @param cls closure
- * @param instance_id instance to provide transfer details for
- * @param exchange_url which exchange made the transfer
- * @param payto_uri what is the merchant's bank account that received the 
transfer
- * @param wtid identifier of the wire transfer
- * @param td transfer details to store
- * @return transaction status,
- *   #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if the @a wtid and @a exchange_uri 
are not known for this @a instance_id
- *   #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT on success
+ * Closure for #lookup_transfer_details_cb().
  */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_transfer_details (
-  void *cls,
-  const char *instance_id,
-  const char *exchange_url,
-  const char *payto_uri,
-  const struct TALER_WireTransferIdentifierRawP *wtid,
-  const struct TALER_EXCHANGE_TransferData *td)
+struct LookupTransferDetailsContext
 {
-  struct PostgresClosure *pg = cls;
-  enum GNUNET_DB_QueryStatus qs;
-  uint64_t credit_serial;
-  unsigned int retries;
-
-  retries = 0;
-  check_connection (pg);
-RETRY:
-  if (MAX_RETRIES < ++retries)
-    return GNUNET_DB_STATUS_SOFT_ERROR;
-  if (GNUNET_OK !=
-      postgres_start_read_committed (pg,
-                                     "insert transfer details"))
-  {
-    GNUNET_break (0);
-    return GNUNET_DB_STATUS_HARD_ERROR;
-  }
-
-  /* lookup credit serial */
-  {
-    struct GNUNET_PQ_QueryParam params[] = {
-      GNUNET_PQ_query_param_string (exchange_url),
-      GNUNET_PQ_query_param_string (payto_uri),
-      GNUNET_PQ_query_param_string (instance_id),
-      GNUNET_PQ_query_param_auto_from_type (wtid),
-      GNUNET_PQ_query_param_end
-    };
-    struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_uint64 ("credit_serial",
-                                    &credit_serial),
-      GNUNET_PQ_result_spec_end
-    };
-
-    qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   "lookup_credit_serial",
-                                                   params,
-                                                   rs);
-    if (0 > qs)
-    {
-      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
-      postgres_rollback (pg);
-      if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
-        goto RETRY;
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  "'lookup_credit_serial' for account %s and amount %s failed 
with status %d\n",
-                  payto_uri,
-                  TALER_amount2s (&td->total_amount),
-                  qs);
-      return qs;
-    }
-    if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
-    {
-      postgres_rollback (pg);
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  "'lookup_credit_serial' for account %s failed with transfer 
unknown\n",
-                  payto_uri);
-      return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
-    }
-  }
-
-  /* update merchant_transfer_signatures table */
-  {
-    struct GNUNET_PQ_QueryParam params[] = {
-      GNUNET_PQ_query_param_uint64 (&credit_serial),
-      TALER_PQ_query_param_amount (&td->total_amount),
-      TALER_PQ_query_param_amount (&td->wire_fee),
-      GNUNET_PQ_query_param_timestamp (&td->execution_time),
-      GNUNET_PQ_query_param_auto_from_type (&td->exchange_sig),
-      GNUNET_PQ_query_param_auto_from_type (&td->exchange_pub),
-      GNUNET_PQ_query_param_end
-    };
-
-    qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "insert_transfer_signature",
-                                             params);
-    if (0 > qs)
-    {
-      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
-      postgres_rollback (pg);
-      if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
-        goto RETRY;
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  "'insert_transfer_signature' failed with status %d\n",
-                  qs);
-      return qs;
-    }
-    if (0 == qs)
-    {
-      postgres_rollback (pg);
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  "'insert_transfer_signature' failed with status %d\n",
-                  qs);
-      return GNUNET_DB_STATUS_HARD_ERROR;
-    }
-  }
-
-  /* Update transfer-coin association table */
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Updating transfer-coin association table\n");
-  for (unsigned int i = 0; i<td->details_length; i++)
-  {
-    const struct TALER_TrackTransferDetails *d = &td->details[i];
-    uint64_t i64 = (uint64_t) i;
-    struct GNUNET_PQ_QueryParam params[] = {
-      GNUNET_PQ_query_param_uint64 (&credit_serial),
-      GNUNET_PQ_query_param_uint64 (&i64),
-      TALER_PQ_query_param_amount (&d->coin_value),
-      TALER_PQ_query_param_amount (&d->coin_fee), /* deposit fee */
-      GNUNET_PQ_query_param_auto_from_type (&d->coin_pub),
-      GNUNET_PQ_query_param_auto_from_type (&d->h_contract_terms),
-      GNUNET_PQ_query_param_string (instance_id),
-      GNUNET_PQ_query_param_end
-    };
-
-    qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "insert_transfer_to_coin_mapping",
-                                             params);
-    if (0 > qs)
-    {
-      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
-      postgres_rollback (pg);
-      if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
-        goto RETRY;
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  "'insert_transfer_to_coin_mapping' failed with status %d\n",
-                  qs);
-      return qs;
-    }
-    if (0 == qs)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  "'insert_transfer_to_coin_mapping' failed at %u: deposit 
unknown\n",
-                  i);
-    }
-  }
-  /* Update merchant_contract_terms 'wired' status: for all coins
-     that were wired, set the respective order's "wired" status to
-     true, *if* all other deposited coins associated with that order
-     have also been wired (this time or earlier) */
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Updating contract terms 'wired' status\n");
-  for (unsigned int i = 0; i<td->details_length; i++)
-  {
-    const struct TALER_TrackTransferDetails *d = &td->details[i];
-    struct GNUNET_PQ_QueryParam params[] = {
-      GNUNET_PQ_query_param_auto_from_type (&d->coin_pub),
-      GNUNET_PQ_query_param_end
-    };
-
-    qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "update_wired_by_coin_pub",
-                                             params);
-    if (0 > qs)
-    {
-      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
-      postgres_rollback (pg);
-      if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
-        goto RETRY;
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  "'update_wired_by_coin_pub' failed with status %d\n",
-                  qs);
-      return qs;
-    }
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Committing transaction...\n");
-  qs = postgres_commit (pg);
-  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
-    return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
-  GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
-  if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
-    goto RETRY;
-  return qs;
-}
-
-
-/**
- * Obtain information about wire fees charged by an exchange,
- * including signature (so we have proof).
- *
- * @param cls closure
- * @param master_pub public key of the exchange
- * @param wire_method the wire method
- * @param contract_date date of the contract to use for the lookup
- * @param[out] fees wire fees charged
- * @param[out] start_date start of fee being used
- * @param[out] end_date end of fee being used
- * @param[out] master_sig signature of exchange over fee structure
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_wire_fee (void *cls,
-                          const struct TALER_MasterPublicKeyP *master_pub,
-                          const char *wire_method,
-                          struct GNUNET_TIME_Timestamp contract_date,
-                          struct TALER_WireFeeSet *fees,
-                          struct GNUNET_TIME_Timestamp *start_date,
-                          struct GNUNET_TIME_Timestamp *end_date,
-                          struct TALER_MasterSignatureP *master_sig)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_HashCode h_wire_method;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (master_pub),
-    GNUNET_PQ_query_param_auto_from_type (&h_wire_method),
-    GNUNET_PQ_query_param_timestamp (&contract_date),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
-                                 &fees->wire),
-    TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
-                                 &fees->closing),
-    GNUNET_PQ_result_spec_timestamp ("start_date",
-                                     start_date),
-    GNUNET_PQ_result_spec_timestamp ("end_date",
-                                     end_date),
-    GNUNET_PQ_result_spec_auto_from_type ("master_sig",
-                                          master_sig),
-    GNUNET_PQ_result_spec_end
-  };
-
-  check_connection (pg);
-  GNUNET_CRYPTO_hash (wire_method,
-                      strlen (wire_method) + 1,
-                      &h_wire_method);
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   "lookup_wire_fee",
-                                                   params,
-                                                   rs);
-}
-
-
-/**
- * Closure for #lookup_deposits_by_contract_and_coin_cb().
- */
-struct LookupDepositsByCnCContext
-{
-  /**
-   * Function to call for each deposit.
-   */
-  TALER_MERCHANTDB_CoinDepositCallback cb;
+  /**
+   * Function to call for each order that was aggregated.
+   */
+  TALER_MERCHANTDB_TransferDetailsCallback cb;
 
   /**
    * Closure for @e cb.
@@ -3189,51 +2779,33 @@ struct LookupDepositsByCnCContext
  * Function to be called with the results of a SELECT statement
  * that has returned @a num_results results.
  *
- * @param cls of type `struct LookupDepositsByCnCContext *`
+ * @param cls of type `struct LookupTransferDetailsContext *`
  * @param result the postgres result
  * @param num_results the number of results in @a result
  */
 static void
-lookup_deposits_by_contract_and_coin_cb (void *cls,
-                                         PGresult *result,
-                                         unsigned int num_results)
+lookup_transfer_details_cb (void *cls,
+                            PGresult *result,
+                            unsigned int num_results)
 {
-  struct LookupDepositsByCnCContext *ldcc = cls;
-  struct PostgresClosure *pg = ldcc->pg;
+  struct LookupTransferDetailsContext *ltdc = cls;
+  struct PostgresClosure *pg = ltdc->pg;
 
   for (unsigned int i = 0; i<num_results; i++)
   {
-    char *exchange_url;
-    struct TALER_Amount amount_with_fee;
-    struct TALER_Amount deposit_fee;
-    struct TALER_Amount refund_fee;
-    struct TALER_Amount wire_fee;
-    struct TALER_MerchantWireHashP h_wire;
-    struct GNUNET_TIME_Timestamp deposit_timestamp;
-    struct GNUNET_TIME_Timestamp refund_deadline;
-    struct TALER_ExchangeSignatureP exchange_sig;
-    struct TALER_ExchangePublicKeyP exchange_pub;
+    uint64_t current_offset;
+    struct TALER_TrackTransferDetails ttd;
     struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_string ("exchange_url",
-                                    &exchange_url),
-      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_AMOUNT ("wire_fee",
-                                   &wire_fee),
-      GNUNET_PQ_result_spec_auto_from_type ("h_wire",
-                                            &h_wire),
-      GNUNET_PQ_result_spec_timestamp ("deposit_timestamp",
-                                       &deposit_timestamp),
-      GNUNET_PQ_result_spec_timestamp ("refund_deadline",
-                                       &refund_deadline),
-      GNUNET_PQ_result_spec_auto_from_type ("exchange_sig",
-                                            &exchange_sig),
-      GNUNET_PQ_result_spec_auto_from_type ("exchange_pub",
-                                            &exchange_pub),
+      GNUNET_PQ_result_spec_uint64 ("offset_in_exchange_list",
+                                    &current_offset),
+      GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
+                                            &ttd.h_contract_terms),
+      GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
+                                            &ttd.coin_pub),
+      TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_value",
+                                   &ttd.coin_value),
+      TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_fee",
+                                   &ttd.coin_fee),
       GNUNET_PQ_result_spec_end
     };
 
@@ -3243,55 +2815,43 @@ lookup_deposits_by_contract_and_coin_cb (void *cls,
                                   i))
     {
       GNUNET_break (0);
-      ldcc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+      ltdc->qs = GNUNET_DB_STATUS_HARD_ERROR;
       return;
     }
-    ldcc->cb (ldcc->cb_cls,
-              exchange_url,
-              &amount_with_fee,
-              &deposit_fee,
-              &refund_fee,
-              &wire_fee,
-              &h_wire,
-              deposit_timestamp,
-              refund_deadline,
-              &exchange_sig,
-              &exchange_pub);
+    ltdc->cb (ltdc->cb_cls,
+              (unsigned int) current_offset,
+              &ttd);
     GNUNET_PQ_cleanup_result (rs);
   }
-  ldcc->qs = num_results;
+  ltdc->qs = num_results;
 }
 
 
 /**
- * Lookup information about coin payments by @a h_contract_terms and
- * @a coin_pub.
+ * Lookup transfer details.
  *
  * @param cls closure
- * @param instance_id instance to lookup payments for
- * @param h_contract_terms proposal data's hashcode
- * @param coin_pub public key to use for the search
- * @param cb function to call with payment data
+ * @param exchange_url the exchange that made the transfer
+ * @param wtid wire transfer subject
+ * @param cb function to call with detailed transfer data
  * @param cb_cls closure for @a cb
  * @return transaction status
  */
 static enum GNUNET_DB_QueryStatus
-postgres_lookup_deposits_by_contract_and_coin (
+postgres_lookup_transfer_details (
   void *cls,
-  const char *instance_id,
-  const struct TALER_PrivateContractHashP *h_contract_terms,
-  const struct TALER_CoinSpendPublicKeyP *coin_pub,
-  TALER_MERCHANTDB_CoinDepositCallback cb,
+  const char *exchange_url,
+  const struct TALER_WireTransferIdentifierRawP *wtid,
+  TALER_MERCHANTDB_TransferDetailsCallback cb,
   void *cb_cls)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
-    GNUNET_PQ_query_param_auto_from_type (coin_pub),
+    GNUNET_PQ_query_param_string (exchange_url),
+    GNUNET_PQ_query_param_auto_from_type (wtid),
     GNUNET_PQ_query_param_end
   };
-  struct LookupDepositsByCnCContext ldcc = {
+  struct LookupTransferDetailsContext ltdc = {
     .cb  = cb,
     .cb_cls = cb_cls,
     .pg = pg
@@ -3301,289 +2861,256 @@ postgres_lookup_deposits_by_contract_and_coin (
   check_connection (pg);
   qs = GNUNET_PQ_eval_prepared_multi_select (
     pg->conn,
-    "lookup_deposits_by_contract_and_coin",
+    "lookup_transfer_details",
     params,
-    &lookup_deposits_by_contract_and_coin_cb,
-    &ldcc);
+    &lookup_transfer_details_cb,
+    &ltdc);
   if (0 >= qs)
     return qs;
-  return ldcc.qs;
+  return ltdc.qs;
 }
 
 
 /**
- * Lookup transfer status.
+ * Store information about wire fees charged by an exchange,
+ * including signature (so we have proof).
  *
  * @param cls closure
- * @param instance_id at which instance should we resolve the transfer
- * @param exchange_url the exchange that made the transfer
- * @param wtid wire transfer subject
- * @param[out] total_amount amount that was debited from our
- *             aggregate balance at the exchange (in total, sum of
- *             the wire transfer amount and the @a wire_fee)
- * @param[out] wire_fee the wire fee the exchange charged (only set if @a 
have_exchange_sig is true)
- * @param[out] exchange_amount the amount the exchange claims was transferred 
(only set if @a have_exchange_sig is true)
- * @param[out] execution_time when the transfer was executed by the exchange 
(only set if @a have_exchange_sig is true)
- * @param[out] have_exchange_sig do we have a response from the exchange about 
this transfer
- * @param[out] verified did we confirm the transfer was OK
- * @return transaction status
+ * @param master_pub public key of the exchange
+ * @param h_wire_method hash of wire method
+ * @param fees the fee charged
+ * @param start_date start of fee being used
+ * @param end_date end of fee being used
+ * @param master_sig signature of exchange over fee structure
+ * @return transaction status code
  */
 static enum GNUNET_DB_QueryStatus
-postgres_lookup_transfer (
+postgres_store_wire_fee_by_exchange (
   void *cls,
-  const char *instance_id,
-  const char *exchange_url,
-  const struct TALER_WireTransferIdentifierRawP *wtid,
-  struct TALER_Amount *total_amount,
-  struct TALER_Amount *wire_fee,
-  struct TALER_Amount *exchange_amount,
-  struct GNUNET_TIME_Timestamp *execution_time,
-  bool *have_exchange_sig,
-  bool *verified)
+  const struct TALER_MasterPublicKeyP *master_pub,
+  const struct GNUNET_HashCode *h_wire_method,
+  const struct TALER_WireFeeSet *fees,
+  struct GNUNET_TIME_Timestamp start_date,
+  struct GNUNET_TIME_Timestamp end_date,
+  const struct TALER_MasterSignatureP *master_sig)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (exchange_url),
-    GNUNET_PQ_query_param_auto_from_type (wtid),
-    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_auto_from_type (master_pub),
+    GNUNET_PQ_query_param_auto_from_type (h_wire_method),
+    TALER_PQ_query_param_amount (&fees->wire),
+    TALER_PQ_query_param_amount (&fees->closing),
+    GNUNET_PQ_query_param_timestamp (&start_date),
+    GNUNET_PQ_query_param_timestamp (&end_date),
+    GNUNET_PQ_query_param_auto_from_type (master_sig),
     GNUNET_PQ_query_param_end
   };
-  uint8_t verified8;
-  /** Amount we got actually credited, _excludes_ the wire fee */
-  bool no_sig;
-  struct TALER_Amount credit_amount;
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    TALER_PQ_RESULT_SPEC_AMOUNT ("credit_amount",
-                                 &credit_amount),
-    GNUNET_PQ_result_spec_allow_null (
-      TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
-                                   wire_fee),
-      &no_sig),
-    GNUNET_PQ_result_spec_allow_null (
-      TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_amount",
-                                   exchange_amount),
-      NULL),
-    GNUNET_PQ_result_spec_allow_null (
-      GNUNET_PQ_result_spec_timestamp ("execution_time",
-                                       execution_time),
-      NULL),
-    GNUNET_PQ_result_spec_auto_from_type ("verified",
-                                          &verified8),
-    GNUNET_PQ_result_spec_end
-  };
-  enum GNUNET_DB_QueryStatus qs;
 
+  /* no preflight check here, run in its own transaction by the caller */
   check_connection (pg);
-  *execution_time = GNUNET_TIME_UNIT_ZERO_TS;
-  qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                 "lookup_transfer",
-                                                 params,
-                                                 rs);
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Lookup transfer returned %d\n",
-              qs);
-  if (qs > 0)
-  {
-    *have_exchange_sig = ! no_sig;
-    *verified = (0 != verified8);
-    if ( (! no_sig) &&
-         (0 >
-          TALER_amount_add (total_amount,
-                            &credit_amount,
-                            wire_fee)) )
-    {
-      GNUNET_break (0);
-      return GNUNET_DB_STATUS_HARD_ERROR;
-    }
-  }
-  else
-  {
-    *verified = false;
-    *have_exchange_sig = false;
-  }
-  return qs;
+              "Storing wire fee for %s starting at %s of %s\n",
+              TALER_B2S (master_pub),
+              GNUNET_TIME_timestamp2s (start_date),
+              TALER_amount2s (&fees->wire));
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "insert_wire_fee",
+                                             params);
 }
 
 
 /**
- * Closure for #lookup_transfer_summary_cb().
+ * Add @a credit to a reserve to be used for tipping.  Note that
+ * this function does not actually perform any wire transfers to
+ * credit the reserve, it merely tells the merchant backend that
+ * a reserve now exists.  This has to happen before tips can be
+ * authorized.
+ *
+ * @param cls closure, typically a connection to the db
+ * @param instance_id which instance is the reserve tied to
+ * @param reserve_priv which reserve is topped up or created
+ * @param reserve_pub which reserve is topped up or created
+ * @param master_pub master public key of the exchange
+ * @param exchange_url what URL is the exchange reachable at where the reserve 
is located
+ * @param initial_balance how much money will be added to the reserve
+ * @param expiration when does the reserve expire?
+ * @return transaction status, usually
+ *      #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
  */
-struct LookupTransferSummaryContext
+static enum TALER_ErrorCode
+postgres_insert_reserve (void *cls,
+                         const char *instance_id,
+                         const struct TALER_ReservePrivateKeyP *reserve_priv,
+                         const struct TALER_ReservePublicKeyP *reserve_pub,
+                         const struct TALER_MasterPublicKeyP *master_pub,
+                         const char *exchange_url,
+                         const struct TALER_Amount *initial_balance,
+                         struct GNUNET_TIME_Timestamp expiration)
 {
-  /**
-   * Function to call for each order that was aggregated.
-   */
-  TALER_MERCHANTDB_TransferSummaryCallback cb;
-
-  /**
-   * Closure for @e cb.
-   */
-  void *cb_cls;
-
-  /**
-   * Plugin context.
-   */
-  struct PostgresClosure *pg;
-
-  /**
-   * Transaction result.
-   */
+  struct PostgresClosure *pg = cls;
+  unsigned int retries;
   enum GNUNET_DB_QueryStatus qs;
-};
 
+  retries = 0;
+  check_connection (pg);
+RETRY:
+  if (MAX_RETRIES < ++retries)
+    return TALER_EC_GENERIC_DB_SOFT_FAILURE;
+  if (GNUNET_OK !=
+      postgres_start (pg,
+                      "insert reserve"))
+  {
+    GNUNET_break (0);
+    return TALER_EC_GENERIC_DB_START_FAILED;
+  }
 
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
- *
- * @param cls of type `struct LookupTransferSummaryContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_transfer_summary_cb (void *cls,
-                            PGresult *result,
-                            unsigned int num_results)
-{
-  struct LookupTransferSummaryContext *ltdc = cls;
-  struct PostgresClosure *pg = ltdc->pg;
+  /* Setup reserve */
+  {
+    struct GNUNET_TIME_Timestamp now;
+    struct GNUNET_PQ_QueryParam params[] = {
+      GNUNET_PQ_query_param_string (instance_id),
+      GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+      GNUNET_PQ_query_param_timestamp (&now),
+      GNUNET_PQ_query_param_timestamp (&expiration),
+      TALER_PQ_query_param_amount (initial_balance),
+      GNUNET_PQ_query_param_end
+    };
 
-  for (unsigned int i = 0; i<num_results; i++)
+    now = GNUNET_TIME_timestamp_get ();
+    qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "insert_reserve",
+                                             params);
+    if (0 > qs)
+    {
+      postgres_rollback (pg);
+      if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+        goto RETRY;
+      return qs;
+    }
+  }
+  /* Store private key */
   {
-    char *order_id;
-    struct TALER_Amount deposit_value;
-    struct TALER_Amount deposit_fee;
-    struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_string ("order_id",
-                                    &order_id),
-      TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_value",
-                                   &deposit_value),
-      TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_fee",
-                                   &deposit_fee),
-      GNUNET_PQ_result_spec_end
+    struct GNUNET_PQ_QueryParam params[] = {
+      GNUNET_PQ_query_param_string (instance_id),
+      GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+      GNUNET_PQ_query_param_auto_from_type (reserve_priv),
+      GNUNET_PQ_query_param_string (exchange_url),
+      GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+      GNUNET_PQ_query_param_end
     };
 
-    if (GNUNET_OK !=
-        GNUNET_PQ_extract_result (result,
-                                  rs,
-                                  i))
+    qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "insert_reserve_key",
+                                             params);
+    if (0 > qs)
     {
-      GNUNET_break (0);
-      ltdc->qs = GNUNET_DB_STATUS_HARD_ERROR;
-      return;
+      postgres_rollback (pg);
+      if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+        goto RETRY;
+      return qs;
     }
-    ltdc->cb (ltdc->cb_cls,
-              order_id,
-              &deposit_value,
-              &deposit_fee);
-    GNUNET_PQ_cleanup_result (rs);
   }
-  ltdc->qs = num_results;
+  qs = postgres_commit (pg);
+  if (0 <= qs)
+    return TALER_EC_NONE; /* success  */
+  if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+    goto RETRY;
+  return qs;
 }
 
 
 /**
- * Lookup transfer summary.
+ * Confirms @a credit as the amount the exchange claims to have received and
+ * thus really 'activates' the reserve.  This has to happen before tips can
+ * be authorized.
  *
- * @param cls closure
- * @param exchange_url the exchange that made the transfer
- * @param wtid wire transfer subject
- * @param cb function to call with detailed transfer data
- * @param cb_cls closure for @a cb
- * @return transaction status
+ * @param cls closure, typically a connection to the db
+ * @param instance_id which instance is the reserve tied to
+ * @param reserve_pub which reserve is topped up or created
+ * @param initial_exchange_balance how much money was be added to the reserve
+ *           according to the exchange
+ * @return transaction status, usually
+ *      #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
  */
 static enum GNUNET_DB_QueryStatus
-postgres_lookup_transfer_summary (
-  void *cls,
-  const char *exchange_url,
-  const struct TALER_WireTransferIdentifierRawP *wtid,
-  TALER_MERCHANTDB_TransferSummaryCallback cb,
-  void *cb_cls)
+postgres_activate_reserve (void *cls,
+                           const char *instance_id,
+                           const struct TALER_ReservePublicKeyP *reserve_pub,
+                           const struct TALER_Amount *initial_exchange_balance)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (exchange_url),
-    GNUNET_PQ_query_param_auto_from_type (wtid),
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+    TALER_PQ_query_param_amount (initial_exchange_balance),
     GNUNET_PQ_query_param_end
   };
-  struct LookupTransferSummaryContext ltdc = {
-    .cb  = cb,
-    .cb_cls = cb_cls,
-    .pg = pg
-  };
-  enum GNUNET_DB_QueryStatus qs;
 
-  check_connection (pg);
-  qs = GNUNET_PQ_eval_prepared_multi_select (
-    pg->conn,
-    "lookup_transfer_summary",
-    params,
-    &lookup_transfer_summary_cb,
-    &ltdc);
-  if (0 >= qs)
-    return qs;
-  return ltdc.qs;
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "activate_reserve",
+                                             params);
 }
 
 
 /**
- * Closure for #lookup_transfer_details_cb().
+ * Closure for #lookup_pending_reserves_cb.
  */
-struct LookupTransferDetailsContext
+struct LookupPendingReservesContext
 {
   /**
-   * Function to call for each order that was aggregated.
+   * Postgres context.
    */
-  TALER_MERCHANTDB_TransferDetailsCallback cb;
+  struct PostgresClosure *pg;
 
   /**
-   * Closure for @e cb.
+   * Function to call with the results
    */
-  void *cb_cls;
+  TALER_MERCHANTDB_PendingReservesCallback cb;
 
   /**
-   * Plugin context.
+   * Closure for @e cb
    */
-  struct PostgresClosure *pg;
+  void *cb_cls;
 
   /**
-   * Transaction result.
+   * Set in case of errors.
    */
   enum GNUNET_DB_QueryStatus qs;
+
 };
 
 
 /**
  * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results.
+ * that has returned @a num_results results about accounts.
  *
- * @param cls of type `struct LookupTransferDetailsContext *`
+ * @param[in,out] cls of type `struct LookupReservesContext *`
  * @param result the postgres result
  * @param num_results the number of results in @a result
  */
 static void
-lookup_transfer_details_cb (void *cls,
+lookup_pending_reserves_cb (void *cls,
                             PGresult *result,
                             unsigned int num_results)
 {
-  struct LookupTransferDetailsContext *ltdc = cls;
-  struct PostgresClosure *pg = ltdc->pg;
+  struct LookupPendingReservesContext *lrc = cls;
+  struct PostgresClosure *pg = lrc->pg;
 
-  for (unsigned int i = 0; i<num_results; i++)
+  for (unsigned int i = 0; i < num_results; i++)
   {
-    uint64_t current_offset;
-    struct TALER_TrackTransferDetails ttd;
+    struct TALER_ReservePublicKeyP reserve_pub;
+    struct TALER_Amount merchant_initial_balance;
+    char *exchange_url;
+    char *instance_id;
     struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_uint64 ("offset_in_exchange_list",
-                                    &current_offset),
-      GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
-                                            &ttd.h_contract_terms),
-      GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
-                                            &ttd.coin_pub),
-      TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_value",
-                                   &ttd.coin_value),
-      TALER_PQ_RESULT_SPEC_AMOUNT ("exchange_deposit_fee",
-                                   &ttd.coin_fee),
+      GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
+                                            &reserve_pub),
+      GNUNET_PQ_result_spec_string ("merchant_id",
+                                    &instance_id),
+      GNUNET_PQ_result_spec_string ("exchange_url",
+                                    &exchange_url),
+      TALER_PQ_RESULT_SPEC_AMOUNT ("merchant_initial_balance",
+                                   &merchant_initial_balance),
       GNUNET_PQ_result_spec_end
     };
 
@@ -3593,247 +3120,59 @@ lookup_transfer_details_cb (void *cls,
                                   i))
     {
       GNUNET_break (0);
-      ltdc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+      lrc->qs = GNUNET_DB_STATUS_HARD_ERROR;
       return;
     }
-    ltdc->cb (ltdc->cb_cls,
-              (unsigned int) current_offset,
-              &ttd);
+    lrc->cb (lrc->cb_cls,
+             instance_id,
+             exchange_url,
+             &reserve_pub,
+             &merchant_initial_balance);
     GNUNET_PQ_cleanup_result (rs);
   }
-  ltdc->qs = num_results;
 }
 
 
 /**
- * Lookup transfer details.
+ * Lookup reserves pending activation across all instances.
  *
  * @param cls closure
- * @param exchange_url the exchange that made the transfer
- * @param wtid wire transfer subject
- * @param cb function to call with detailed transfer data
+ * @param cb function to call with reserve summary data
  * @param cb_cls closure for @a cb
  * @return transaction status
  */
 static enum GNUNET_DB_QueryStatus
-postgres_lookup_transfer_details (
-  void *cls,
-  const char *exchange_url,
-  const struct TALER_WireTransferIdentifierRawP *wtid,
-  TALER_MERCHANTDB_TransferDetailsCallback cb,
-  void *cb_cls)
+postgres_lookup_pending_reserves (void *cls,
+                                  TALER_MERCHANTDB_PendingReservesCallback cb,
+                                  void *cb_cls)
 {
   struct PostgresClosure *pg = cls;
+  struct LookupPendingReservesContext lrc = {
+    .pg = pg,
+    .cb = cb,
+    .cb_cls = cb_cls
+  };
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (exchange_url),
-    GNUNET_PQ_query_param_auto_from_type (wtid),
     GNUNET_PQ_query_param_end
   };
-  struct LookupTransferDetailsContext ltdc = {
-    .cb  = cb,
-    .cb_cls = cb_cls,
-    .pg = pg
-  };
   enum GNUNET_DB_QueryStatus qs;
 
   check_connection (pg);
-  qs = GNUNET_PQ_eval_prepared_multi_select (
-    pg->conn,
-    "lookup_transfer_details",
-    params,
-    &lookup_transfer_details_cb,
-    &ltdc);
-  if (0 >= qs)
-    return qs;
-  return ltdc.qs;
+  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+                                             "lookup_pending_reserves",
+                                             params,
+                                             &lookup_pending_reserves_cb,
+                                             &lrc);
+  if (lrc.qs < 0)
+    return lrc.qs;
+  return qs;
 }
 
 
 /**
- * Store information about wire fees charged by an exchange,
- * including signature (so we have proof).
- *
- * @param cls closure
- * @param master_pub public key of the exchange
- * @param h_wire_method hash of wire method
- * @param fees the fee charged
- * @param start_date start of fee being used
- * @param end_date end of fee being used
- * @param master_sig signature of exchange over fee structure
- * @return transaction status code
+ * Closure for #lookup_reserve_tips_cb().
  */
-static enum GNUNET_DB_QueryStatus
-postgres_store_wire_fee_by_exchange (
-  void *cls,
-  const struct TALER_MasterPublicKeyP *master_pub,
-  const struct GNUNET_HashCode *h_wire_method,
-  const struct TALER_WireFeeSet *fees,
-  struct GNUNET_TIME_Timestamp start_date,
-  struct GNUNET_TIME_Timestamp end_date,
-  const struct TALER_MasterSignatureP *master_sig)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (master_pub),
-    GNUNET_PQ_query_param_auto_from_type (h_wire_method),
-    TALER_PQ_query_param_amount (&fees->wire),
-    TALER_PQ_query_param_amount (&fees->closing),
-    GNUNET_PQ_query_param_timestamp (&start_date),
-    GNUNET_PQ_query_param_timestamp (&end_date),
-    GNUNET_PQ_query_param_auto_from_type (master_sig),
-    GNUNET_PQ_query_param_end
-  };
-
-  /* no preflight check here, run in its own transaction by the caller */
-  check_connection (pg);
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Storing wire fee for %s starting at %s of %s\n",
-              TALER_B2S (master_pub),
-              GNUNET_TIME_timestamp2s (start_date),
-              TALER_amount2s (&fees->wire));
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "insert_wire_fee",
-                                             params);
-}
-
-
-/**
- * Add @a credit to a reserve to be used for tipping.  Note that
- * this function does not actually perform any wire transfers to
- * credit the reserve, it merely tells the merchant backend that
- * a reserve now exists.  This has to happen before tips can be
- * authorized.
- *
- * @param cls closure, typically a connection to the db
- * @param instance_id which instance is the reserve tied to
- * @param reserve_priv which reserve is topped up or created
- * @param reserve_pub which reserve is topped up or created
- * @param master_pub master public key of the exchange
- * @param exchange_url what URL is the exchange reachable at where the reserve 
is located
- * @param initial_balance how much money will be added to the reserve
- * @param expiration when does the reserve expire?
- * @return transaction status, usually
- *      #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
- */
-static enum TALER_ErrorCode
-postgres_insert_reserve (void *cls,
-                         const char *instance_id,
-                         const struct TALER_ReservePrivateKeyP *reserve_priv,
-                         const struct TALER_ReservePublicKeyP *reserve_pub,
-                         const struct TALER_MasterPublicKeyP *master_pub,
-                         const char *exchange_url,
-                         const struct TALER_Amount *initial_balance,
-                         struct GNUNET_TIME_Timestamp expiration)
-{
-  struct PostgresClosure *pg = cls;
-  unsigned int retries;
-  enum GNUNET_DB_QueryStatus qs;
-
-  retries = 0;
-  check_connection (pg);
-RETRY:
-  if (MAX_RETRIES < ++retries)
-    return TALER_EC_GENERIC_DB_SOFT_FAILURE;
-  if (GNUNET_OK !=
-      postgres_start (pg,
-                      "insert reserve"))
-  {
-    GNUNET_break (0);
-    return TALER_EC_GENERIC_DB_START_FAILED;
-  }
-
-  /* Setup reserve */
-  {
-    struct GNUNET_TIME_Timestamp now;
-    struct GNUNET_PQ_QueryParam params[] = {
-      GNUNET_PQ_query_param_string (instance_id),
-      GNUNET_PQ_query_param_auto_from_type (reserve_pub),
-      GNUNET_PQ_query_param_timestamp (&now),
-      GNUNET_PQ_query_param_timestamp (&expiration),
-      TALER_PQ_query_param_amount (initial_balance),
-      GNUNET_PQ_query_param_end
-    };
-
-    now = GNUNET_TIME_timestamp_get ();
-    qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "insert_reserve",
-                                             params);
-    if (0 > qs)
-    {
-      postgres_rollback (pg);
-      if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
-        goto RETRY;
-      return qs;
-    }
-  }
-  /* Store private key */
-  {
-    struct GNUNET_PQ_QueryParam params[] = {
-      GNUNET_PQ_query_param_string (instance_id),
-      GNUNET_PQ_query_param_auto_from_type (reserve_pub),
-      GNUNET_PQ_query_param_auto_from_type (reserve_priv),
-      GNUNET_PQ_query_param_string (exchange_url),
-      GNUNET_PQ_query_param_auto_from_type (reserve_pub),
-      GNUNET_PQ_query_param_end
-    };
-
-    qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "insert_reserve_key",
-                                             params);
-    if (0 > qs)
-    {
-      postgres_rollback (pg);
-      if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
-        goto RETRY;
-      return qs;
-    }
-  }
-  qs = postgres_commit (pg);
-  if (0 <= qs)
-    return TALER_EC_NONE; /* success  */
-  if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
-    goto RETRY;
-  return qs;
-}
-
-
-/**
- * Confirms @a credit as the amount the exchange claims to have received and
- * thus really 'activates' the reserve.  This has to happen before tips can
- * be authorized.
- *
- * @param cls closure, typically a connection to the db
- * @param instance_id which instance is the reserve tied to
- * @param reserve_pub which reserve is topped up or created
- * @param initial_exchange_balance how much money was be added to the reserve
- *           according to the exchange
- * @return transaction status, usually
- *      #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success
- */
-static enum GNUNET_DB_QueryStatus
-postgres_activate_reserve (void *cls,
-                           const char *instance_id,
-                           const struct TALER_ReservePublicKeyP *reserve_pub,
-                           const struct TALER_Amount *initial_exchange_balance)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_auto_from_type (reserve_pub),
-    TALER_PQ_query_param_amount (initial_exchange_balance),
-    GNUNET_PQ_query_param_end
-  };
-
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "activate_reserve",
-                                             params);
-}
-
-
-/**
- * Closure for #lookup_pending_reserves_cb.
- */
-struct LookupPendingReservesContext
+struct LookupTipsContext
 {
   /**
    * Postgres context.
@@ -3841,20 +3180,19 @@ struct LookupPendingReservesContext
   struct PostgresClosure *pg;
 
   /**
-   * Function to call with the results
+   * Array with information about tips generated from this reserve.
    */
-  TALER_MERCHANTDB_PendingReservesCallback cb;
+  struct TALER_MERCHANTDB_TipDetails *tips;
 
   /**
-   * Closure for @e cb
+   * Length of the @e tips array.
    */
-  void *cb_cls;
+  unsigned int tips_length;
 
   /**
    * Set in case of errors.
    */
   enum GNUNET_DB_QueryStatus qs;
-
 };
 
 
@@ -3862,33 +3200,31 @@ struct LookupPendingReservesContext
  * Function to be called with the results of a SELECT statement
  * that has returned @a num_results results about accounts.
  *
- * @param[in,out] cls of type `struct LookupReservesContext *`
+ * @param[in,out] cls of type `struct LookupTipsContext *`
  * @param result the postgres result
  * @param num_results the number of results in @a result
  */
 static void
-lookup_pending_reserves_cb (void *cls,
-                            PGresult *result,
-                            unsigned int num_results)
+lookup_reserve_tips_cb (void *cls,
+                        PGresult *result,
+                        unsigned int num_results)
 {
-  struct LookupPendingReservesContext *lrc = cls;
-  struct PostgresClosure *pg = lrc->pg;
+  struct LookupTipsContext *ltc = cls;
+  struct PostgresClosure *pg = ltc->pg;
 
+  GNUNET_array_grow (ltc->tips,
+                     ltc->tips_length,
+                     num_results);
   for (unsigned int i = 0; i < num_results; i++)
   {
-    struct TALER_ReservePublicKeyP reserve_pub;
-    struct TALER_Amount merchant_initial_balance;
-    char *exchange_url;
-    char *instance_id;
+    struct TALER_MERCHANTDB_TipDetails *td = &ltc->tips[i];
     struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
-                                            &reserve_pub),
-      GNUNET_PQ_result_spec_string ("merchant_id",
-                                    &instance_id),
-      GNUNET_PQ_result_spec_string ("exchange_url",
-                                    &exchange_url),
-      TALER_PQ_RESULT_SPEC_AMOUNT ("merchant_initial_balance",
-                                   &merchant_initial_balance),
+      GNUNET_PQ_result_spec_string ("justification",
+                                    &td->reason),
+      GNUNET_PQ_result_spec_auto_from_type ("tip_id",
+                                            &td->tip_id),
+      TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
+                                   &td->total_amount),
       GNUNET_PQ_result_spec_end
     };
 
@@ -3898,154 +3234,40 @@ lookup_pending_reserves_cb (void *cls,
                                   i))
     {
       GNUNET_break (0);
-      lrc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+      ltc->qs = GNUNET_DB_STATUS_HARD_ERROR;
       return;
     }
-    lrc->cb (lrc->cb_cls,
-             instance_id,
-             exchange_url,
-             &reserve_pub,
-             &merchant_initial_balance);
-    GNUNET_PQ_cleanup_result (rs);
   }
 }
 
 
 /**
- * Lookup reserves pending activation across all instances.
+ * Lookup reserve details.
  *
  * @param cls closure
+ * @param instance_id instance to lookup payments for
+ * @param reserve_pub public key of the reserve to inspect
+ * @param fetch_tips if true, also return information about tips
  * @param cb function to call with reserve summary data
  * @param cb_cls closure for @a cb
  * @return transaction status
  */
 static enum GNUNET_DB_QueryStatus
-postgres_lookup_pending_reserves (void *cls,
-                                  TALER_MERCHANTDB_PendingReservesCallback cb,
-                                  void *cb_cls)
+postgres_lookup_reserve (void *cls,
+                         const char *instance_id,
+                         const struct TALER_ReservePublicKeyP *reserve_pub,
+                         bool fetch_tips,
+                         TALER_MERCHANTDB_ReserveDetailsCallback cb,
+                         void *cb_cls)
 {
   struct PostgresClosure *pg = cls;
-  struct LookupPendingReservesContext lrc = {
+  struct LookupTipsContext ltc = {
     .pg = pg,
-    .cb = cb,
-    .cb_cls = cb_cls
+    .qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
   };
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_end
-  };
-  enum GNUNET_DB_QueryStatus qs;
-
-  check_connection (pg);
-  qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
-                                             "lookup_pending_reserves",
-                                             params,
-                                             &lookup_pending_reserves_cb,
-                                             &lrc);
-  if (lrc.qs < 0)
-    return lrc.qs;
-  return qs;
-}
-
-
-/**
- * Closure for #lookup_reserve_tips_cb().
- */
-struct LookupTipsContext
-{
-  /**
-   * Postgres context.
-   */
-  struct PostgresClosure *pg;
-
-  /**
-   * Array with information about tips generated from this reserve.
-   */
-  struct TALER_MERCHANTDB_TipDetails *tips;
-
-  /**
-   * Length of the @e tips array.
-   */
-  unsigned int tips_length;
-
-  /**
-   * Set in case of errors.
-   */
-  enum GNUNET_DB_QueryStatus qs;
-};
-
-
-/**
- * Function to be called with the results of a SELECT statement
- * that has returned @a num_results results about accounts.
- *
- * @param[in,out] cls of type `struct LookupTipsContext *`
- * @param result the postgres result
- * @param num_results the number of results in @a result
- */
-static void
-lookup_reserve_tips_cb (void *cls,
-                        PGresult *result,
-                        unsigned int num_results)
-{
-  struct LookupTipsContext *ltc = cls;
-  struct PostgresClosure *pg = ltc->pg;
-
-  GNUNET_array_grow (ltc->tips,
-                     ltc->tips_length,
-                     num_results);
-  for (unsigned int i = 0; i < num_results; i++)
-  {
-    struct TALER_MERCHANTDB_TipDetails *td = &ltc->tips[i];
-    struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_string ("justification",
-                                    &td->reason),
-      GNUNET_PQ_result_spec_auto_from_type ("tip_id",
-                                            &td->tip_id),
-      TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
-                                   &td->total_amount),
-      GNUNET_PQ_result_spec_end
-    };
-
-    if (GNUNET_OK !=
-        GNUNET_PQ_extract_result (result,
-                                  rs,
-                                  i))
-    {
-      GNUNET_break (0);
-      ltc->qs = GNUNET_DB_STATUS_HARD_ERROR;
-      return;
-    }
-  }
-}
-
-
-/**
- * Lookup reserve details.
- *
- * @param cls closure
- * @param instance_id instance to lookup payments for
- * @param reserve_pub public key of the reserve to inspect
- * @param fetch_tips if true, also return information about tips
- * @param cb function to call with reserve summary data
- * @param cb_cls closure for @a cb
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_reserve (void *cls,
-                         const char *instance_id,
-                         const struct TALER_ReservePublicKeyP *reserve_pub,
-                         bool fetch_tips,
-                         TALER_MERCHANTDB_ReserveDetailsCallback cb,
-                         void *cb_cls)
-{
-  struct PostgresClosure *pg = cls;
-  struct LookupTipsContext ltc = {
-    .pg = pg,
-    .qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
-  };
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (instance_id),
-    GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+    GNUNET_PQ_query_param_string (instance_id),
+    GNUNET_PQ_query_param_auto_from_type (reserve_pub),
     GNUNET_PQ_query_param_end
   };
   struct GNUNET_TIME_Timestamp creation_time;
@@ -6206,980 +5428,6 @@ postgres_connect (void *cls)
   struct GNUNET_PQ_PreparedStatement ps[] = {
     GNUNET_PQ_make_prepare ("end_transaction",
                             "COMMIT"),
-    /* for postgres_expire_locks() */
-    GNUNET_PQ_make_prepare ("unlock_products",
-                            "DELETE FROM merchant_inventory_locks"
-                            " WHERE expiration < $1"),
-    /* for postgres_expire_locks() */
-    GNUNET_PQ_make_prepare ("unlock_orders",
-                            "DELETE FROM merchant_orders"
-                            " WHERE pay_deadline < $1"),
-    /* for postgres_expire_locks() */
-    GNUNET_PQ_make_prepare ("unlock_contracts",
-                            "DELETE FROM merchant_contract_terms"
-                            " WHERE NOT paid"
-                            "   AND pay_deadline < $1"),
-
-    /* for postgres_delete_order() */
-    GNUNET_PQ_make_prepare ("delete_order",
-                            "WITH ms AS"
-                            "(SELECT merchant_serial "
-                            "   FROM merchant_instances"
-                            "  WHERE merchant_id=$1)"
-                            ", mc AS"
-                            "(SELECT paid"
-                            "   FROM merchant_contract_terms"
-                            "   JOIN ms USING (merchant_serial)"
-                            "  WHERE order_id=$2) "
-                            "DELETE"
-                            " FROM merchant_orders mo"
-                            " WHERE order_id=$2"
-                            "   AND merchant_serial=(SELECT merchant_serial 
FROM ms)"
-                            "   AND (  (pay_deadline < $3)"
-                            "       OR (NOT EXISTS (SELECT paid FROM mc))"
-                            "       OR ($4 AND (FALSE=(SELECT paid FROM mc))) 
);"),
-    GNUNET_PQ_make_prepare ("delete_contract",
-                            "DELETE"
-                            " FROM merchant_contract_terms"
-                            " WHERE order_id=$2 AND"
-                            "   merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND NOT paid;"),
-    /* for postgres_lookup_order() */
-    GNUNET_PQ_make_prepare ("lookup_order",
-                            "SELECT"
-                            " contract_terms"
-                            ",claim_token"
-                            ",h_post_data"
-                            ",pos_key"
-                            " FROM merchant_orders"
-                            " WHERE merchant_orders.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND merchant_orders.order_id=$2"),
-    /* for postgres_lookup_order_summary() */
-    GNUNET_PQ_make_prepare ("lookup_order_summary",
-                            "(SELECT"
-                            " creation_time"
-                            ",order_serial"
-                            " FROM merchant_contract_terms"
-                            " WHERE merchant_contract_terms.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND merchant_contract_terms.order_id=$2)"
-                            "UNION"
-                            "(SELECT"
-                            " creation_time"
-                            ",order_serial"
-                            " FROM merchant_orders"
-                            " WHERE merchant_orders.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND merchant_orders.order_id=$2)"),
-    /* for postgres_lookup_orders() */
-    GNUNET_PQ_make_prepare ("lookup_orders_inc",
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($5 as BOOL)" /* otherwise $5 is unused and 
Postgres unhappy */
-                            ",CAST($6 as BOOL)" /* otherwise $6 is unused and 
Postgres unhappy */
-                            ",CAST($7 as BOOL)" /* otherwise $7 is unused and 
Postgres unhappy */
-                            " FROM merchant_orders"
-                            " WHERE merchant_orders.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial > $3"
-                            "   AND"
-                            "    creation_time > $4"
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2)"
-                            "UNION " /* union ensures elements are distinct! */
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($5 as BOOL)" /* otherwise $5 is unused and 
Postgres unhappy */
-                            ",CAST($6 as BOOL)" /* otherwise $6 is unused and 
Postgres unhappy */
-                            ",CAST($7 as BOOL)" /* otherwise $7 is unused and 
Postgres unhappy */
-                            " FROM merchant_contract_terms"
-                            " WHERE merchant_contract_terms.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial > $3"
-                            "   AND"
-                            "    creation_time > $4"
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2)"
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2"),
-    GNUNET_PQ_make_prepare ("lookup_orders_inc_paid",
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($6 as BOOL)" /* otherwise $6 is unused and 
Postgres unhappy */
-                            ",CAST($7 as BOOL)" /* otherwise $7 is unused and 
Postgres unhappy */
-                            " FROM merchant_orders"
-                            " WHERE merchant_orders.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial > $3"
-                            "   AND"
-                            "    creation_time > $4"
-                            "   AND"
-                            "    NOT CAST($5 as BOOL)" /* unclaimed orders are 
never paid */
-                            "   AND"
-                            "    order_serial NOT IN"
-                            "     (SELECT order_serial"
-                            "      FROM merchant_contract_terms)" /* only 
select unclaimed orders */
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2)"
-                            "UNION " /* union ensures elements are distinct! */
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($6 as BOOL)" /* otherwise $6 is unused and 
Postgres unhappy */
-                            ",CAST($7 as BOOL)" /* otherwise $7 is unused and 
Postgres unhappy */
-                            " FROM merchant_contract_terms"
-                            " WHERE merchant_contract_terms.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial > $3"
-                            "   AND"
-                            "    creation_time > $4"
-                            "   AND"
-                            "    BOOL($5) = paid"
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2)"
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2"),
-    GNUNET_PQ_make_prepare ("lookup_orders_inc_refunded",
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($5 as BOOL)" /* otherwise $5 is unused and 
Postgres unhappy */
-                            ",CAST($7 as BOOL)" /* otherwise $7 is unused and 
Postgres unhappy */
-                            " FROM merchant_orders"
-                            " WHERE merchant_orders.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial > $3"
-                            "   AND"
-                            "    creation_time > $4"
-                            "   AND"
-                            "    NOT CAST($6 as BOOL)"/* unclaimed orders are 
never refunded */
-                            "   AND"
-                            "    order_serial NOT IN"
-                            "     (SELECT order_serial"
-                            "      FROM merchant_contract_terms)" /* only 
select unclaimed orders */
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2)"
-                            "UNION " /* union ensures elements are distinct! */
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($5 as BOOL)" /* otherwise $5 is unused and 
Postgres unhappy */
-                            ",CAST($7 as BOOL)" /* otherwise $7 is unused and 
Postgres unhappy */
-                            " FROM merchant_contract_terms"
-                            " WHERE merchant_contract_terms.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial > $3"
-                            "   AND"
-                            "    creation_time > $4"
-                            "   AND"
-                            "    CAST($6 as BOOL) = (order_serial IN"
-                            "     (SELECT order_serial "
-                            "      FROM merchant_refunds))"
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2)"
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2"),
-    GNUNET_PQ_make_prepare ("lookup_orders_inc_wired",
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($5 as BOOL)" /* otherwise $5 is unused and 
Postgres unhappy */
-                            ",CAST($6 as BOOL)" /* otherwise $6 is unused and 
Postgres unhappy */
-                            " FROM merchant_orders"
-                            " WHERE merchant_orders.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial > $3"
-                            "   AND"
-                            "    creation_time > $4"
-                            "   AND"
-                            "    NOT CAST($7 as BOOL)" /* unclaimed orders are 
never wired */
-                            "   AND"
-                            "    order_serial NOT IN"
-                            "     (SELECT order_serial"
-                            "      FROM merchant_contract_terms)" /* only 
select unclaimed orders */
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2)"
-                            "UNION " /* union ensures elements are distinct! */
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($5 as BOOL)" /* otherwise $5 is unused and 
Postgres unhappy */
-                            ",CAST($6 as BOOL)" /* otherwise $6 is unused and 
Postgres unhappy */
-                            " FROM merchant_contract_terms"
-                            " WHERE merchant_contract_terms.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial > $3"
-                            "   AND"
-                            "    creation_time > $4"
-                            "   AND"
-                            "    BOOL($7) = wired"
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2)"
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2"),
-    GNUNET_PQ_make_prepare ("lookup_orders_inc_paid_refunded",
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($7 as BOOL)" /* otherwise $7 is unused and 
Postgres unhappy */
-                            " FROM merchant_orders"
-                            " WHERE merchant_orders.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial > $3"
-                            "   AND"
-                            "    creation_time > $4"
-                            "   AND"
-                            "    NOT CAST($5 as BOOL)" /* unclaimed orders are 
never paid */
-                            "   AND"
-                            "    NOT CAST($6 as BOOL)"/* unclaimed orders are 
never refunded */
-                            "   AND"
-                            "    order_serial NOT IN"
-                            "     (SELECT order_serial"
-                            "      FROM merchant_contract_terms)" /* only 
select unclaimed orders */
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2)"
-                            "UNION " /* union ensures elements are distinct! */
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($7 as BOOL)" /* otherwise $7 is unused and 
Postgres unhappy */
-                            " FROM merchant_contract_terms"
-                            " WHERE merchant_contract_terms.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial > $3"
-                            "   AND"
-                            "    creation_time > $4"
-                            "   AND"
-                            "    BOOL($5) = paid"
-                            "   AND"
-                            "    BOOL($6) = (order_serial IN"
-                            "     (SELECT order_serial "
-                            "      FROM merchant_refunds))"
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2)"
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2"),
-    GNUNET_PQ_make_prepare ("lookup_orders_inc_paid_wired",
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($6 as BOOL)" /* otherwise $6 is unused and 
Postgres unhappy */
-                            " FROM merchant_orders"
-                            " WHERE merchant_orders.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial > $3"
-                            "   AND"
-                            "    creation_time > $4"
-                            "   AND"
-                            "    NOT CAST($5 as BOOL)" /* unclaimed orders are 
never paid */
-                            "   AND"
-                            "    NOT CAST($7 as BOOL)" /* unclaimed orders are 
never wired */
-                            "   AND"
-                            "    order_serial NOT IN"
-                            "     (SELECT order_serial"
-                            "      FROM merchant_contract_terms)" /* only 
select unclaimed orders */
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2)"
-                            "UNION " /* union ensures elements are distinct! */
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($6 as BOOL)" /* otherwise $6 is unused and 
Postgres unhappy */
-                            " FROM merchant_contract_terms"
-                            " WHERE merchant_contract_terms.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial > $3"
-                            "   AND"
-                            "    creation_time > $4"
-                            "   AND"
-                            "    BOOL($5) = paid"
-                            "   AND"
-                            "    BOOL($7) = wired"
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2)"
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2"),
-    GNUNET_PQ_make_prepare ("lookup_orders_inc_refunded_wired",
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($5 as BOOL)" /* otherwise $5 is unused and 
Postgres unhappy */
-                            " FROM merchant_orders"
-                            " WHERE merchant_orders.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial > $3"
-                            "   AND"
-                            "    creation_time > $4"
-                            "   AND"
-                            "    NOT CAST($6 as BOOL)"/* unclaimed orders are 
never refunded */
-                            "   AND"
-                            "    NOT CAST($7 as BOOL)" /* unclaimed orders are 
never wired */
-                            "   AND"
-                            "    order_serial NOT IN"
-                            "     (SELECT order_serial"
-                            "      FROM merchant_contract_terms)" /* only 
select unclaimed orders */
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2)"
-                            "UNION " /* union ensures elements are distinct! */
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($5 as BOOL)" /* otherwise $5 is unused and 
Postgres unhappy */
-                            " FROM merchant_contract_terms"
-                            " WHERE merchant_contract_terms.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial > $3"
-                            "   AND"
-                            "    creation_time > $4"
-                            "   AND"
-                            "    BOOL($6) = (order_serial IN"
-                            "     (SELECT order_serial "
-                            "      FROM merchant_refunds))"
-                            "   AND"
-                            "    BOOL($7) = wired"
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2)"
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2"),
-    GNUNET_PQ_make_prepare ("lookup_orders_inc_paid_refunded_wired",
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            " FROM merchant_orders"
-                            " WHERE merchant_orders.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial > $3"
-                            "   AND"
-                            "    creation_time > $4"
-                            "   AND"
-                            "    NOT CAST($5 as BOOL)" /* unclaimed orders are 
never paid */
-                            "   AND"
-                            "    NOT CAST($6 as BOOL)"/* unclaimed orders are 
never refunded */
-                            "   AND"
-                            "    NOT CAST($7 as BOOL)" /* unclaimed orders are 
never wired */
-                            "   AND"
-                            "    order_serial NOT IN"
-                            "     (SELECT order_serial"
-                            "      FROM merchant_contract_terms)" /* only 
select unclaimed orders */
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2)"
-                            "UNION " /* union ensures elements are distinct! */
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            " FROM merchant_contract_terms"
-                            " WHERE merchant_contract_terms.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial > $3"
-                            "   AND"
-                            "    creation_time > $4"
-                            "   AND"
-                            "    BOOL($5) = paid"
-                            "   AND"
-                            "    BOOL($6) = (order_serial IN"
-                            "     (SELECT order_serial "
-                            "      FROM merchant_refunds))"
-                            "   AND"
-                            "    BOOL($7) = wired"
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2)"
-                            " ORDER BY order_serial ASC"
-                            " LIMIT $2"),
-    GNUNET_PQ_make_prepare ("lookup_orders_dec",
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($5 as BOOL)" /* otherwise $5 is unused and 
Postgres unhappy */
-                            ",CAST($6 as BOOL)" /* otherwise $6 is unused and 
Postgres unhappy */
-                            ",CAST($7 as BOOL)" /* otherwise $7 is unused and 
Postgres unhappy */
-                            " FROM merchant_orders"
-                            " WHERE merchant_orders.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial < $3"
-                            "   AND"
-                            "    creation_time < $4"
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2)"
-                            "UNION " /* union ensures elements are distinct! */
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($5 as BOOL)" /* otherwise $5 is unused and 
Postgres unhappy */
-                            ",CAST($6 as BOOL)" /* otherwise $6 is unused and 
Postgres unhappy */
-                            ",CAST($7 as BOOL)" /* otherwise $7 is unused and 
Postgres unhappy */
-                            " FROM merchant_contract_terms"
-                            " WHERE merchant_contract_terms.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial < $3"
-                            "   AND"
-                            "    creation_time < $4"
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2)"
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2"),
-    GNUNET_PQ_make_prepare ("lookup_orders_dec_paid",
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($6 as BOOL)" /* otherwise $6 is unused and 
Postgres unhappy */
-                            ",CAST($7 as BOOL)" /* otherwise $7 is unused and 
Postgres unhappy */
-                            " FROM merchant_orders"
-                            " WHERE merchant_orders.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial < $3"
-                            "   AND"
-                            "    creation_time < $4"
-                            "   AND"
-                            "    NOT CAST($5 as BOOL)" /* unclaimed orders are 
never paid */
-                            "   AND"
-                            "    order_serial NOT IN"
-                            "     (SELECT order_serial"
-                            "      FROM merchant_contract_terms)" /* only 
select unclaimed orders */
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2)"
-                            "UNION " /* union ensures elements are distinct! */
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($6 as BOOL)" /* otherwise $6 is unused and 
Postgres unhappy */
-                            ",CAST($7 as BOOL)" /* otherwise $7 is unused and 
Postgres unhappy */
-                            " FROM merchant_contract_terms"
-                            " WHERE merchant_contract_terms.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial < $3"
-                            "   AND"
-                            "    creation_time < $4"
-                            "   AND"
-                            "    BOOL($5) = paid"
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2)"
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2"),
-    GNUNET_PQ_make_prepare ("lookup_orders_dec_refunded",
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($5 as BOOL)" /* otherwise $5 is unused and 
Postgres unhappy */
-                            ",CAST($7 as BOOL)" /* otherwise $7 is unused and 
Postgres unhappy */
-                            " FROM merchant_orders"
-                            " WHERE merchant_orders.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial < $3"
-                            "   AND"
-                            "    creation_time < $4"
-                            "   AND"
-                            "    NOT CAST($6 as BOOL)"/* unclaimed orders are 
never refunded */
-                            "   AND"
-                            "    order_serial NOT IN"
-                            "     (SELECT order_serial"
-                            "      FROM merchant_contract_terms)" /* only 
select unclaimed orders */
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2)"
-                            "UNION " /* union ensures elements are distinct! */
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($5 as BOOL)" /* otherwise $5 is unused and 
Postgres unhappy */
-                            ",CAST($7 as BOOL)" /* otherwise $7 is unused and 
Postgres unhappy */
-                            " FROM merchant_contract_terms"
-                            " WHERE merchant_contract_terms.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial < $3"
-                            "   AND"
-                            "    creation_time < $4"
-                            "   AND"
-                            "    BOOL($6) = (order_serial IN"
-                            "     (SELECT order_serial "
-                            "      FROM merchant_refunds))"
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2)"
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2"),
-    GNUNET_PQ_make_prepare ("lookup_orders_dec_wired",
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($5 as BOOL)" /* otherwise $5 is unused and 
Postgres unhappy */
-                            ",CAST($6 as BOOL)" /* otherwise $6 is unused and 
Postgres unhappy */
-                            " FROM merchant_orders"
-                            " WHERE merchant_orders.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial < $3"
-                            "   AND"
-                            "    creation_time < $4"
-                            "   AND"
-                            "    NOT CAST($7 as BOOL)" /* unclaimed orders are 
never wired */
-                            "   AND"
-                            "    order_serial NOT IN"
-                            "     (SELECT order_serial"
-                            "      FROM merchant_contract_terms)" /* only 
select unclaimed orders */
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2)"
-                            "UNION " /* union ensures elements are distinct! */
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($5 as BOOL)" /* otherwise $5 is unused and 
Postgres unhappy */
-                            ",CAST($6 as BOOL)" /* otherwise $6 is unused and 
Postgres unhappy */
-                            " FROM merchant_contract_terms"
-                            " WHERE merchant_contract_terms.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial < $3"
-                            "   AND"
-                            "    creation_time < $4"
-                            "   AND"
-                            "    BOOL($7) = wired"
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2)"
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2"),
-    GNUNET_PQ_make_prepare ("lookup_orders_dec_paid_refunded",
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($7 as BOOL)" /* otherwise $7 is unused and 
Postgres unhappy */
-                            " FROM merchant_orders"
-                            " WHERE merchant_orders.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial < $3"
-                            "   AND"
-                            "    creation_time < $4"
-                            "   AND"
-                            "    NOT CAST($5 as BOOL)" /* unclaimed orders are 
never paid */
-                            "   AND"
-                            "    NOT CAST($6 as BOOL)"/* unclaimed orders are 
never refunded */
-                            "   AND"
-                            "    order_serial NOT IN"
-                            "     (SELECT order_serial"
-                            "      FROM merchant_contract_terms)" /* only 
select unclaimed orders */
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2)"
-                            "UNION " /* union ensures elements are distinct! */
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($7 as BOOL)" /* otherwise $7 is unused and 
Postgres unhappy */
-                            " FROM merchant_contract_terms"
-                            " WHERE merchant_contract_terms.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial < $3"
-                            "   AND"
-                            "    creation_time < $4"
-                            "   AND"
-                            "    BOOL($5) = paid"
-                            "   AND"
-                            "    BOOL($6) = (order_serial IN"
-                            "     (SELECT order_serial "
-                            "      FROM merchant_refunds))"
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2)"
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2"),
-    GNUNET_PQ_make_prepare ("lookup_orders_dec_paid_wired",
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($6 as BOOL)" /* otherwise $6 is unused and 
Postgres unhappy */
-                            " FROM merchant_orders"
-                            " WHERE merchant_orders.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial < $3"
-                            "   AND"
-                            "    creation_time < $4"
-                            "   AND"
-                            "    NOT CAST($5 as BOOL)" /* unclaimed orders are 
never paid */
-                            "   AND"
-                            "    NOT CAST($7 as BOOL)" /* unclaimed orders are 
never wired */
-                            "   AND"
-                            "    order_serial NOT IN"
-                            "     (SELECT order_serial"
-                            "      FROM merchant_contract_terms)" /* only 
select unclaimed orders */
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2)"
-                            "UNION " /* union ensures elements are distinct! */
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($6 as BOOL)" /* otherwise $6 is unused and 
Postgres unhappy */
-                            " FROM merchant_contract_terms"
-                            " WHERE merchant_contract_terms.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial < $3"
-                            "   AND"
-                            "    creation_time < $4"
-                            "   AND"
-                            "    BOOL($5) = paid"
-                            "   AND"
-                            "    BOOL($7) = wired"
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2)"
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2"),
-    GNUNET_PQ_make_prepare ("lookup_orders_dec_refunded_wired",
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($5 as BOOL)" /* otherwise $5 is unused and 
Postgres unhappy */
-                            " FROM merchant_orders"
-                            " WHERE merchant_orders.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial < $3"
-                            "   AND"
-                            "    creation_time < $4"
-                            "   AND"
-                            "    NOT CAST($6 as BOOL)"/* unclaimed orders are 
never refunded */
-                            "   AND"
-                            "    NOT CAST($7 as BOOL)" /* unclaimed orders are 
never wired */
-                            "   AND"
-                            "    order_serial NOT IN"
-                            "     (SELECT order_serial"
-                            "      FROM merchant_contract_terms)" /* only 
select unclaimed orders */
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2)"
-                            "UNION " /* union ensures elements are distinct! */
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            ",CAST($5 as BOOL)" /* otherwise $5 is unused and 
Postgres unhappy */
-                            " FROM merchant_contract_terms"
-                            " WHERE merchant_contract_terms.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial < $3"
-                            "   AND"
-                            "    creation_time < $4"
-                            "   AND"
-                            "    BOOL($6) = (order_serial IN"
-                            "     (SELECT order_serial "
-                            "      FROM merchant_refunds))"
-                            "   AND"
-                            "    BOOL($7) = wired"
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2)"
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2"),
-    GNUNET_PQ_make_prepare ("lookup_orders_dec_paid_refunded_wired",
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            " FROM merchant_orders"
-                            " WHERE merchant_orders.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial < $3"
-                            "   AND"
-                            "    creation_time < $4"
-                            "   AND"
-                            "    NOT CAST($5 as BOOL)" /* unclaimed orders are 
never paid */
-                            "   AND"
-                            "    NOT CAST($6 as BOOL)"/* unclaimed orders are 
never refunded */
-                            "   AND"
-                            "    NOT CAST($7 as BOOL)" /* unclaimed orders are 
never wired */
-                            "   AND"
-                            "    order_serial NOT IN"
-                            "     (SELECT order_serial"
-                            "      FROM merchant_contract_terms)" /* only 
select unclaimed orders */
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2)"
-                            "UNION " /* union ensures elements are distinct! */
-                            "(SELECT"
-                            " order_id"
-                            ",order_serial"
-                            ",creation_time"
-                            " FROM merchant_contract_terms"
-                            " WHERE merchant_contract_terms.merchant_serial="
-                            "     (SELECT merchant_serial "
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND"
-                            "    order_serial < $3"
-                            "   AND"
-                            "    creation_time < $4"
-                            "   AND"
-                            "    BOOL($5) = paid"
-                            "   AND"
-                            "    BOOL($6) = (order_serial IN"
-                            "     (SELECT order_serial "
-                            "      FROM merchant_refunds))"
-                            "   AND"
-                            "    BOOL($7) = wired"
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2)"
-                            " ORDER BY order_serial DESC"
-                            " LIMIT $2"),
-    /* for postgres_insert_order() */
-    GNUNET_PQ_make_prepare ("insert_order",
-                            "INSERT INTO merchant_orders"
-                            "(merchant_serial"
-                            ",order_id"
-                            ",pay_deadline"
-                            ",claim_token"
-                            ",h_post_data"
-                            ",creation_time"
-                            ",contract_terms"
-                            ",pos_key"
-                            ",pos_algorithm)"
-                            " SELECT merchant_serial,"
-                            " $2, $3, $4, $5, $6, $7, $8, $9"
-                            " FROM merchant_instances"
-                            " WHERE merchant_id=$1"),
-    /* for postgres_unlock_inventory() */
-    GNUNET_PQ_make_prepare ("unlock_inventory",
-                            "DELETE"
-                            " FROM merchant_inventory_locks"
-                            " WHERE lock_uuid=$1"),
-    /* for postgres_insert_order_lock() */
-    GNUNET_PQ_make_prepare ("insert_order_lock",
-                            "WITH tmp AS"
-                            "  (SELECT "
-                            "      product_serial"
-                            "     ,merchant_serial"
-                            "     ,total_stock"
-                            "     ,total_sold"
-                            "     ,total_lost"
-                            "   FROM merchant_inventory"
-                            "   WHERE product_id=$3"
-                            "     AND merchant_serial="
-                            "     (SELECT merchant_serial"
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1))"
-                            " INSERT INTO merchant_order_locks"
-                            " (product_serial"
-                            " ,total_locked"
-                            " ,order_serial)"
-                            " SELECT tmp.product_serial, $4, order_serial"
-                            "   FROM merchant_orders"
-                            "   JOIN tmp USING(merchant_serial)"
-                            "   WHERE order_id=$2 AND"
-                            "     tmp.total_stock - tmp.total_sold - 
tmp.total_lost - $4 >= "
-                            "     (SELECT COALESCE(SUM(total_locked), 0)"
-                            "        FROM merchant_inventory_locks"
-                            "        WHERE product_serial=tmp.product_serial) 
+ "
-                            "     (SELECT COALESCE(SUM(total_locked), 0)"
-                            "        FROM merchant_order_locks"
-                            "        WHERE 
product_serial=tmp.product_serial)"),
-    /* for postgres_lookup_contract_terms() */
-    GNUNET_PQ_make_prepare ("lookup_contract_terms",
-                            "SELECT"
-                            " contract_terms"
-                            ",order_serial"
-                            ",claim_token"
-                            ",paid"
-                            " FROM merchant_contract_terms"
-                            " WHERE order_id=$2"
-                            "   AND merchant_serial="
-                            "     (SELECT merchant_serial"
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"),
-    /* for postgres_lookup_contract_terms() */
-    GNUNET_PQ_make_prepare ("lookup_contract_terms2",
-                            "SELECT"
-                            " contract_terms"
-                            ",order_serial"
-                            ",claim_token"
-                            ",paid"
-                            ",pos_key"
-                            ",pos_algorithm"
-                            " FROM merchant_contract_terms"
-                            " WHERE order_id=$2"
-                            "   AND merchant_serial="
-                            "     (SELECT merchant_serial"
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"),
-    /* for postgres_insert_contract_terms() */
-    GNUNET_PQ_make_prepare ("insert_contract_terms",
-                            "INSERT INTO merchant_contract_terms"
-                            "(order_serial"
-                            ",merchant_serial"
-                            ",order_id"
-                            ",contract_terms"
-                            ",h_contract_terms"
-                            ",creation_time"
-                            ",pay_deadline"
-                            ",refund_deadline"
-                            ",fulfillment_url"
-                            ",claim_token"
-                            ",pos_key"
-                            ",pos_algorithm)"
-                            "SELECT"
-                            " mo.order_serial"
-                            ",mo.merchant_serial"
-                            ",mo.order_id"
-                            ",$3"  /* contract_terms */
-                            ",$4"  /* h_contract_terms */
-                            ",mo.creation_time"
-                            ",$5" /* pay_deadline */
-                            ",$6" /* refund_deadline */
-                            ",$7" /* fulfillment_url */
-                            ",mo.claim_token"
-                            ",mo.pos_key"
-                            ",mo.pos_algorithm"
-                            " FROM merchant_orders mo"
-                            " WHERE order_id=$2"
-                            "   AND merchant_serial="
-                            "     (SELECT merchant_serial"
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            " RETURNING order_serial"),
-    /* for postgres_update_contract_terms() */
-    GNUNET_PQ_make_prepare ("update_contract_terms",
-                            "UPDATE merchant_contract_terms SET"
-                            " contract_terms=$3"
-                            ",h_contract_terms=$4"
-                            ",pay_deadline=$5"
-                            ",refund_deadline=$6"
-                            ",fulfillment_url=$7"
-                            " WHERE order_id=$2"
-                            "   AND merchant_serial="
-                            "     (SELECT merchant_serial"
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"),
-    /* for postgres_delete_contract_terms() */
-    GNUNET_PQ_make_prepare ("delete_contract_terms",
-                            "DELETE FROM merchant_contract_terms"
-                            " WHERE order_id=$2"
-                            "   AND merchant_serial="
-                            "     (SELECT merchant_serial"
-                            "        FROM merchant_instances"
-                            "        WHERE merchant_id=$1)"
-                            "   AND ( ( (pay_deadline < $4) AND"
-                            "           (NOT paid) ) OR"
-                            "         (creation_time + $3 < $4) )"),
     /* for postgres_lookup_deposits() */
     GNUNET_PQ_make_prepare ("lookup_deposits",
                             "SELECT"
@@ -8426,19 +6674,32 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
     = &TMH_PG_update_product;
   plugin->lock_product
     = &TMH_PG_lock_product;
-  plugin->expire_locks = &postgres_expire_locks;
-  plugin->delete_order = &postgres_delete_order;
-  plugin->lookup_order = &postgres_lookup_order;
-  plugin->lookup_order_summary = &postgres_lookup_order_summary;
-  plugin->lookup_orders = &postgres_lookup_orders;
-  plugin->insert_order = &postgres_insert_order;
-  plugin->unlock_inventory = &postgres_unlock_inventory;
-  plugin->insert_order_lock = &postgres_insert_order_lock;
-  plugin->lookup_contract_terms = &postgres_lookup_contract_terms;
-  plugin->lookup_contract_terms2 = &postgres_lookup_contract_terms2;
-  plugin->insert_contract_terms = &postgres_insert_contract_terms;
-  plugin->update_contract_terms = &postgres_update_contract_terms;
-  plugin->delete_contract_terms = &postgres_delete_contract_terms;
+  plugin->expire_locks
+    = &TMH_PG_expire_locks;
+  plugin->delete_order
+    = &TMH_PG_delete_order;
+  plugin->lookup_order
+    = &TMH_PG_lookup_order;
+  plugin->lookup_order_summary
+    = &TMH_PG_lookup_order_summary;
+  plugin->lookup_orders
+    = &TMH_PG_lookup_orders;
+  plugin->insert_order
+    = &TMH_PG_insert_order;
+  plugin->unlock_inventory
+    = &TMH_PG_unlock_inventory;
+  plugin->insert_order_lock
+    = &TMH_PG_insert_order_lock;
+  plugin->lookup_contract_terms
+    = &TMH_PG_lookup_contract_terms;
+  plugin->lookup_contract_terms2
+    = &TMH_PG_lookup_contract_terms2;
+  plugin->insert_contract_terms
+    = &TMH_PG_insert_contract_terms;
+  plugin->update_contract_terms
+    = &TMH_PG_update_contract_terms;
+  plugin->delete_contract_terms
+    = &TMH_PG_delete_contract_terms;
   plugin->lookup_deposits = &postgres_lookup_deposits;
   plugin->insert_exchange_signkey = &postgres_insert_exchange_signkey;
   plugin->insert_deposit = &postgres_insert_deposit;

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

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