gnunet-svn
[Top][All Lists]
Advanced

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

[taler-exchange] branch master updated: move few more functions


From: gnunet
Subject: [taler-exchange] branch master updated: move few more functions
Date: Thu, 10 Nov 2022 16:37:56 +0100

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

joseph-xu pushed a commit to branch master
in repository exchange.

The following commit(s) were added to refs/heads/master by this push:
     new 945821cb move few more functions
945821cb is described below

commit 945821cbc842644f9d10de4ef36e8ef03d2d2253
Author: Joseph <Joseph.xu@efrei.net>
AuthorDate: Thu Nov 10 10:37:28 2022 -0500

    move few more functions
---
 src/exchangedb/Makefile.am                         |   38 +-
 src/exchangedb/pg_activate_signing_key.c           |   58 +
 ...gation_tracking.h => pg_activate_signing_key.h} |   22 +-
 src/exchangedb/pg_begin_revolving_shard.c          |  263 ++
 src/exchangedb/pg_begin_revolving_shard.h          |   48 +
 src/exchangedb/pg_do_batch_withdraw_insert.c       |   77 +
 src/exchangedb/pg_do_batch_withdraw_insert.h       |   52 +
 src/exchangedb/pg_do_purse_deposit.c               |   80 +
 src/exchangedb/pg_do_purse_deposit.h               |   61 +
 src/exchangedb/pg_do_purse_merge.c                 |   92 +
 src/exchangedb/pg_do_purse_merge.h                 |   57 +
 src/exchangedb/pg_do_reserve_purse.c               |  109 +
 src/exchangedb/pg_do_reserve_purse.h               |   57 +
 src/exchangedb/pg_get_drain_profit.c               |   78 +
 ...ggregation_tracking.h => pg_get_drain_profit.h} |   30 +-
 src/exchangedb/pg_get_extension_manifest.c         |   68 +
 ...tion_tracking.h => pg_get_extension_manifest.h} |   25 +-
 src/exchangedb/pg_get_purse_deposit.c              |   85 +
 src/exchangedb/pg_get_purse_deposit.h              |   53 +
 src/exchangedb/pg_insert_aggregation_tracking.h    |    1 +
 src/exchangedb/pg_insert_contract.c                |   93 +
 ...aggregation_tracking.h => pg_insert_contract.h} |   27 +-
 src/exchangedb/pg_insert_denomination_info.c       |  105 +
 ...on_tracking.h => pg_insert_denomination_info.h} |   26 +-
 src/exchangedb/pg_insert_drain_profit.c            |   64 +
 ...egation_tracking.h => pg_insert_drain_profit.h} |   28 +-
 src/exchangedb/pg_insert_history_request.c         |   66 +
 src/exchangedb/pg_insert_history_request.h         |   53 +
 .../pg_insert_kyc_requirement_for_account.c        |   62 +
 ...g.h => pg_insert_kyc_requirement_for_account.h} |   26 +-
 src/exchangedb/pg_insert_kyc_requirement_process.c |   75 +
 ...cking.h => pg_insert_kyc_requirement_process.h} |   30 +-
 src/exchangedb/pg_kyc_provider_account_lookup.c    |   65 +
 ...tracking.h => pg_kyc_provider_account_lookup.h} |   29 +-
 src/exchangedb/pg_lookup_global_fee_by_time.c      |  189 ++
 src/exchangedb/pg_lookup_global_fee_by_time.h      |   51 +
 src/exchangedb/pg_lookup_kyc_process_by_account.c  |   78 +
 src/exchangedb/pg_lookup_kyc_process_by_account.h  |   50 +
 src/exchangedb/pg_lookup_kyc_requirement_by_row.c  |   60 +
 ...acking.h => pg_lookup_kyc_requirement_by_row.h} |   26 +-
 src/exchangedb/pg_lookup_wire_fee_by_time.c        |  158 +
 src/exchangedb/pg_lookup_wire_fee_by_time.h        |   76 +
 src/exchangedb/{pg_prefligth.c => pg_preflight.c}  |    4 +-
 src/exchangedb/{pg_prefligth.h => pg_preflight.h}  |    4 +-
 src/exchangedb/pg_profit_drains_get_pending.c      |   79 +
 src/exchangedb/pg_profit_drains_get_pending.h      |   52 +
 ...artitions.c => pg_profit_drains_set_finished.c} |   35 +-
 ..._tracking.h => pg_profit_drains_set_finished.h} |   20 +-
 src/exchangedb/{pg_prefligth.c => pg_rollback.c}   |   42 +-
 .../{pg_setup_partitions.c => pg_rollback.h}       |   26 +-
 .../pg_select_aggregation_amounts_for_kyc_check.c  |  158 +
 .../pg_select_aggregation_amounts_for_kyc_check.h  |   47 +
 src/exchangedb/pg_select_contract.c                |   66 +
 src/exchangedb/pg_select_contract.h                |   47 +
 src/exchangedb/pg_select_contract_by_purse.c       |   63 +
 ...on_tracking.h => pg_select_contract_by_purse.h} |   24 +-
 .../pg_select_merge_amounts_for_kyc_check.c        |  160 +
 .../pg_select_merge_amounts_for_kyc_check.h        |   47 +
 src/exchangedb/pg_select_purse_merge.c             |   74 +
 src/exchangedb/pg_select_purse_merge.h             |   49 +
 src/exchangedb/pg_select_satisfied_kyc_processes.c |  152 +
 ...cking.h => pg_select_satisfied_kyc_processes.h} |   27 +-
 .../pg_select_withdraw_amounts_for_kyc_check.c     |  158 +
 .../pg_select_withdraw_amounts_for_kyc_check.h     |   47 +
 src/exchangedb/pg_setup_partitions.c               |   47 +
 src/exchangedb/{pg_prefligth.c => pg_start.c}      |   49 +-
 src/exchangedb/{pg_prefligth.h => pg_start.h}      |   25 +-
 .../{pg_prefligth.c => pg_start_read_committed.c}  |   48 +-
 .../{pg_prefligth.h => pg_start_read_committed.h}  |   26 +-
 .../{pg_prefligth.c => pg_start_read_only.c}       |   48 +-
 .../{pg_prefligth.h => pg_start_read_only.h}       |   25 +-
 src/exchangedb/pg_update_auditor.c                 |   59 +
 src/exchangedb/pg_update_auditor.h                 |   47 +
 src/exchangedb/pg_update_kyc_process_by_row.c      |  103 +
 src/exchangedb/pg_update_kyc_process_by_row.h      |   51 +
 src/exchangedb/plugin_exchangedb_postgres.c        | 3207 +++-----------------
 76 files changed, 4785 insertions(+), 3122 deletions(-)

diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am
index 1de08006..4843503c 100644
--- a/src/exchangedb/Makefile.am
+++ b/src/exchangedb/Makefile.am
@@ -70,16 +70,50 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
   plugin_exchangedb_common.c plugin_exchangedb_common.h \
   plugin_exchangedb_postgres.c pg_helper.h \
   pg_insert_aggregation_tracking.h pg_insert_aggregation_tracking.c \
+  pg_select_aggregation_amounts_for_kyc_check.h 
pg_select_aggregation_amounts_for_kyc_check.c \
+  pg_lookup_wire_fee_by_time.h pg_lookup_wire_fee_by_time.c \
+  pg_select_satisfied_kyc_processes.h pg_select_satisfied_kyc_processes.c \
+  pg_kyc_provider_account_lookup.h pg_kyc_provider_account_lookup.c \
+  pg_lookup_kyc_requirement_by_row.h pg_lookup_kyc_requirement_by_row.c \
+  pg_insert_kyc_requirement_for_account.h 
pg_insert_kyc_requirement_for_account.c \
+  pg_lookup_kyc_process_by_account.h pg_lookup_kyc_process_by_account.c \
+  pg_update_kyc_process_by_row.h pg_update_kyc_process_by_row.c \
+  pg_insert_kyc_requirement_process.h pg_insert_kyc_requirement_process.c \
+  pg_select_withdraw_amounts_for_kyc_check.h 
pg_select_withdraw_amounts_for_kyc_check.c \
+  pg_select_merge_amounts_for_kyc_check.h 
pg_select_merge_amounts_for_kyc_check.c \
+  pg_profit_drains_set_finished.h pg_profit_drains_set_finished.c \
+  pg_profit_drains_get_pending.h pg_profit_drains_get_pending.c \
+  pg_get_drain_profit.h pg_get_drain_profit.c \
+  pg_get_purse_deposit.h pg_get_purse_deposit.c \
+  pg_insert_contract.h pg_insert_contract.c \
+  pg_select_contract.h pg_select_contract.c \
+  pg_select_purse_merge.h pg_select_purse_merge.c \
+  pg_select_contract_by_purse.h pg_select_contract_by_purse.c \
+  pg_insert_drain_profit.h pg_insert_drain_profit.c \
+  pg_do_reserve_purse.h pg_do_reserve_purse.c \
+  pg_lookup_global_fee_by_time.h pg_lookup_global_fee_by_time.c \
+  pg_do_purse_deposit.h pg_do_purse_deposit.c \
+  pg_activate_signing_key.h pg_activate_signing_key.c \
+  pg_update_auditor.h pg_update_auditor.c \
+  pg_begin_revolving_shard.h pg_begin_revolving_shard.c \
+  pg_get_extension_manifest.h pg_get_extension_manifest.c \
+  pg_insert_history_request.h pg_insert_history_request.c \
+  pg_do_purse_merge.h pg_do_purse_merge.c \
+  pg_start_read_committed.h pg_start_read_committed.c \
+  pg_start_read_only.h pg_start_read_only.c \
+  pg_insert_denomination_info.h pg_insert_denomination_info.c \
+  pg_do_batch_withdraw_insert.h pg_do_batch_withdraw_insert.c \
   pg_do_reserve_open.c pg_do_reserve_open.h \
   pg_do_withdraw.h pg_do_withdraw.c \
   pg_create_shard_tables.h pg_create_shard_tables.c \
-  pg_prefligth.h pg_prefligth.c \
+  pg_preflight.h pg_preflight.c \
   pg_iterate_active_signkeys.h pg_iterate_active_signkeys.c \
   pg_commit.h pg_commit.c \
   pg_get_coin_transactions.c pg_get_coin_transactions.h \
   pg_get_expired_reserves.c pg_get_expired_reserves.h \
+  pg_start.h pg_start.c \
+  pg_rollback.h pg_rollback.c \
   pg_setup_partitions.h pg_setup_partitions.c \
-  pg_insert_aggregation_tracking.h pg_insert_aggregation_tracking.c \
   pg_get_purse_request.c pg_get_purse_request.h \
   pg_get_reserve_history.c pg_get_reserve_history.h \
   pg_get_unfinished_close_requests.c pg_get_unfinished_close_requests.h \
diff --git a/src/exchangedb/pg_activate_signing_key.c 
b/src/exchangedb/pg_activate_signing_key.c
new file mode 100644
index 00000000..fab2a0ff
--- /dev/null
+++ b/src/exchangedb/pg_activate_signing_key.c
@@ -0,0 +1,58 @@
+/*
+   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 exchangedb/pg_activate_signing_key.c
+ * @brief Implementation of the activate_signing_key function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_activate_signing_key.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_activate_signing_key (
+  void *cls,
+  const struct TALER_ExchangePublicKeyP *exchange_pub,
+  const struct TALER_EXCHANGEDB_SignkeyMetaData *meta,
+  const struct TALER_MasterSignatureP *master_sig)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam iparams[] = {
+    GNUNET_PQ_query_param_auto_from_type (exchange_pub),
+    GNUNET_PQ_query_param_timestamp (&meta->start),
+    GNUNET_PQ_query_param_timestamp (&meta->expire_sign),
+    GNUNET_PQ_query_param_timestamp (&meta->expire_legal),
+    GNUNET_PQ_query_param_auto_from_type (master_sig),
+    GNUNET_PQ_query_param_end
+  };
+
+  PREPARE (pg,
+           "insert_signkey",
+           "INSERT INTO exchange_sign_keys "
+           "(exchange_pub"
+           ",valid_from"
+           ",expire_sign"
+           ",expire_legal"
+           ",master_sig"
+           ") VALUES "
+           "($1, $2, $3, $4, $5);");
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "insert_signkey",
+                                             iparams);
+}
diff --git a/src/exchangedb/pg_insert_aggregation_tracking.h 
b/src/exchangedb/pg_activate_signing_key.h
similarity index 62%
copy from src/exchangedb/pg_insert_aggregation_tracking.h
copy to src/exchangedb/pg_activate_signing_key.h
index e67c0e8e..2d4df067 100644
--- a/src/exchangedb/pg_insert_aggregation_tracking.h
+++ b/src/exchangedb/pg_activate_signing_key.h
@@ -14,29 +14,31 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_insert_aggregation_tracking.h
- * @brief implementation of the insert_aggregation_tracking function for 
Postgres
+ * @file exchangedb/pg_activate_signing_key.h
+ * @brief implementation of the activate_signing_key function for Postgres
  * @author Christian Grothoff
  */
-#ifndef PG_INSERT_AGGREGATION_TRACKING_H
-#define PG_INSERT_AGGREGATION_TRACKING_H
+#ifndef PG_ACTIVATE_SIGNING_KEY_H
+#define PG_ACTIVATE_SIGNING_KEY_H
 
 #include "taler_util.h"
 #include "taler_json_lib.h"
 #include "taler_exchangedb_plugin.h"
 
 /**
- * Function called to insert aggregation information into the DB.
+ * Add signing key.
  *
  * @param cls closure
- * @param wtid the raw wire transfer identifier we used
- * @param deposit_serial_id row in the deposits table for which this is 
aggregation data
+ * @param exchange_pub the exchange online signing public key
+ * @param meta meta data about @a exchange_pub
+ * @param master_sig master signature to add
  * @return transaction status code
  */
 enum GNUNET_DB_QueryStatus
-TEH_PG_insert_aggregation_tracking (
+TEH_PG_activate_signing_key (
   void *cls,
-  const struct TALER_WireTransferIdentifierRawP *wtid,
-  unsigned long long deposit_serial_id);
+  const struct TALER_ExchangePublicKeyP *exchange_pub,
+  const struct TALER_EXCHANGEDB_SignkeyMetaData *meta,
+  const struct TALER_MasterSignatureP *master_sig);
 
 #endif
diff --git a/src/exchangedb/pg_begin_revolving_shard.c 
b/src/exchangedb/pg_begin_revolving_shard.c
new file mode 100644
index 00000000..888d7fd2
--- /dev/null
+++ b/src/exchangedb/pg_begin_revolving_shard.c
@@ -0,0 +1,263 @@
+/*
+   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 exchangedb/pg_begin_revolving_shard.c
+ * @brief Implementation of the begin_revolving_shard function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_begin_revolving_shard.h"
+#include "pg_commit.h"
+#include "pg_helper.h"
+#include "pg_start.h"
+#include "pg_rollback.h"
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_begin_revolving_shard (void *cls,
+                                const char *job_name,
+                                uint32_t shard_size,
+                                uint32_t shard_limit,
+                                uint32_t *start_row,
+                                uint32_t *end_row)
+{
+  struct PostgresClosure *pg = cls;
+
+  GNUNET_assert (shard_limit <= 1U + (uint32_t) INT_MAX);
+  GNUNET_assert (shard_limit > 0);
+  GNUNET_assert (shard_size > 0);
+  for (unsigned int retries = 0; retries<3; retries++)
+  {
+    if (GNUNET_OK !=
+        TEH_PG_start (pg,
+                        "begin_revolving_shard"))
+    {
+      GNUNET_break (0);
+      return GNUNET_DB_STATUS_HARD_ERROR;
+    }
+
+    /* First, find last 'end_row' */
+    {
+      enum GNUNET_DB_QueryStatus qs;
+      uint32_t last_end;
+      struct GNUNET_PQ_QueryParam params[] = {
+        GNUNET_PQ_query_param_string (job_name),
+        GNUNET_PQ_query_param_end
+      };
+      struct GNUNET_PQ_ResultSpec rs[] = {
+        GNUNET_PQ_result_spec_uint32 ("end_row",
+                                      &last_end),
+        GNUNET_PQ_result_spec_end
+      };
+          /* Used in #postgres_begin_revolving_shard() */
+      PREPARE(pg,
+              "get_last_revolving_shard",
+              "SELECT"
+              " end_row"
+              " FROM revolving_work_shards"
+              " WHERE job_name=$1"
+              " ORDER BY end_row DESC"
+              " LIMIT 1;");
+      qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                     
"get_last_revolving_shard",
+                                                     params,
+                                                     rs);
+      switch (qs)
+      {
+      case GNUNET_DB_STATUS_HARD_ERROR:
+        GNUNET_break (0);
+        TEH_PG_rollback (pg);
+        return qs;
+      case GNUNET_DB_STATUS_SOFT_ERROR:
+        TEH_PG_rollback (pg);
+        continue;
+      case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+        *start_row = 1U + last_end;
+        break;
+      case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+        *start_row = 0; /* base-case: no shards yet */
+        break; /* continued below */
+      }
+    } /* get_last_shard */
+
+    if (*start_row < shard_limit)
+    {
+      /* Claim fresh shard */
+      enum GNUNET_DB_QueryStatus qs;
+      struct GNUNET_TIME_Absolute now;
+      struct GNUNET_PQ_QueryParam params[] = {
+        GNUNET_PQ_query_param_string (job_name),
+        GNUNET_PQ_query_param_absolute_time (&now),
+        GNUNET_PQ_query_param_uint32 (start_row),
+        GNUNET_PQ_query_param_uint32 (end_row),
+        GNUNET_PQ_query_param_end
+      };
+
+      *end_row = GNUNET_MIN (shard_limit,
+                             *start_row + shard_size - 1);
+      now = GNUNET_TIME_absolute_get ();
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                  "Trying to claim shard %llu-%llu\n",
+                  (unsigned long long) *start_row,
+                  (unsigned long long) *end_row);
+
+    /* Used in #postgres_claim_revolving_shard() */
+      PREPARE (pg,
+               "create_revolving_shard",
+               "INSERT INTO revolving_work_shards"
+               "(job_name"
+               ",last_attempt"
+               ",start_row"
+               ",end_row"
+               ",active"
+               ") VALUES "
+               "($1, $2, $3, $4, TRUE);");
+      qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                               "create_revolving_shard",
+                                               params);
+      switch (qs)
+      {
+      case GNUNET_DB_STATUS_HARD_ERROR:
+        GNUNET_break (0);
+        TEH_PG_rollback (pg);
+        return qs;
+      case GNUNET_DB_STATUS_SOFT_ERROR:
+        TEH_PG_rollback (pg);
+        continue;
+      case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+        /* continued below (with commit) */
+        break;
+      case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+        /* someone else got this shard already,
+           try again */
+        TEH_PG_rollback (pg);
+        continue;
+      }
+    } /* end create fresh reovlving shard */
+    else
+    {
+      /* claim oldest existing shard */
+      enum GNUNET_DB_QueryStatus qs;
+      struct GNUNET_PQ_QueryParam params[] = {
+        GNUNET_PQ_query_param_string (job_name),
+        GNUNET_PQ_query_param_end
+      };
+      struct GNUNET_PQ_ResultSpec rs[] = {
+        GNUNET_PQ_result_spec_uint32 ("start_row",
+                                      start_row),
+        GNUNET_PQ_result_spec_uint32 ("end_row",
+                                      end_row),
+        GNUNET_PQ_result_spec_end
+      };
+    /* Used in #postgres_begin_revolving_shard() */
+      PREPARE (pg,
+               "get_open_revolving_shard",
+               "SELECT"
+               " start_row"
+               ",end_row"
+               " FROM revolving_work_shards"
+               " WHERE job_name=$1"
+               "   AND active=FALSE"
+               " ORDER BY last_attempt ASC"
+               " LIMIT 1;");
+      qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                     
"get_open_revolving_shard",
+                                                     params,
+                                                     rs);
+      switch (qs)
+      {
+      case GNUNET_DB_STATUS_HARD_ERROR:
+        GNUNET_break (0);
+        TEH_PG_rollback (pg);
+        return qs;
+      case GNUNET_DB_STATUS_SOFT_ERROR:
+        TEH_PG_rollback (pg);
+        continue;
+      case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+        /* no open shards available */
+        TEH_PG_rollback (pg);
+        return qs;
+      case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+        {
+          enum GNUNET_DB_QueryStatus qs;
+          struct GNUNET_TIME_Timestamp now;
+          struct GNUNET_PQ_QueryParam params[] = {
+            GNUNET_PQ_query_param_string (job_name),
+            GNUNET_PQ_query_param_timestamp (&now),
+            GNUNET_PQ_query_param_uint32 (start_row),
+            GNUNET_PQ_query_param_uint32 (end_row),
+            GNUNET_PQ_query_param_end
+          };
+
+          now = GNUNET_TIME_timestamp_get ();
+
+              /* Used in #postgres_begin_revolving_shard() */
+          PREPARE (pg,
+                   "reclaim_revolving_shard",
+                   "UPDATE revolving_work_shards"
+                   " SET last_attempt=$2"
+                   "    ,active=TRUE"
+                   " WHERE job_name=$1"
+                   "   AND start_row=$3"
+                   "   AND end_row=$4");
+          qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                                   "reclaim_revolving_shard",
+                                                   params);
+          switch (qs)
+          {
+          case GNUNET_DB_STATUS_HARD_ERROR:
+            GNUNET_break (0);
+            TEH_PG_rollback (pg);
+            return qs;
+          case GNUNET_DB_STATUS_SOFT_ERROR:
+            TEH_PG_rollback (pg);
+            continue;
+          case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+            break; /* continue with commit */
+          case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+            GNUNET_break (0); /* logic error, should be impossible */
+            TEH_PG_rollback (pg);
+            return GNUNET_DB_STATUS_HARD_ERROR;
+          }
+        }
+        break; /* continue with commit */
+      }
+    } /* end claim oldest existing shard */
+
+    /* commit */
+    {
+      enum GNUNET_DB_QueryStatus qs;
+
+      qs = TEH_PG_commit (pg);
+      switch (qs)
+      {
+      case GNUNET_DB_STATUS_HARD_ERROR:
+        GNUNET_break (0);
+        TEH_PG_rollback (pg);
+        return qs;
+      case GNUNET_DB_STATUS_SOFT_ERROR:
+        TEH_PG_rollback (pg);
+        continue;
+      case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+      case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+        return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
+      }
+    }
+  } /* retry 'for' loop */
+  return GNUNET_DB_STATUS_SOFT_ERROR;
+}
diff --git a/src/exchangedb/pg_begin_revolving_shard.h 
b/src/exchangedb/pg_begin_revolving_shard.h
new file mode 100644
index 00000000..bdbca4f1
--- /dev/null
+++ b/src/exchangedb/pg_begin_revolving_shard.h
@@ -0,0 +1,48 @@
+/*
+   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 exchangedb/pg_begin_revolving_shard.h
+ * @brief implementation of the begin_revolving_shard function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_BEGIN_REVOLVING_SHARD_H
+#define PG_BEGIN_REVOLVING_SHARD_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+
+/**
+ * Function called to grab a revolving work shard on an operation @a op. Runs
+ * in its own transaction. Returns the oldest inactive shard.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param job_name name of the operation to grab a revolving shard for
+ * @param shard_size desired shard size
+ * @param shard_limit exclusive end of the shard range
+ * @param[out] start_row inclusive start row of the shard (returned)
+ * @param[out] end_row inclusive end row of the shard (returned)
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_begin_revolving_shard (void *cls,
+                                const char *job_name,
+                                uint32_t shard_size,
+                                uint32_t shard_limit,
+                                uint32_t *start_row,
+                              uint32_t *end_row);
+#endif
diff --git a/src/exchangedb/pg_do_batch_withdraw_insert.c 
b/src/exchangedb/pg_do_batch_withdraw_insert.c
new file mode 100644
index 00000000..8d3aac68
--- /dev/null
+++ b/src/exchangedb/pg_do_batch_withdraw_insert.c
@@ -0,0 +1,77 @@
+/*
+   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 exchangedb/pg_do_batch_withdraw_insert.c
+ * @brief Implementation of the do_batch_withdraw_insert function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_do_batch_withdraw_insert.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_do_batch_withdraw_insert (
+  void *cls,
+  const struct TALER_CsNonce *nonce,
+  const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable,
+  struct GNUNET_TIME_Timestamp now,
+  uint64_t ruuid,
+  bool *denom_unknown,
+  bool *conflict,
+  bool *nonce_reuse)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    NULL == nonce
+    ? GNUNET_PQ_query_param_null ()
+    : GNUNET_PQ_query_param_auto_from_type (nonce),
+    TALER_PQ_query_param_amount (&collectable->amount_with_fee),
+    GNUNET_PQ_query_param_auto_from_type (&collectable->denom_pub_hash),
+    GNUNET_PQ_query_param_uint64 (&ruuid),
+    GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_sig),
+    GNUNET_PQ_query_param_auto_from_type (&collectable->h_coin_envelope),
+    TALER_PQ_query_param_blinded_denom_sig (&collectable->sig),
+    GNUNET_PQ_query_param_timestamp (&now),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_bool ("denom_unknown",
+                                denom_unknown),
+    GNUNET_PQ_result_spec_bool ("conflict",
+                                conflict),
+    GNUNET_PQ_result_spec_bool ("nonce_reuse",
+                                nonce_reuse),
+    GNUNET_PQ_result_spec_end
+  };
+ /* Used in #postgres_do_batch_withdraw_insert() to store
+       the signature of a blinded coin with the blinded coin's
+       details. */
+  PREPARE (pg,
+           "call_batch_withdraw_insert",
+           "SELECT "
+           " out_denom_unknown AS denom_unknown"
+           ",out_conflict AS conflict"
+           ",out_nonce_reuse AS nonce_reuse"
+           " FROM exchange_do_batch_withdraw_insert"
+           " ($1,$2,$3,$4,$5,$6,$7,$8,$9);");
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   
"call_batch_withdraw_insert",
+                                                   params,
+                                                   rs);
+}
diff --git a/src/exchangedb/pg_do_batch_withdraw_insert.h 
b/src/exchangedb/pg_do_batch_withdraw_insert.h
new file mode 100644
index 00000000..6bc1a9a4
--- /dev/null
+++ b/src/exchangedb/pg_do_batch_withdraw_insert.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 exchangedb/pg_do_batch_withdraw_insert.h
+ * @brief implementation of the do_batch_withdraw_insert function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_DO_BATCH_WITHDRAW_INSERT_H
+#define PG_DO_BATCH_WITHDRAW_INSERT_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+/**
+ * Perform insert as part of a batch withdraw operation, and persisting the
+ * withdrawal details.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param nonce client-contributed input for CS denominations that must be 
checked for idempotency, or NULL for non-CS withdrawals
+ * @param collectable corresponding collectable coin (blind signature)
+ * @param now current time (rounded)
+ * @param ruuid reserve UUID
+ * @param[out] denom_unknown set if the denomination is unknown in the DB
+ * @param[out] conflict if the envelope was already in the DB
+ * @param[out] nonce_reuse if @a nonce was non-NULL and reused
+ * @return query execution status
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_do_batch_withdraw_insert (
+  void *cls,
+  const struct TALER_CsNonce *nonce,
+  const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable,
+  struct GNUNET_TIME_Timestamp now,
+  uint64_t ruuid,
+  bool *denom_unknown,
+  bool *conflict,
+  bool *nonce_reuse);
+
+#endif
diff --git a/src/exchangedb/pg_do_purse_deposit.c 
b/src/exchangedb/pg_do_purse_deposit.c
new file mode 100644
index 00000000..51d4a371
--- /dev/null
+++ b/src/exchangedb/pg_do_purse_deposit.c
@@ -0,0 +1,80 @@
+/*
+   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 exchangedb/pg_do_purse_deposit.c
+ * @brief Implementation of the do_purse_deposit function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_do_purse_deposit.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_do_purse_deposit (
+  void *cls,
+  const struct TALER_PurseContractPublicKeyP *purse_pub,
+  const struct TALER_CoinSpendPublicKeyP *coin_pub,
+  const struct TALER_Amount *amount,
+  const struct TALER_CoinSpendSignatureP *coin_sig,
+  const struct TALER_Amount *amount_minus_fee,
+  bool *balance_ok,
+  bool *conflict)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
+  struct GNUNET_TIME_Timestamp reserve_expiration;
+  uint64_t partner_id = 0; /* FIXME #7271: WAD support... */
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_uint64 (&partner_id),
+    GNUNET_PQ_query_param_auto_from_type (purse_pub),
+    TALER_PQ_query_param_amount (amount),
+    GNUNET_PQ_query_param_auto_from_type (coin_pub),
+    GNUNET_PQ_query_param_auto_from_type (coin_sig),
+    TALER_PQ_query_param_amount (amount_minus_fee),
+    GNUNET_PQ_query_param_timestamp (&reserve_expiration),
+    GNUNET_PQ_query_param_timestamp (&now),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_bool ("balance_ok",
+                                balance_ok),
+    GNUNET_PQ_result_spec_bool ("conflict",
+                                conflict),
+    GNUNET_PQ_result_spec_end
+  };
+
+  reserve_expiration
+    = GNUNET_TIME_absolute_to_timestamp (
+        GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
+                                  pg->legal_reserve_expiration_time));
+
+  PREPARE (pg,
+           "call_purse_deposit",
+           "SELECT "
+           " out_balance_ok AS balance_ok"
+           ",out_conflict AS conflict"
+           " FROM exchange_do_purse_deposit"
+           " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10);");
+
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "call_purse_deposit",
+                                                   params,
+                                                   rs);
+}
diff --git a/src/exchangedb/pg_do_purse_deposit.h 
b/src/exchangedb/pg_do_purse_deposit.h
new file mode 100644
index 00000000..b4b9c35c
--- /dev/null
+++ b/src/exchangedb/pg_do_purse_deposit.h
@@ -0,0 +1,61 @@
+/*
+   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 exchangedb/pg_do_purse_deposit.h
+ * @brief implementation of the do_purse_deposit function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_DO_PURSE_DEPOSIT_H
+#define PG_DO_PURSE_DEPOSIT_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+/**
+ * Function called to execute a transaction crediting
+ * a purse with @a amount from @a coin_pub. Reduces the
+ * value of @a coin_pub and increase the balance of
+ * the @a purse_pub purse. If the balance reaches the
+ * target amount and the purse has been merged, triggers
+ * the updates of the reserve/account balance.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param purse_pub purse to credit
+ * @param coin_pub coin to deposit (debit)
+ * @param amount fraction of the coin's value to deposit
+ * @param coin_sig signature affirming the operation
+ * @param amount_minus_fee amount to add to the purse
+ * @param[out] balance_ok set to false if the coin's
+ *        remaining balance is below @a amount;
+ *             in this case, the return value will be
+ *             #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT despite the failure
+ * @param[out] conflict set to true if the deposit failed due to a conflict 
(coin already spent,
+ *             or deposited into this purse with a different amount)
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_do_purse_deposit (
+  void *cls,
+  const struct TALER_PurseContractPublicKeyP *purse_pub,
+  const struct TALER_CoinSpendPublicKeyP *coin_pub,
+  const struct TALER_Amount *amount,
+  const struct TALER_CoinSpendSignatureP *coin_sig,
+  const struct TALER_Amount *amount_minus_fee,
+  bool *balance_ok,
+  bool *conflict);
+
+#endif
diff --git a/src/exchangedb/pg_do_purse_merge.c 
b/src/exchangedb/pg_do_purse_merge.c
new file mode 100644
index 00000000..518b66bf
--- /dev/null
+++ b/src/exchangedb/pg_do_purse_merge.c
@@ -0,0 +1,92 @@
+/*
+   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 exchangedb/pg_do_purse_merge.c
+ * @brief Implementation of the do_purse_merge function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_do_purse_merge.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_do_purse_merge (
+  void *cls,
+  const struct TALER_PurseContractPublicKeyP *purse_pub,
+  const struct TALER_PurseMergeSignatureP *merge_sig,
+  const struct GNUNET_TIME_Timestamp merge_timestamp,
+  const struct TALER_ReserveSignatureP *reserve_sig,
+  const char *partner_url,
+  const struct TALER_ReservePublicKeyP *reserve_pub,
+  bool *no_partner,
+  bool *no_balance,
+  bool *in_conflict)
+{
+  struct PostgresClosure *pg = cls;
+  struct TALER_PaytoHashP h_payto;
+  struct GNUNET_TIME_Timestamp expiration
+    = GNUNET_TIME_relative_to_timestamp (pg->legal_reserve_expiration_time);
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (purse_pub),
+    GNUNET_PQ_query_param_auto_from_type (merge_sig),
+    GNUNET_PQ_query_param_timestamp (&merge_timestamp),
+    GNUNET_PQ_query_param_auto_from_type (reserve_sig),
+    (NULL == partner_url)
+    ? GNUNET_PQ_query_param_null ()
+    : GNUNET_PQ_query_param_string (partner_url),
+    GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+    GNUNET_PQ_query_param_auto_from_type (&h_payto),
+    GNUNET_PQ_query_param_timestamp (&expiration),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_bool ("no_partner",
+                                no_partner),
+    GNUNET_PQ_result_spec_bool ("no_balance",
+                                no_balance),
+    GNUNET_PQ_result_spec_bool ("conflict",
+                                in_conflict),
+    GNUNET_PQ_result_spec_end
+  };
+
+  {
+    char *payto_uri;
+
+    payto_uri = TALER_reserve_make_payto (pg->exchange_url,
+                                          reserve_pub);
+    TALER_payto_hash (payto_uri,
+                      &h_payto);
+    GNUNET_free (payto_uri);
+  }
+    /* Used in #postgres_do_purse_merge() */
+  PREPARE (pg,
+           "call_purse_merge",
+           "SELECT"
+           " out_no_partner AS no_partner"
+           ",out_no_balance AS no_balance"
+           ",out_conflict AS conflict"
+           " FROM exchange_do_purse_merge"
+           "  ($1, $2, $3, $4, $5, $6, $7, $8);");
+
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "call_purse_merge",
+                                                   params,
+                                                   rs);
+}
diff --git a/src/exchangedb/pg_do_purse_merge.h 
b/src/exchangedb/pg_do_purse_merge.h
new file mode 100644
index 00000000..a51de47b
--- /dev/null
+++ b/src/exchangedb/pg_do_purse_merge.h
@@ -0,0 +1,57 @@
+/*
+   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 exchangedb/pg_do_purse_merge.h
+ * @brief implementation of the do_purse_merge function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_DO_PURSE_MERGE_H
+#define PG_DO_PURSE_MERGE_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+/**
+ * Function called to approve merging a purse into a
+ * reserve by the respective purse merge key.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param purse_pub purse to merge
+ * @param merge_sig signature affirming the merge
+ * @param merge_timestamp time of the merge
+ * @param reserve_sig signature of the reserve affirming the merge
+ * @param partner_url URL of the partner exchange, can be NULL if the reserves 
lives with us
+ * @param reserve_pub public key of the reserve to credit
+ * @param[out] no_partner set to true if @a partner_url is unknown
+ * @param[out] no_balance set to true if the @a purse_pub is not paid up yet
+ * @param[out] in_conflict set to true if @a purse_pub was merged into a 
different reserve already
+  * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_do_purse_merge (
+  void *cls,
+  const struct TALER_PurseContractPublicKeyP *purse_pub,
+  const struct TALER_PurseMergeSignatureP *merge_sig,
+  const struct GNUNET_TIME_Timestamp merge_timestamp,
+  const struct TALER_ReserveSignatureP *reserve_sig,
+  const char *partner_url,
+  const struct TALER_ReservePublicKeyP *reserve_pub,
+  bool *no_partner,
+  bool *no_balance,
+  bool *in_conflict);
+
+#endif
diff --git a/src/exchangedb/pg_do_reserve_purse.c 
b/src/exchangedb/pg_do_reserve_purse.c
new file mode 100644
index 00000000..cb8f83d4
--- /dev/null
+++ b/src/exchangedb/pg_do_reserve_purse.c
@@ -0,0 +1,109 @@
+/*
+   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 exchangedb/pg_do_reserve_purse.c
+ * @brief Implementation of the do_reserve_purse function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_do_reserve_purse.h"
+#include "pg_helper.h"
+/**
+ * Function called insert request to merge a purse into a reserve by the
+ * respective purse merge key. The purse must not have been merged into a
+ * different reserve.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param purse_pub purse to merge
+ * @param merge_sig signature affirming the merge
+ * @param merge_timestamp time of the merge
+ * @param reserve_sig signature of the reserve affirming the merge
+ * @param purse_fee amount to charge the reserve for the purse creation, NULL 
to use the quota
+ * @param reserve_pub public key of the reserve to credit
+ * @param[out] in_conflict set to true if @a purse_pub was merged into a 
different reserve already
+ * @param[out] no_reserve set to true if @a reserve_pub is not a known reserve
+ * @param[out] insufficient_funds set to true if @a reserve_pub has 
insufficient capacity to create another purse
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_do_reserve_purse (
+  void *cls,
+  const struct TALER_PurseContractPublicKeyP *purse_pub,
+  const struct TALER_PurseMergeSignatureP *merge_sig,
+  const struct GNUNET_TIME_Timestamp merge_timestamp,
+  const struct TALER_ReserveSignatureP *reserve_sig,
+  const struct TALER_Amount *purse_fee,
+  const struct TALER_ReservePublicKeyP *reserve_pub,
+  bool *in_conflict,
+  bool *no_reserve,
+  bool *insufficient_funds)
+{
+  struct PostgresClosure *pg = cls;
+  struct TALER_Amount zero_fee;
+  struct TALER_PaytoHashP h_payto;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (purse_pub),
+    GNUNET_PQ_query_param_auto_from_type (merge_sig),
+    GNUNET_PQ_query_param_timestamp (&merge_timestamp),
+    GNUNET_PQ_query_param_auto_from_type (reserve_sig),
+    GNUNET_PQ_query_param_bool (NULL == purse_fee),
+    TALER_PQ_query_param_amount (NULL == purse_fee
+                                 ? &zero_fee
+                                 : purse_fee),
+    GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+    GNUNET_PQ_query_param_auto_from_type (&h_payto),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_bool ("insufficient_funds",
+                                insufficient_funds),
+    GNUNET_PQ_result_spec_bool ("conflict",
+                                in_conflict),
+    GNUNET_PQ_result_spec_bool ("no_reserve",
+                                no_reserve),
+    GNUNET_PQ_result_spec_end
+  };
+
+  {
+    char *payto_uri;
+
+    payto_uri = TALER_reserve_make_payto (pg->exchange_url,
+                                          reserve_pub);
+    TALER_payto_hash (payto_uri,
+                      &h_payto);
+    GNUNET_free (payto_uri);
+  }
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_amount_set_zero (pg->currency,
+                                        &zero_fee));
+  /* Used in #postgres_do_reserve_purse() */
+  PREPARE (pg,
+           "call_reserve_purse",
+           "SELECT"
+           " out_no_funds AS insufficient_funds"
+           ",out_no_reserve AS no_reserve"
+           ",out_conflict AS conflict"
+           " FROM exchange_do_reserve_purse"
+           "  ($1, $2, $3, $4, $5, $6, $7, $8, $9);");
+
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "call_reserve_purse",
+                                                   params,
+                                                   rs);
+}
diff --git a/src/exchangedb/pg_do_reserve_purse.h 
b/src/exchangedb/pg_do_reserve_purse.h
new file mode 100644
index 00000000..dde2d6ce
--- /dev/null
+++ b/src/exchangedb/pg_do_reserve_purse.h
@@ -0,0 +1,57 @@
+/*
+   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 exchangedb/pg_do_reserve_purse.h
+ * @brief implementation of the do_reserve_purse function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_DO_RESERVE_PURSE_H
+#define PG_DO_RESERVE_PURSE_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+/**
+ * Function called insert request to merge a purse into a reserve by the
+ * respective purse merge key. The purse must not have been merged into a
+ * different reserve.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param purse_pub purse to merge
+ * @param merge_sig signature affirming the merge
+ * @param merge_timestamp time of the merge
+ * @param reserve_sig signature of the reserve affirming the merge
+ * @param purse_fee amount to charge the reserve for the purse creation, NULL 
to use the quota
+ * @param reserve_pub public key of the reserve to credit
+ * @param[out] in_conflict set to true if @a purse_pub was merged into a 
different reserve already
+ * @param[out] no_reserve set to true if @a reserve_pub is not a known reserve
+ * @param[out] insufficient_funds set to true if @a reserve_pub has 
insufficient capacity to create another purse
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_do_reserve_purse (
+  void *cls,
+  const struct TALER_PurseContractPublicKeyP *purse_pub,
+  const struct TALER_PurseMergeSignatureP *merge_sig,
+  const struct GNUNET_TIME_Timestamp merge_timestamp,
+  const struct TALER_ReserveSignatureP *reserve_sig,
+  const struct TALER_Amount *purse_fee,
+  const struct TALER_ReservePublicKeyP *reserve_pub,
+  bool *in_conflict,
+  bool *no_reserve,
+  bool *insufficient_funds);
+
+#endif
diff --git a/src/exchangedb/pg_get_drain_profit.c 
b/src/exchangedb/pg_get_drain_profit.c
new file mode 100644
index 00000000..d02802e1
--- /dev/null
+++ b/src/exchangedb/pg_get_drain_profit.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 exchangedb/pg_get_drain_profit.c
+ * @brief Implementation of the get_drain_profit function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_get_drain_profit.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_get_drain_profit (
+  void *cls,
+  const struct TALER_WireTransferIdentifierRawP *wtid,
+  uint64_t *serial,
+  char **account_section,
+  char **payto_uri,
+  struct GNUNET_TIME_Timestamp *request_timestamp,
+  struct TALER_Amount *amount,
+  struct TALER_MasterSignatureP *master_sig)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (wtid),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_uint64 ("profit_drain_serial_id",
+                                  serial),
+    GNUNET_PQ_result_spec_string ("account_section",
+                                  account_section),
+    GNUNET_PQ_result_spec_string ("payto_uri",
+                                  payto_uri),
+    GNUNET_PQ_result_spec_timestamp ("trigger_date",
+                                     request_timestamp),
+    TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
+                                 amount),
+    GNUNET_PQ_result_spec_auto_from_type ("master_sig",
+                                          master_sig),
+    GNUNET_PQ_result_spec_end
+  };
+
+
+  PREPARE (pg,
+           "get_profit_drain",
+           "SELECT"
+           " profit_drain_serial_id"
+           ",account_section"
+           ",payto_uri"
+           ",trigger_date"
+           ",amount_val"
+           ",amount_frac"
+           ",master_sig"
+           " FROM profit_drains"
+           " WHERE wtid=$1;");
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "get_profit_drain",
+                                                   params,
+                                                   rs);
+}
diff --git a/src/exchangedb/pg_insert_aggregation_tracking.h 
b/src/exchangedb/pg_get_drain_profit.h
similarity index 51%
copy from src/exchangedb/pg_insert_aggregation_tracking.h
copy to src/exchangedb/pg_get_drain_profit.h
index e67c0e8e..dd05d8af 100644
--- a/src/exchangedb/pg_insert_aggregation_tracking.h
+++ b/src/exchangedb/pg_get_drain_profit.h
@@ -14,29 +14,39 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_insert_aggregation_tracking.h
- * @brief implementation of the insert_aggregation_tracking function for 
Postgres
+ * @file exchangedb/pg_get_drain_profit.h
+ * @brief implementation of the get_drain_profit function for Postgres
  * @author Christian Grothoff
  */
-#ifndef PG_INSERT_AGGREGATION_TRACKING_H
-#define PG_INSERT_AGGREGATION_TRACKING_H
+#ifndef PG_GET_DRAIN_PROFIT_H
+#define PG_GET_DRAIN_PROFIT_H
 
 #include "taler_util.h"
 #include "taler_json_lib.h"
 #include "taler_exchangedb_plugin.h"
 
 /**
- * Function called to insert aggregation information into the DB.
+ * Function called to get information about a profit drain event.
  *
- * @param cls closure
- * @param wtid the raw wire transfer identifier we used
- * @param deposit_serial_id row in the deposits table for which this is 
aggregation data
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param wtid wire transfer ID to look up drain event for
+ * @param[out] serial set to serial ID of the entry
+ * @param[out] account_section set to account to drain
+ * @param[out] payto_uri set to account to wire funds to
+ * @param[out] request_timestamp set to time of the signature
+ * @param[out] amount set to amount to wire
+ * @param[out] master_sig set to signature affirming the operation
  * @return transaction status code
  */
 enum GNUNET_DB_QueryStatus
-TEH_PG_insert_aggregation_tracking (
+TEH_PG_get_drain_profit (
   void *cls,
   const struct TALER_WireTransferIdentifierRawP *wtid,
-  unsigned long long deposit_serial_id);
+  uint64_t *serial,
+  char **account_section,
+  char **payto_uri,
+  struct GNUNET_TIME_Timestamp *request_timestamp,
+  struct TALER_Amount *amount,
+  struct TALER_MasterSignatureP *master_sig);
 
 #endif
diff --git a/src/exchangedb/pg_get_extension_manifest.c 
b/src/exchangedb/pg_get_extension_manifest.c
new file mode 100644
index 00000000..7df50e2b
--- /dev/null
+++ b/src/exchangedb/pg_get_extension_manifest.c
@@ -0,0 +1,68 @@
+/*
+   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 exchangedb/pg_get_extension_manifest.c
+ * @brief Implementation of the get_extension_manifest function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_get_extension_manifest.h"
+#include "pg_helper.h"
+
+/**
+ * Function called to get the manifest of an extension
+ * (age-restriction, policy_extension_...)
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param extension_name the name of the extension
+ * @param[out] manifest JSON object of the manifest as string
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+postgres_get_extension_manifest (void *cls,
+                                 const char *extension_name,
+                                 char **manifest)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (extension_name),
+    GNUNET_PQ_query_param_end
+  };
+  bool is_null;
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_allow_null (
+      GNUNET_PQ_result_spec_string ("manifest",
+                                    manifest),
+      &is_null),
+    GNUNET_PQ_result_spec_end
+  };
+
+  *manifest = NULL;
+    /* Used in #postgres_get_extension_manifest */
+  PREPARE (pg,
+           "get_extension_manifest",
+           "SELECT "
+           " manifest "
+           "FROM extensions"
+           "   WHERE name=$1;");
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "get_extension_manifest",
+                                                   params,
+                                                   rs);
+}
diff --git a/src/exchangedb/pg_insert_aggregation_tracking.h 
b/src/exchangedb/pg_get_extension_manifest.h
similarity index 58%
copy from src/exchangedb/pg_insert_aggregation_tracking.h
copy to src/exchangedb/pg_get_extension_manifest.h
index e67c0e8e..3756b7f4 100644
--- a/src/exchangedb/pg_insert_aggregation_tracking.h
+++ b/src/exchangedb/pg_get_extension_manifest.h
@@ -14,29 +14,28 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_insert_aggregation_tracking.h
- * @brief implementation of the insert_aggregation_tracking function for 
Postgres
+ * @file exchangedb/pg_get_extension_manifest.h
+ * @brief implementation of the get_extension_manifest function for Postgres
  * @author Christian Grothoff
  */
-#ifndef PG_INSERT_AGGREGATION_TRACKING_H
-#define PG_INSERT_AGGREGATION_TRACKING_H
+#ifndef PG_GET_EXTENSION_MANIFEST_H
+#define PG_GET_EXTENSION_MANIFEST_H
 
 #include "taler_util.h"
 #include "taler_json_lib.h"
 #include "taler_exchangedb_plugin.h"
 
 /**
- * Function called to insert aggregation information into the DB.
+ * Function called to get the manifest of an extension
+ * (age-restriction, policy_extension_...)
  *
- * @param cls closure
- * @param wtid the raw wire transfer identifier we used
- * @param deposit_serial_id row in the deposits table for which this is 
aggregation data
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param extension_name the name of the extension
+ * @param[out] manifest JSON object of the manifest as string
  * @return transaction status code
  */
 enum GNUNET_DB_QueryStatus
-TEH_PG_insert_aggregation_tracking (
-  void *cls,
-  const struct TALER_WireTransferIdentifierRawP *wtid,
-  unsigned long long deposit_serial_id);
-
+TEH_PG_get_extension_manifest (void *cls,
+                                 const char *extension_name,
+                               char **manifest);
 #endif
diff --git a/src/exchangedb/pg_get_purse_deposit.c 
b/src/exchangedb/pg_get_purse_deposit.c
new file mode 100644
index 00000000..539bd5ec
--- /dev/null
+++ b/src/exchangedb/pg_get_purse_deposit.c
@@ -0,0 +1,85 @@
+/*
+   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 exchangedb/pg_get_purse_deposit.c
+ * @brief Implementation of the get_purse_deposit function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_get_purse_deposit.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_get_purse_deposit (
+  void *cls,
+  const struct TALER_PurseContractPublicKeyP *purse_pub,
+  const struct TALER_CoinSpendPublicKeyP *coin_pub,
+  struct TALER_Amount *amount,
+  struct TALER_DenominationHashP *h_denom_pub,
+  struct TALER_AgeCommitmentHash *phac,
+  struct TALER_CoinSpendSignatureP *coin_sig,
+  char **partner_url)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (purse_pub),
+    GNUNET_PQ_query_param_auto_from_type (coin_pub),
+    GNUNET_PQ_query_param_end
+  };
+  bool is_null;
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
+                                          h_denom_pub),
+    GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
+                                          phac),
+    GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
+                                          coin_sig),
+    TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
+                                 amount),
+    GNUNET_PQ_result_spec_allow_null (
+      GNUNET_PQ_result_spec_string ("partner_base_url",
+                                    partner_url),
+      &is_null),
+    GNUNET_PQ_result_spec_end
+  };
+
+
+  *partner_url = NULL;
+ /* Used in #postgres_get_purse_deposit */
+  PREPARE (pg,
+           "select_purse_deposit_by_coin_pub",
+           "SELECT "
+           " coin_sig"
+           ",amount_with_fee_val"
+           ",amount_with_fee_frac"
+           ",denom_pub_hash"
+           ",age_commitment_hash"
+           ",partner_base_url"
+           " FROM purse_deposits"
+           " LEFT JOIN partners USING (partner_serial_id)"
+           " JOIN known_coins kc USING (coin_pub)"
+           " JOIN denominations USING (denominations_serial)"
+           " WHERE coin_pub=$2"
+           "   AND purse_pub=$1;");
+
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   
"select_purse_deposit_by_coin_pub",
+                                                   params,
+                                                   rs);
+}
diff --git a/src/exchangedb/pg_get_purse_deposit.h 
b/src/exchangedb/pg_get_purse_deposit.h
new file mode 100644
index 00000000..b9c9947f
--- /dev/null
+++ b/src/exchangedb/pg_get_purse_deposit.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 exchangedb/pg_get_purse_deposit.h
+ * @brief implementation of the get_purse_deposit function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_GET_PURSE_DEPOSIT_H
+#define PG_GET_PURSE_DEPOSIT_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+/**
+ * Function called to obtain a coin deposit data from
+ * depositing the coin into a purse.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param purse_pub purse to credit
+ * @param coin_pub coin to deposit (debit)
+ * @param[out] amount set fraction of the coin's value that was deposited 
(with fee)
+ * @param[out] h_denom_pub set to hash of denomination of the coin
+ * @param[out] phac set to hash of age restriction on the coin
+ * @param[out] coin_sig set to signature affirming the operation
+ * @param[out] partner_url set to the URL of the partner exchange, or NULL for 
ourselves, must be freed by caller
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_get_purse_deposit (
+  void *cls,
+  const struct TALER_PurseContractPublicKeyP *purse_pub,
+  const struct TALER_CoinSpendPublicKeyP *coin_pub,
+  struct TALER_Amount *amount,
+  struct TALER_DenominationHashP *h_denom_pub,
+  struct TALER_AgeCommitmentHash *phac,
+  struct TALER_CoinSpendSignatureP *coin_sig,
+  char **partner_url);
+
+#endif
diff --git a/src/exchangedb/pg_insert_aggregation_tracking.h 
b/src/exchangedb/pg_insert_aggregation_tracking.h
index e67c0e8e..4f0ac1aa 100644
--- a/src/exchangedb/pg_insert_aggregation_tracking.h
+++ b/src/exchangedb/pg_insert_aggregation_tracking.h
@@ -40,3 +40,4 @@ TEH_PG_insert_aggregation_tracking (
   unsigned long long deposit_serial_id);
 
 #endif
+
diff --git a/src/exchangedb/pg_insert_contract.c 
b/src/exchangedb/pg_insert_contract.c
new file mode 100644
index 00000000..d3e6c23b
--- /dev/null
+++ b/src/exchangedb/pg_insert_contract.c
@@ -0,0 +1,93 @@
+/*
+   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 exchangedb/pg_insert_contract.c
+ * @brief Implementation of the insert_contract function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_insert_contract.h"
+#include "pg_select_contract_by_purse.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_insert_contract (
+  void *cls,
+  const struct TALER_PurseContractPublicKeyP *purse_pub,
+  const struct TALER_EncryptedContract *econtract,
+  bool *in_conflict)
+{
+  struct PostgresClosure *pg = cls;
+  enum GNUNET_DB_QueryStatus qs;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (purse_pub),
+    GNUNET_PQ_query_param_auto_from_type (&econtract->contract_pub),
+    GNUNET_PQ_query_param_fixed_size (econtract->econtract,
+                                      econtract->econtract_size),
+    GNUNET_PQ_query_param_auto_from_type (&econtract->econtract_sig),
+    GNUNET_PQ_query_param_end
+  };
+
+  *in_conflict = false;
+   /* Used in #postgres_insert_contract() */
+  PREPARE (pg,
+      "insert_contract",
+      "INSERT INTO contracts"
+      "  (purse_pub"
+      "  ,pub_ckey"
+      "  ,e_contract"
+      "  ,contract_sig"
+      "  ,purse_expiration"
+      "  ) SELECT "
+      "  $1, $2, $3, $4, purse_expiration"
+      "  FROM purse_requests"
+      "  WHERE purse_pub=$1"
+      "  ON CONFLICT DO NOTHING;");
+  qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                           "insert_contract",
+                                           params);
+  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs)
+    return qs;
+  {
+    struct TALER_EncryptedContract econtract2;
+
+    qs = TEH_PG_select_contract_by_purse (pg,
+                                            purse_pub,
+                                            &econtract2);
+    if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
+    {
+      GNUNET_break (0);
+      return GNUNET_DB_STATUS_HARD_ERROR;
+    }
+    if ( (0 == GNUNET_memcmp (&econtract->contract_pub,
+                              &econtract2.contract_pub)) &&
+         (econtract2.econtract_size ==
+          econtract->econtract_size) &&
+         (0 == memcmp (econtract2.econtract,
+                       econtract->econtract,
+                       econtract->econtract_size)) )
+    {
+      GNUNET_free (econtract2.econtract);
+      return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
+    }
+    GNUNET_free (econtract2.econtract);
+    *in_conflict = true;
+    return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
+  }
+}
diff --git a/src/exchangedb/pg_insert_aggregation_tracking.h 
b/src/exchangedb/pg_insert_contract.h
similarity index 52%
copy from src/exchangedb/pg_insert_aggregation_tracking.h
copy to src/exchangedb/pg_insert_contract.h
index e67c0e8e..e2e6b5ee 100644
--- a/src/exchangedb/pg_insert_aggregation_tracking.h
+++ b/src/exchangedb/pg_insert_contract.h
@@ -14,29 +14,34 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_insert_aggregation_tracking.h
- * @brief implementation of the insert_aggregation_tracking function for 
Postgres
+ * @file exchangedb/pg_insert_contract.h
+ * @brief implementation of the insert_contract function for Postgres
  * @author Christian Grothoff
  */
-#ifndef PG_INSERT_AGGREGATION_TRACKING_H
-#define PG_INSERT_AGGREGATION_TRACKING_H
+#ifndef PG_INSERT_CONTRACT_H
+#define PG_INSERT_CONTRACT_H
 
 #include "taler_util.h"
 #include "taler_json_lib.h"
 #include "taler_exchangedb_plugin.h"
 
 /**
- * Function called to insert aggregation information into the DB.
+ * Function called to persist an encrypted contract associated with a reserve.
  *
- * @param cls closure
- * @param wtid the raw wire transfer identifier we used
- * @param deposit_serial_id row in the deposits table for which this is 
aggregation data
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param purse_pub the purse the contract is associated with (must exist)
+ * @param econtract the encrypted contract
+ * @param[out] in_conflict set to true if @a econtract
+ *             conflicts with an existing contract;
+ *             in this case, the return value will be
+ *             #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT despite the failure
  * @return transaction status code
  */
 enum GNUNET_DB_QueryStatus
-TEH_PG_insert_aggregation_tracking (
+TEH_PG_insert_contract (
   void *cls,
-  const struct TALER_WireTransferIdentifierRawP *wtid,
-  unsigned long long deposit_serial_id);
+  const struct TALER_PurseContractPublicKeyP *purse_pub,
+  const struct TALER_EncryptedContract *econtract,
+  bool *in_conflict);
 
 #endif
diff --git a/src/exchangedb/pg_insert_denomination_info.c 
b/src/exchangedb/pg_insert_denomination_info.c
new file mode 100644
index 00000000..bad6b8e7
--- /dev/null
+++ b/src/exchangedb/pg_insert_denomination_info.c
@@ -0,0 +1,105 @@
+/*
+   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 exchangedb/pg_insert_denomination_info.c
+ * @brief Implementation of the insert_denomination_info function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_insert_denomination_info.h"
+#include "pg_helper.h"
+
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_insert_denomination_info (
+  void *cls,
+  const struct TALER_DenominationPublicKey *denom_pub,
+  const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue)
+{
+  struct PostgresClosure *pg = cls;
+  struct TALER_DenominationHashP denom_hash;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (&issue->denom_hash),
+    TALER_PQ_query_param_denom_pub (denom_pub),
+    GNUNET_PQ_query_param_auto_from_type (&issue->signature),
+    GNUNET_PQ_query_param_timestamp (&issue->start),
+    GNUNET_PQ_query_param_timestamp (&issue->expire_withdraw),
+    GNUNET_PQ_query_param_timestamp (&issue->expire_deposit),
+    GNUNET_PQ_query_param_timestamp (&issue->expire_legal),
+    TALER_PQ_query_param_amount (&issue->value),
+    TALER_PQ_query_param_amount (&issue->fees.withdraw),
+    TALER_PQ_query_param_amount (&issue->fees.deposit),
+    TALER_PQ_query_param_amount (&issue->fees.refresh),
+    TALER_PQ_query_param_amount (&issue->fees.refund),
+    GNUNET_PQ_query_param_uint32 (&denom_pub->age_mask.bits),
+    GNUNET_PQ_query_param_end
+  };
+
+  GNUNET_assert (denom_pub->age_mask.bits ==
+                 issue->age_mask.bits);
+  TALER_denom_pub_hash (denom_pub,
+                        &denom_hash);
+  GNUNET_assert (0 ==
+                 GNUNET_memcmp (&denom_hash,
+                                &issue->denom_hash));
+  GNUNET_assert (! GNUNET_TIME_absolute_is_zero (
+                   issue->start.abs_time));
+  GNUNET_assert (! GNUNET_TIME_absolute_is_zero (
+                   issue->expire_withdraw.abs_time));
+  GNUNET_assert (! GNUNET_TIME_absolute_is_zero (
+                   issue->expire_deposit.abs_time));
+  GNUNET_assert (! GNUNET_TIME_absolute_is_zero (
+                   issue->expire_legal.abs_time));
+  /* check fees match denomination currency */
+  GNUNET_assert (GNUNET_YES ==
+                 TALER_denom_fee_check_currency (
+                   issue->value.currency,
+                   &issue->fees));
+ /* Used in #postgres_insert_denomination_info() and
+     #postgres_add_denomination_key() */
+  PREPARE (pg, 
+           "denomination_insert",
+           "INSERT INTO denominations "
+           "(denom_pub_hash"
+           ",denom_pub"
+           ",master_sig"
+           ",valid_from"
+           ",expire_withdraw"
+           ",expire_deposit"
+           ",expire_legal"
+           ",coin_val"                                                /* value 
of this denom */
+           ",coin_frac"                                                /* 
fractional value of this denom */
+           ",fee_withdraw_val"
+           ",fee_withdraw_frac"
+           ",fee_deposit_val"
+           ",fee_deposit_frac"
+           ",fee_refresh_val"
+           ",fee_refresh_frac"
+           ",fee_refund_val"
+           ",fee_refund_frac"
+           ",age_mask"
+           ") VALUES "
+           "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
+           " $11, $12, $13, $14, $15, $16, $17, $18);");
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "denomination_insert",
+                                             params);
+}
+
diff --git a/src/exchangedb/pg_insert_aggregation_tracking.h 
b/src/exchangedb/pg_insert_denomination_info.h
similarity index 54%
copy from src/exchangedb/pg_insert_aggregation_tracking.h
copy to src/exchangedb/pg_insert_denomination_info.h
index e67c0e8e..663f45bd 100644
--- a/src/exchangedb/pg_insert_aggregation_tracking.h
+++ b/src/exchangedb/pg_insert_denomination_info.h
@@ -14,29 +14,29 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_insert_aggregation_tracking.h
- * @brief implementation of the insert_aggregation_tracking function for 
Postgres
+ * @file exchangedb/pg_insert_denomination_info.h
+ * @brief implementation of the insert_denomination_info function for Postgres
  * @author Christian Grothoff
  */
-#ifndef PG_INSERT_AGGREGATION_TRACKING_H
-#define PG_INSERT_AGGREGATION_TRACKING_H
+#ifndef PG_INSERT_DENOMINATION_INFO_H
+#define PG_INSERT_DENOMINATION_INFO_H
 
 #include "taler_util.h"
 #include "taler_json_lib.h"
 #include "taler_exchangedb_plugin.h"
-
 /**
- * Function called to insert aggregation information into the DB.
+ * Insert a denomination key's public information into the database for
+ * reference by auditors and other consistency checks.
  *
- * @param cls closure
- * @param wtid the raw wire transfer identifier we used
- * @param deposit_serial_id row in the deposits table for which this is 
aggregation data
- * @return transaction status code
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param denom_pub the public key used for signing coins of this denomination
+ * @param issue issuing information with value, fees and other info about the 
coin
+ * @return status of the query
  */
 enum GNUNET_DB_QueryStatus
-TEH_PG_insert_aggregation_tracking (
+TEH_PG_insert_denomination_info (
   void *cls,
-  const struct TALER_WireTransferIdentifierRawP *wtid,
-  unsigned long long deposit_serial_id);
+  const struct TALER_DenominationPublicKey *denom_pub,
+  const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue);
 
 #endif
diff --git a/src/exchangedb/pg_insert_drain_profit.c 
b/src/exchangedb/pg_insert_drain_profit.c
new file mode 100644
index 00000000..19340eaf
--- /dev/null
+++ b/src/exchangedb/pg_insert_drain_profit.c
@@ -0,0 +1,64 @@
+/*
+   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 exchangedb/pg_insert_drain_profit.c
+ * @brief Implementation of the insert_drain_profit function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_insert_drain_profit.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_insert_drain_profit (
+  void *cls,
+  const struct TALER_WireTransferIdentifierRawP *wtid,
+  const char *account_section,
+  const char *payto_uri,
+  struct GNUNET_TIME_Timestamp request_timestamp,
+  const struct TALER_Amount *amount,
+  const struct TALER_MasterSignatureP *master_sig)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (wtid),
+    GNUNET_PQ_query_param_string (account_section),
+    GNUNET_PQ_query_param_string (payto_uri),
+    GNUNET_PQ_query_param_timestamp (&request_timestamp),
+    TALER_PQ_query_param_amount (amount),
+    GNUNET_PQ_query_param_auto_from_type (master_sig),
+    GNUNET_PQ_query_param_end
+  };
+ /* Used in #postgres_insert_drain_profit() */
+  PREPARE (pg,
+           "drain_profit_insert",
+           "INSERT INTO profit_drains "
+           "(wtid"
+           ",account_section"
+           ",payto_uri"
+           ",trigger_date"
+           ",amount_val"
+           ",amount_frac"
+           ",master_sig"
+           ") VALUES ($1, $2, $3, $4, $5, $6, $7);");
+
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "drain_profit_insert",
+                                             params);
+}
diff --git a/src/exchangedb/pg_insert_aggregation_tracking.h 
b/src/exchangedb/pg_insert_drain_profit.h
similarity index 54%
copy from src/exchangedb/pg_insert_aggregation_tracking.h
copy to src/exchangedb/pg_insert_drain_profit.h
index e67c0e8e..90183d85 100644
--- a/src/exchangedb/pg_insert_aggregation_tracking.h
+++ b/src/exchangedb/pg_insert_drain_profit.h
@@ -14,29 +14,37 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_insert_aggregation_tracking.h
- * @brief implementation of the insert_aggregation_tracking function for 
Postgres
+ * @file exchangedb/pg_insert_drain_profit.h
+ * @brief implementation of the insert_drain_profit function for Postgres
  * @author Christian Grothoff
  */
-#ifndef PG_INSERT_AGGREGATION_TRACKING_H
-#define PG_INSERT_AGGREGATION_TRACKING_H
+#ifndef PG_INSERT_DRAIN_PROFIT_H
+#define PG_INSERT_DRAIN_PROFIT_H
 
 #include "taler_util.h"
 #include "taler_json_lib.h"
 #include "taler_exchangedb_plugin.h"
 
 /**
- * Function called to insert aggregation information into the DB.
+ * Function called to persist a request to drain profits.
  *
- * @param cls closure
- * @param wtid the raw wire transfer identifier we used
- * @param deposit_serial_id row in the deposits table for which this is 
aggregation data
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param wtid wire transfer ID to use
+ * @param account_section account to drain
+ * @param payto_uri account to wire funds to
+ * @param request_timestamp when was the request made
+ * @param amount amount to wire
+ * @param master_sig signature affirming the operation
  * @return transaction status code
  */
 enum GNUNET_DB_QueryStatus
-TEH_PG_insert_aggregation_tracking (
+TEH_PG_insert_drain_profit (
   void *cls,
   const struct TALER_WireTransferIdentifierRawP *wtid,
-  unsigned long long deposit_serial_id);
+  const char *account_section,
+  const char *payto_uri,
+  struct GNUNET_TIME_Timestamp request_timestamp,
+  const struct TALER_Amount *amount,
+  const struct TALER_MasterSignatureP *master_sig);
 
 #endif
diff --git a/src/exchangedb/pg_insert_history_request.c 
b/src/exchangedb/pg_insert_history_request.c
new file mode 100644
index 00000000..00270b1a
--- /dev/null
+++ b/src/exchangedb/pg_insert_history_request.c
@@ -0,0 +1,66 @@
+/*
+   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 exchangedb/pg_insert_history_request.c
+ * @brief Implementation of the insert_history_request function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_insert_history_request.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_insert_history_request (
+  void *cls,
+  const struct TALER_ReservePublicKeyP *reserve_pub,
+  const struct TALER_ReserveSignatureP *reserve_sig,
+  struct GNUNET_TIME_Timestamp request_timestamp,
+  const struct TALER_Amount *history_fee,
+  bool *balance_ok,
+  bool *idempotent)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+    GNUNET_PQ_query_param_auto_from_type (reserve_sig),
+    GNUNET_PQ_query_param_timestamp (&request_timestamp),
+    TALER_PQ_query_param_amount (history_fee),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_bool ("balance_ok",
+                                balance_ok),
+    GNUNET_PQ_result_spec_bool ("idempotent",
+                                idempotent),
+    GNUNET_PQ_result_spec_end
+  };
+    /* Used in #postgres_insert_history_request() */
+  PREPARE (pg,
+           "call_history_request",
+           "SELECT"
+           "  out_balance_ok AS balance_ok"
+           " ,out_idempotent AS idempotent"
+           " FROM exchange_do_history_request"
+           "  ($1, $2, $3, $4, $5)");
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "call_history_request",
+                                                   params,
+                                                   rs);
+}
diff --git a/src/exchangedb/pg_insert_history_request.h 
b/src/exchangedb/pg_insert_history_request.h
new file mode 100644
index 00000000..75004a7e
--- /dev/null
+++ b/src/exchangedb/pg_insert_history_request.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 exchangedb/pg_insert_history_request.h
+ * @brief implementation of the insert_history_request function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_INSERT_HISTORY_REQUEST_H
+#define PG_INSERT_HISTORY_REQUEST_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+/**
+ * Function called to persist a signature that
+ * prove that the client requested an
+ * account history.  Debits the @a history_fee from
+ * the reserve (if possible).
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param reserve_pub account that the history was requested for
+ * @param reserve_sig signature affirming the request
+ * @param request_timestamp when was the request made
+ * @param history_fee how much should the @a reserve_pub be charged for the 
request
+ * @param[out] balance_ok set to TRUE if the reserve balance
+ *         was sufficient
+ * @param[out] idempotent set to TRUE if the request is already in the DB
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_insert_history_request (
+  void *cls,
+  const struct TALER_ReservePublicKeyP *reserve_pub,
+  const struct TALER_ReserveSignatureP *reserve_sig,
+  struct GNUNET_TIME_Timestamp request_timestamp,
+  const struct TALER_Amount *history_fee,
+  bool *balance_ok,
+  bool *idempotent);
+
+#endif
diff --git a/src/exchangedb/pg_insert_kyc_requirement_for_account.c 
b/src/exchangedb/pg_insert_kyc_requirement_for_account.c
new file mode 100644
index 00000000..be5cbac8
--- /dev/null
+++ b/src/exchangedb/pg_insert_kyc_requirement_for_account.c
@@ -0,0 +1,62 @@
+/*
+   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 exchangedb/pg_insert_kyc_requirement_for_account.c
+ * @brief Implementation of the insert_kyc_requirement_for_account function 
for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_insert_kyc_requirement_for_account.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_insert_kyc_requirement_for_account (
+  void *cls,
+  const char *provider_section,
+  const struct TALER_PaytoHashP *h_payto,
+  uint64_t *requirement_row)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (h_payto),
+    GNUNET_PQ_query_param_string (provider_section),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_uint64 ("legitimization_requirement_serial_id",
+                                  requirement_row),
+    GNUNET_PQ_result_spec_end
+  };
+ /* Used in #postgres_insert_kyc_requirement_for_account() */
+  PREPARE (pg,
+           "insert_legitimization_requirement",
+           "INSERT INTO legitimization_requirements"
+           "  (h_payto"
+           "  ,required_checks"
+           "  ) VALUES "
+           "  ($1, $2)"
+           " ON CONFLICT (h_payto,required_checks) "
+           "   DO UPDATE SET h_payto=$1" /* syntax requirement: dummy op */
+           " RETURNING legitimization_requirement_serial_id");
+  return GNUNET_PQ_eval_prepared_singleton_select (
+    pg->conn,
+    "insert_legitimization_requirement",
+    params,
+    rs);
+}
diff --git a/src/exchangedb/pg_insert_aggregation_tracking.h 
b/src/exchangedb/pg_insert_kyc_requirement_for_account.h
similarity index 57%
copy from src/exchangedb/pg_insert_aggregation_tracking.h
copy to src/exchangedb/pg_insert_kyc_requirement_for_account.h
index e67c0e8e..5f9bf6a4 100644
--- a/src/exchangedb/pg_insert_aggregation_tracking.h
+++ b/src/exchangedb/pg_insert_kyc_requirement_for_account.h
@@ -14,29 +14,31 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_insert_aggregation_tracking.h
- * @brief implementation of the insert_aggregation_tracking function for 
Postgres
+ * @file exchangedb/pg_insert_kyc_requirement_for_account.h
+ * @brief implementation of the insert_kyc_requirement_for_account function 
for Postgres
  * @author Christian Grothoff
  */
-#ifndef PG_INSERT_AGGREGATION_TRACKING_H
-#define PG_INSERT_AGGREGATION_TRACKING_H
+#ifndef PG_INSERT_KYC_REQUIREMENT_FOR_ACCOUNT_H
+#define PG_INSERT_KYC_REQUIREMENT_FOR_ACCOUNT_H
 
 #include "taler_util.h"
 #include "taler_json_lib.h"
 #include "taler_exchangedb_plugin.h"
 
+
 /**
- * Function called to insert aggregation information into the DB.
+ * Insert KYC requirement for @a h_payto account into table.
  *
  * @param cls closure
- * @param wtid the raw wire transfer identifier we used
- * @param deposit_serial_id row in the deposits table for which this is 
aggregation data
- * @return transaction status code
+ * @param provider_section provider that must be checked
+ * @param h_payto account that must be KYC'ed
+ * @param[out] requirement_row set to legitimization requirement row for this 
check
+ * @return database transaction status
  */
 enum GNUNET_DB_QueryStatus
-TEH_PG_insert_aggregation_tracking (
+TEH_PG_insert_kyc_requirement_for_account (
   void *cls,
-  const struct TALER_WireTransferIdentifierRawP *wtid,
-  unsigned long long deposit_serial_id);
-
+  const char *provider_section,
+  const struct TALER_PaytoHashP *h_payto,
+  uint64_t *requirement_row);
 #endif
diff --git a/src/exchangedb/pg_insert_kyc_requirement_process.c 
b/src/exchangedb/pg_insert_kyc_requirement_process.c
new file mode 100644
index 00000000..d520ac59
--- /dev/null
+++ b/src/exchangedb/pg_insert_kyc_requirement_process.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 exchangedb/pg_insert_kyc_requirement_process.c
+ * @brief Implementation of the insert_kyc_requirement_process function for 
Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_insert_kyc_requirement_process.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_insert_kyc_requirement_process (
+  void *cls,
+  const struct TALER_PaytoHashP *h_payto,
+  const char *provider_section,
+  const char *provider_account_id,
+  const char *provider_legitimization_id,
+  uint64_t *process_row)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (h_payto),
+    GNUNET_PQ_query_param_string (provider_section),
+    (NULL != provider_account_id)
+    ? GNUNET_PQ_query_param_string (provider_account_id)
+    : GNUNET_PQ_query_param_null (),
+    (NULL != provider_legitimization_id)
+    ? GNUNET_PQ_query_param_string (provider_legitimization_id)
+    : GNUNET_PQ_query_param_null (),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_uint64 ("legitimization_process_serial_id",
+                                  process_row),
+    GNUNET_PQ_result_spec_end
+  };
+
+    /* Used in #postgres_insert_kyc_requirement_process() */
+  PREPARE (pg,
+           "insert_legitimization_process",
+           "INSERT INTO legitimization_processes"
+           "  (h_payto"
+           "  ,provider_section"
+           "  ,provider_user_id"
+           "  ,provider_legitimization_id"
+           "  ) VALUES "
+           "  ($1, $2, $3, $4)"
+           " ON CONFLICT (h_payto,provider_section) "
+           "   DO UPDATE SET"
+           "      provider_user_id=$3"
+           "     ,provider_legitimization_id=$4"
+           " RETURNING legitimization_process_serial_id");
+  return GNUNET_PQ_eval_prepared_singleton_select (
+    pg->conn,
+    "insert_legitimization_process",
+    params,
+    rs);
+}
diff --git a/src/exchangedb/pg_insert_aggregation_tracking.h 
b/src/exchangedb/pg_insert_kyc_requirement_process.h
similarity index 53%
copy from src/exchangedb/pg_insert_aggregation_tracking.h
copy to src/exchangedb/pg_insert_kyc_requirement_process.h
index e67c0e8e..3f354472 100644
--- a/src/exchangedb/pg_insert_aggregation_tracking.h
+++ b/src/exchangedb/pg_insert_kyc_requirement_process.h
@@ -14,29 +14,35 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_insert_aggregation_tracking.h
- * @brief implementation of the insert_aggregation_tracking function for 
Postgres
+ * @file exchangedb/pg_insert_kyc_requirement_process.h
+ * @brief implementation of the insert_kyc_requirement_process function for 
Postgres
  * @author Christian Grothoff
  */
-#ifndef PG_INSERT_AGGREGATION_TRACKING_H
-#define PG_INSERT_AGGREGATION_TRACKING_H
+#ifndef PG_INSERT_KYC_REQUIREMENT_PROCESS_H
+#define PG_INSERT_KYC_REQUIREMENT_PROCESS_H
 
 #include "taler_util.h"
 #include "taler_json_lib.h"
 #include "taler_exchangedb_plugin.h"
 
+
 /**
- * Function called to insert aggregation information into the DB.
+ * Begin KYC requirement process.
  *
  * @param cls closure
- * @param wtid the raw wire transfer identifier we used
- * @param deposit_serial_id row in the deposits table for which this is 
aggregation data
- * @return transaction status code
+ * @param h_payto account that must be KYC'ed
+ * @param provider_section provider that must be checked
+ * @param provider_account_id provider account ID
+ * @param provider_legitimization_id provider legitimization ID
+ * @param[out] process_row row the process is stored under
+ * @return database transaction status
  */
 enum GNUNET_DB_QueryStatus
-TEH_PG_insert_aggregation_tracking (
+TEH_PG_insert_kyc_requirement_process (
   void *cls,
-  const struct TALER_WireTransferIdentifierRawP *wtid,
-  unsigned long long deposit_serial_id);
-
+  const struct TALER_PaytoHashP *h_payto,
+  const char *provider_section,
+  const char *provider_account_id,
+  const char *provider_legitimization_id,
+  uint64_t *process_row);
 #endif
diff --git a/src/exchangedb/pg_kyc_provider_account_lookup.c 
b/src/exchangedb/pg_kyc_provider_account_lookup.c
new file mode 100644
index 00000000..32cd65f7
--- /dev/null
+++ b/src/exchangedb/pg_kyc_provider_account_lookup.c
@@ -0,0 +1,65 @@
+/*
+   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 exchangedb/pg_kyc_provider_account_lookup.c
+ * @brief Implementation of the kyc_provider_account_lookup function for 
Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_kyc_provider_account_lookup.h"
+#include "pg_helper.h"
+
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_kyc_provider_account_lookup (
+  void *cls,
+  const char *provider_section,
+  const char *provider_legitimization_id,
+  struct TALER_PaytoHashP *h_payto,
+  uint64_t *process_row)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (provider_section),
+    GNUNET_PQ_query_param_string (provider_legitimization_id),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_auto_from_type ("h_payto",
+                                          h_payto),
+    GNUNET_PQ_result_spec_uint64 ("legitimization_process_serial_id",
+                                  process_row),
+    GNUNET_PQ_result_spec_end
+  };
+ /* Used in #postgres_kyc_provider_account_lookup() */
+  PREPARE (pg,
+           "get_wire_target_by_legitimization_id",
+           "SELECT "
+           " h_payto"
+           ",legitimization_process_serial_id"
+           " FROM legitimization_processes"
+           " WHERE provider_legitimization_id=$1"
+           "   AND provider_section=$2;");
+  return GNUNET_PQ_eval_prepared_singleton_select (
+    pg->conn,
+    "get_wire_target_by_legitimization_id",
+    params,
+    rs);
+}
diff --git a/src/exchangedb/pg_insert_aggregation_tracking.h 
b/src/exchangedb/pg_kyc_provider_account_lookup.h
similarity index 58%
copy from src/exchangedb/pg_insert_aggregation_tracking.h
copy to src/exchangedb/pg_kyc_provider_account_lookup.h
index e67c0e8e..41bcb86a 100644
--- a/src/exchangedb/pg_insert_aggregation_tracking.h
+++ b/src/exchangedb/pg_kyc_provider_account_lookup.h
@@ -14,29 +14,34 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_insert_aggregation_tracking.h
- * @brief implementation of the insert_aggregation_tracking function for 
Postgres
+ * @file exchangedb/pg_kyc_provider_account_lookup.h
+ * @brief implementation of the kyc_provider_account_lookup function for 
Postgres
  * @author Christian Grothoff
  */
-#ifndef PG_INSERT_AGGREGATION_TRACKING_H
-#define PG_INSERT_AGGREGATION_TRACKING_H
+#ifndef PG_KYC_PROVIDER_ACCOUNT_LOOKUP_H
+#define PG_KYC_PROVIDER_ACCOUNT_LOOKUP_H
 
 #include "taler_util.h"
 #include "taler_json_lib.h"
 #include "taler_exchangedb_plugin.h"
 
+
 /**
- * Function called to insert aggregation information into the DB.
+ * Lookup an
+ * @a h_payto by @a provider_legitimization_id.
  *
  * @param cls closure
- * @param wtid the raw wire transfer identifier we used
- * @param deposit_serial_id row in the deposits table for which this is 
aggregation data
- * @return transaction status code
+ * @param provider_section
+ * @param provider_legitimization_id legi to look up
+ * @param[out] h_payto where to write the result
+ * @param[out] process_row where to write the row of the entry
+ * @return database transaction status
  */
 enum GNUNET_DB_QueryStatus
-TEH_PG_insert_aggregation_tracking (
+TEH_PG_kyc_provider_account_lookup (
   void *cls,
-  const struct TALER_WireTransferIdentifierRawP *wtid,
-  unsigned long long deposit_serial_id);
-
+  const char *provider_section,
+  const char *provider_legitimization_id,
+  struct TALER_PaytoHashP *h_payto,
+  uint64_t *process_row);
 #endif
diff --git a/src/exchangedb/pg_lookup_global_fee_by_time.c 
b/src/exchangedb/pg_lookup_global_fee_by_time.c
new file mode 100644
index 00000000..895db22b
--- /dev/null
+++ b/src/exchangedb/pg_lookup_global_fee_by_time.c
@@ -0,0 +1,189 @@
+/*
+   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 exchangedb/pg_lookup_global_fee_by_time.c
+ * @brief Implementation of the lookup_global_fee_by_time function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_lookup_global_fee_by_time.h"
+#include "pg_helper.h"
+
+/**
+ * Closure for #global_fee_by_time_helper()
+ */
+struct GlobalFeeLookupContext
+{
+
+  /**
+   * Set to the wire fees. Set to invalid if fees conflict over
+   * the given time period.
+   */
+  struct TALER_GlobalFeeSet *fees;
+
+  /**
+   * Set to timeout of unmerged purses
+   */
+  struct GNUNET_TIME_Relative *purse_timeout;
+
+  /**
+   * Set to history expiration for reserves.
+   */
+  struct GNUNET_TIME_Relative *history_expiration;
+
+  /**
+   * Set to number of free purses per account.
+   */
+  uint32_t *purse_account_limit;
+
+  /**
+   * Plugin context.
+   */
+  struct PostgresClosure *pg;
+};
+
+
+/**
+ * Helper function for #postgres_lookup_global_fee_by_time().
+ * Calls the callback with each denomination key.
+ *
+ * @param cls a `struct GlobalFeeLookupContext`
+ * @param result db results
+ * @param num_results number of results in @a result
+ */
+static void
+global_fee_by_time_helper (void *cls,
+                           PGresult *result,
+                           unsigned int num_results)
+{
+  struct GlobalFeeLookupContext *wlc = cls;
+  struct PostgresClosure *pg = wlc->pg;
+
+  for (unsigned int i = 0; i<num_results; i++)
+  {
+    struct TALER_GlobalFeeSet fs;
+    struct GNUNET_TIME_Relative purse_timeout;
+    struct GNUNET_TIME_Relative history_expiration;
+    uint32_t purse_account_limit;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      TALER_PQ_RESULT_SPEC_AMOUNT ("history_fee",
+                                   &fs.history),
+      TALER_PQ_RESULT_SPEC_AMOUNT ("account_fee",
+                                   &fs.account),
+      TALER_PQ_RESULT_SPEC_AMOUNT ("purse_fee",
+                                   &fs.purse),
+      GNUNET_PQ_result_spec_relative_time ("purse_timeout",
+                                           &purse_timeout),
+      GNUNET_PQ_result_spec_relative_time ("history_expiration",
+                                           &history_expiration),
+      GNUNET_PQ_result_spec_uint32 ("purse_account_limit",
+                                    &purse_account_limit),
+      GNUNET_PQ_result_spec_end
+    };
+
+    if (GNUNET_OK !=
+        GNUNET_PQ_extract_result (result,
+                                  rs,
+                                  i))
+    {
+      GNUNET_break (0);
+      /* invalidate */
+      memset (wlc->fees,
+              0,
+              sizeof (struct TALER_GlobalFeeSet));
+      return;
+    }
+    if (0 == i)
+    {
+      *wlc->fees = fs;
+      *wlc->purse_timeout = purse_timeout;
+      *wlc->history_expiration = history_expiration;
+      *wlc->purse_account_limit = purse_account_limit;
+      continue;
+    }
+    if ( (0 !=
+          TALER_global_fee_set_cmp (&fs,
+                                    wlc->fees)) ||
+         (purse_account_limit != *wlc->purse_account_limit) ||
+         (GNUNET_TIME_relative_cmp (purse_timeout,
+                                    !=,
+                                    *wlc->purse_timeout)) ||
+         (GNUNET_TIME_relative_cmp (history_expiration,
+                                    !=,
+                                    *wlc->history_expiration)) )
+    {
+      /* invalidate */
+      memset (wlc->fees,
+              0,
+              sizeof (struct TALER_GlobalFeeSet));
+      return;
+    }
+  }
+}
+
+
+
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_lookup_global_fee_by_time (
+  void *cls,
+  struct GNUNET_TIME_Timestamp start_time,
+  struct GNUNET_TIME_Timestamp end_time,
+  struct TALER_GlobalFeeSet *fees,
+  struct GNUNET_TIME_Relative *purse_timeout,
+  struct GNUNET_TIME_Relative *history_expiration,
+  uint32_t *purse_account_limit)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_timestamp (&start_time),
+    GNUNET_PQ_query_param_timestamp (&end_time),
+    GNUNET_PQ_query_param_end
+  };
+  struct GlobalFeeLookupContext wlc = {
+    .fees = fees,
+    .purse_timeout = purse_timeout,
+    .history_expiration = history_expiration,
+    .purse_account_limit = purse_account_limit,
+    .pg = pg
+  };
+
+  PREPARE (pg,
+           "lookup_global_fee_by_time",
+           "SELECT"
+           " history_fee_val"
+           ",history_fee_frac"
+           ",account_fee_val"
+           ",account_fee_frac"
+           ",purse_fee_val"
+           ",purse_fee_frac"
+           ",purse_timeout"
+           ",history_expiration"
+           ",purse_account_limit"
+           " FROM global_fee"
+           " WHERE end_date > $1"
+           "   AND start_date < $2;");
+  return GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+                                               "lookup_global_fee_by_time",
+                                               params,
+                                               &global_fee_by_time_helper,
+                                               &wlc);
+}
+
diff --git a/src/exchangedb/pg_lookup_global_fee_by_time.h 
b/src/exchangedb/pg_lookup_global_fee_by_time.h
new file mode 100644
index 00000000..9ac7d7dc
--- /dev/null
+++ b/src/exchangedb/pg_lookup_global_fee_by_time.h
@@ -0,0 +1,51 @@
+/*
+   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 exchangedb/pg_lookup_global_fee_by_time.h
+ * @brief implementation of the lookup_global_fee_by_time function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_LOOKUP_GLOBAL_FEE_BY_TIME_H
+#define PG_LOOKUP_GLOBAL_FEE_BY_TIME_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+/**
+ * Lookup information about known global fees.
+ *
+ * @param cls closure
+ * @param start_time starting time of fee
+ * @param end_time end time of fee
+ * @param[out] fees set to wire fees for that time period; if
+ *             different global fee exists within this time
+ *             period, an 'invalid' amount is returned.
+ * @param[out] purse_timeout set to when unmerged purses expire
+ * @param[out] history_expiration set to when we expire reserve histories
+ * @param[out] purse_account_limit set to number of free purses
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_lookup_global_fee_by_time (
+  void *cls,
+  struct GNUNET_TIME_Timestamp start_time,
+  struct GNUNET_TIME_Timestamp end_time,
+  struct TALER_GlobalFeeSet *fees,
+  struct GNUNET_TIME_Relative *purse_timeout,
+  struct GNUNET_TIME_Relative *history_expiration,
+  uint32_t *purse_account_limit);
+#endif
diff --git a/src/exchangedb/pg_lookup_kyc_process_by_account.c 
b/src/exchangedb/pg_lookup_kyc_process_by_account.c
new file mode 100644
index 00000000..6183ae7a
--- /dev/null
+++ b/src/exchangedb/pg_lookup_kyc_process_by_account.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 exchangedb/pg_lookup_kyc_process_by_account.c
+ * @brief Implementation of the lookup_kyc_process_by_account function for 
Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_lookup_kyc_process_by_account.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_lookup_kyc_process_by_account (
+  void *cls,
+  const char *provider_section,
+  const struct TALER_PaytoHashP *h_payto,
+  uint64_t *process_row,
+  struct GNUNET_TIME_Absolute *expiration,
+  char **provider_account_id,
+  char **provider_legitimization_id)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (h_payto),
+    GNUNET_PQ_query_param_string (provider_section),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_uint64 ("legitimization_process_serial_id",
+                                  process_row),
+    GNUNET_PQ_result_spec_absolute_time ("expiration_time",
+                                         expiration),
+    GNUNET_PQ_result_spec_allow_null (
+      GNUNET_PQ_result_spec_string ("provider_user_id",
+                                    provider_account_id),
+      NULL),
+    GNUNET_PQ_result_spec_allow_null (
+      GNUNET_PQ_result_spec_string ("provider_legitimization_id",
+                                    provider_legitimization_id),
+      NULL),
+    GNUNET_PQ_result_spec_end
+  };
+
+  *provider_account_id = NULL;
+  *provider_legitimization_id = NULL;
+   /* Used in #postgres_lookup_kyc_process_by_account() */
+  PREPARE (pg,
+           "lookup_process_by_account",
+           "SELECT "
+           " legitimization_process_serial_id"
+           ",expiration_time"
+           ",provider_user_id"
+           ",provider_legitimization_id"
+           " FROM legitimization_processes"
+           " WHERE h_payto=$1"
+           "   AND provider_section=$2;");
+  return GNUNET_PQ_eval_prepared_singleton_select (
+    pg->conn,
+    "lookup_process_by_account",
+    params,
+    rs);
+}
diff --git a/src/exchangedb/pg_lookup_kyc_process_by_account.h 
b/src/exchangedb/pg_lookup_kyc_process_by_account.h
new file mode 100644
index 00000000..40af6a7f
--- /dev/null
+++ b/src/exchangedb/pg_lookup_kyc_process_by_account.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 exchangedb/pg_lookup_kyc_process_by_account.h
+ * @brief implementation of the lookup_kyc_process_by_account function for 
Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_LOOKUP_KYC_PROCESS_BY_ACCOUNT_H
+#define PG_LOOKUP_KYC_PROCESS_BY_ACCOUNT_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+
+/**
+ * Lookup KYC provider meta data.
+ *
+ * @param cls closure
+ * @param provider_section provider that must be checked
+ * @param h_payto account that must be KYC'ed
+ * @param[out] process_row row with the legitimization data
+ * @param[out] expiration how long is this KYC check set to be valid (in the 
past if invalid)
+ * @param[out] provider_account_id provider account ID
+ * @param[out] provider_legitimization_id provider legitimization ID
+ * @return database transaction status
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_lookup_kyc_process_by_account (
+  void *cls,
+  const char *provider_section,
+  const struct TALER_PaytoHashP *h_payto,
+  uint64_t *process_row,
+  struct GNUNET_TIME_Absolute *expiration,
+  char **provider_account_id,
+  char **provider_legitimization_id);
+#endif
diff --git a/src/exchangedb/pg_lookup_kyc_requirement_by_row.c 
b/src/exchangedb/pg_lookup_kyc_requirement_by_row.c
new file mode 100644
index 00000000..6542aa28
--- /dev/null
+++ b/src/exchangedb/pg_lookup_kyc_requirement_by_row.c
@@ -0,0 +1,60 @@
+/*
+   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 exchangedb/pg_lookup_kyc_requirement_by_row.c
+ * @brief Implementation of the lookup_kyc_requirement_by_row function for 
Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_lookup_kyc_requirement_by_row.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_lookup_kyc_requirement_by_row (
+  void *cls,
+  uint64_t requirement_row,
+  char **requirements,
+  struct TALER_PaytoHashP *h_payto)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_uint64 (&requirement_row),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_string ("required_checks",
+                                  requirements),
+    GNUNET_PQ_result_spec_auto_from_type ("h_payto",
+                                          h_payto),
+    GNUNET_PQ_result_spec_end
+  };
+/* Used in #postgres_lookup_kyc_requirement_by_row() */
+  PREPARE (pg,
+           "lookup_legitimization_requirement_by_row",
+           "SELECT "
+           " required_checks"
+           ",h_payto"
+           " FROM legitimization_requirements"
+           " WHERE legitimization_requirement_serial_id=$1;");
+  return GNUNET_PQ_eval_prepared_singleton_select (
+    pg->conn,
+    "lookup_legitimization_requirement_by_row",
+    params,
+    rs);
+}
diff --git a/src/exchangedb/pg_insert_aggregation_tracking.h 
b/src/exchangedb/pg_lookup_kyc_requirement_by_row.h
similarity index 60%
copy from src/exchangedb/pg_insert_aggregation_tracking.h
copy to src/exchangedb/pg_lookup_kyc_requirement_by_row.h
index e67c0e8e..12d72618 100644
--- a/src/exchangedb/pg_insert_aggregation_tracking.h
+++ b/src/exchangedb/pg_lookup_kyc_requirement_by_row.h
@@ -14,29 +14,31 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_insert_aggregation_tracking.h
- * @brief implementation of the insert_aggregation_tracking function for 
Postgres
+ * @file exchangedb/pg_lookup_kyc_requirement_by_row.h
+ * @brief implementation of the lookup_kyc_requirement_by_row function for 
Postgres
  * @author Christian Grothoff
  */
-#ifndef PG_INSERT_AGGREGATION_TRACKING_H
-#define PG_INSERT_AGGREGATION_TRACKING_H
+#ifndef PG_LOOKUP_KYC_REQUIREMENT_BY_ROW_H
+#define PG_LOOKUP_KYC_REQUIREMENT_BY_ROW_H
 
 #include "taler_util.h"
 #include "taler_json_lib.h"
 #include "taler_exchangedb_plugin.h"
 
+
 /**
- * Function called to insert aggregation information into the DB.
+ * Lookup KYC requirement.
  *
  * @param cls closure
- * @param wtid the raw wire transfer identifier we used
- * @param deposit_serial_id row in the deposits table for which this is 
aggregation data
- * @return transaction status code
+ * @param requirement_row identifies requirement to look up
+ * @param[out] requirements provider that must be checked
+ * @param[out] h_payto account that must be KYC'ed
+ * @return database transaction status
  */
 enum GNUNET_DB_QueryStatus
-TEH_PG_insert_aggregation_tracking (
+TEH_PG_lookup_kyc_requirement_by_row (
   void *cls,
-  const struct TALER_WireTransferIdentifierRawP *wtid,
-  unsigned long long deposit_serial_id);
-
+  uint64_t requirement_row,
+  char **requirements,
+  struct TALER_PaytoHashP *h_payto);
 #endif
diff --git a/src/exchangedb/pg_lookup_wire_fee_by_time.c 
b/src/exchangedb/pg_lookup_wire_fee_by_time.c
new file mode 100644
index 00000000..fdd6f882
--- /dev/null
+++ b/src/exchangedb/pg_lookup_wire_fee_by_time.c
@@ -0,0 +1,158 @@
+/*
+   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 exchangedb/pg_lookup_wire_fee_by_time.c
+ * @brief Implementation of the lookup_wire_fee_by_time function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_lookup_wire_fee_by_time.h"
+#include "pg_helper.h"
+
+
+/**
+ * Closure for #wire_fee_by_time_helper()
+ */
+struct WireFeeLookupContext
+{
+
+  /**
+   * Set to the wire fees. Set to invalid if fees conflict over
+   * the given time period.
+   */
+  struct TALER_WireFeeSet *fees;
+
+  /**
+   * Plugin context.
+   */
+  struct PostgresClosure *pg;
+};
+
+
+/**
+ * Helper function for #postgres_lookup_wire_fee_by_time().
+ * Calls the callback with the wire fee structure.
+ *
+ * @param cls a `struct WireFeeLookupContext`
+ * @param result db results
+ * @param num_results number of results in @a result
+ */
+static void
+wire_fee_by_time_helper (void *cls,
+                         PGresult *result,
+                         unsigned int num_results)
+{
+  struct WireFeeLookupContext *wlc = cls;
+  struct PostgresClosure *pg = wlc->pg;
+
+  for (unsigned int i = 0; i<num_results; i++)
+  {
+    struct TALER_WireFeeSet fs;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
+                                   &fs.wire),
+      TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
+                                   &fs.closing),
+      GNUNET_PQ_result_spec_end
+    };
+
+    if (GNUNET_OK !=
+        GNUNET_PQ_extract_result (result,
+                                  rs,
+                                  i))
+    {
+      GNUNET_break (0);
+      /* invalidate */
+      memset (wlc->fees,
+              0,
+              sizeof (struct TALER_WireFeeSet));
+      return;
+    }
+    if (0 == i)
+    {
+      *wlc->fees = fs;
+      continue;
+    }
+    if (0 !=
+        TALER_wire_fee_set_cmp (&fs,
+                                wlc->fees))
+    {
+      /* invalidate */
+      memset (wlc->fees,
+              0,
+              sizeof (struct TALER_WireFeeSet));
+      return;
+    }
+  }
+}
+
+
+/**
+ * Lookup information about known wire fees.  Finds all applicable
+ * fees in the given range. If they are identical, returns the
+ * respective @a fees. If any of the fees
+ * differ between @a start_time and @a end_time, the transaction
+ * succeeds BUT returns an invalid amount for both fees.
+ *
+ * @param cls closure
+ * @param wire_method the wire method to lookup fees for
+ * @param start_time starting time of fee
+ * @param end_time end time of fee
+ * @param[out] fees wire fees for that time period; if
+ *             different fees exists within this time
+ *             period, an 'invalid' amount is returned.
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_lookup_wire_fee_by_time (
+  void *cls,
+  const char *wire_method,
+  struct GNUNET_TIME_Timestamp start_time,
+  struct GNUNET_TIME_Timestamp end_time,
+  struct TALER_WireFeeSet *fees)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (wire_method),
+    GNUNET_PQ_query_param_timestamp (&start_time),
+    GNUNET_PQ_query_param_timestamp (&end_time),
+    GNUNET_PQ_query_param_end
+  };
+  struct WireFeeLookupContext wlc = {
+    .fees = fees,
+    .pg = pg
+  };
+      /* used in #postgres_lookup_wire_fee_by_time() */
+  PREPARE (pg,
+           "lookup_wire_fee_by_time",
+           "SELECT"
+           " wire_fee_val"
+           ",wire_fee_frac"
+           ",closing_fee_val"
+           ",closing_fee_frac"
+           " FROM wire_fee"
+           " WHERE wire_method=$1"
+           " AND end_date > $2"
+           " AND start_date < $3;");
+  return GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+                                               "lookup_wire_fee_by_time",
+                                               params,
+                                               &wire_fee_by_time_helper,
+                                               &wlc);
+}
diff --git a/src/exchangedb/pg_lookup_wire_fee_by_time.h 
b/src/exchangedb/pg_lookup_wire_fee_by_time.h
new file mode 100644
index 00000000..cbfc36e7
--- /dev/null
+++ b/src/exchangedb/pg_lookup_wire_fee_by_time.h
@@ -0,0 +1,76 @@
+/*
+   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 exchangedb/pg_lookup_wire_fee_by_time.h
+ * @brief implementation of the lookup_wire_fee_by_time function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_LOOKUP_WIRE_FEE_BY_TIME_H
+#define PG_LOOKUP_WIRE_FEE_BY_TIME_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+
+/**
+ * Lookup information about known wire fees.  Finds all applicable
+ * fees in the given range. If they are identical, returns the
+ * respective @a fees. If any of the fees
+ * differ between @a start_time and @a end_time, the transaction
+ * succeeds BUT returns an invalid amount for both fees.
+ *
+ * @param cls closure
+ * @param wire_method the wire method to lookup fees for
+ * @param start_time starting time of fee
+ * @param end_time end time of fee
+ * @param[out] fees wire fees for that time period; if
+ *             different fees exists within this time
+ *             period, an 'invalid' amount is returned.
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_lookup_wire_fee_by_time (
+  void *cls,
+  const char *wire_method,
+  struct GNUNET_TIME_Timestamp start_time,
+  struct GNUNET_TIME_Timestamp end_time,
+  struct TALER_WireFeeSet *fees);
+
+/**
+ * Lookup information about known wire fees.  Finds all applicable
+ * fees in the given range. If they are identical, returns the
+ * respective @a fees. If any of the fees
+ * differ between @a start_time and @a end_time, the transaction
+ * succeeds BUT returns an invalid amount for both fees.
+ *
+ * @param cls closure
+ * @param wire_method the wire method to lookup fees for
+ * @param start_time starting time of fee
+ * @param end_time end time of fee
+ * @param[out] fees wire fees for that time period; if
+ *             different fees exists within this time
+ *             period, an 'invalid' amount is returned.
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_lookup_wire_fee_by_time (
+  void *cls,
+  const char *wire_method,
+  struct GNUNET_TIME_Timestamp start_time,
+  struct GNUNET_TIME_Timestamp end_time,
+  struct TALER_WireFeeSet *fees);
+#endif
diff --git a/src/exchangedb/pg_prefligth.c b/src/exchangedb/pg_preflight.c
similarity index 98%
copy from src/exchangedb/pg_prefligth.c
copy to src/exchangedb/pg_preflight.c
index 9336b6d4..4925db51 100644
--- a/src/exchangedb/pg_prefligth.c
+++ b/src/exchangedb/pg_preflight.c
@@ -22,7 +22,7 @@
 #include "taler_error_codes.h"
 #include "taler_dbevents.h"
 #include "taler_pq_lib.h"
-#include "pg_prefligth.h"
+#include "pg_preflight.h"
 #include "pg_helper.h"
 
 
@@ -38,7 +38,7 @@ TEH_PG_preflight (void *cls)
   if (! pg->init)
   {
     if (GNUNET_OK !=
-        
+
         internal_setup (pg,
                         false))
       return GNUNET_SYSERR;
diff --git a/src/exchangedb/pg_prefligth.h b/src/exchangedb/pg_preflight.h
similarity index 96%
copy from src/exchangedb/pg_prefligth.h
copy to src/exchangedb/pg_preflight.h
index 719d9095..d2b20493 100644
--- a/src/exchangedb/pg_prefligth.h
+++ b/src/exchangedb/pg_preflight.h
@@ -18,8 +18,8 @@
  * @brief implementation of the prefligth function for Postgres
  * @author Christian Grothoff
  */
-#ifndef PG_PREFLIGTH_H
-#define PG_PREFLIGTH_H
+#ifndef PG_PREFLIGHT_H
+#define PG_PREFLIGHT_H
 
 #include "taler_util.h"
 #include "taler_json_lib.h"
diff --git a/src/exchangedb/pg_profit_drains_get_pending.c 
b/src/exchangedb/pg_profit_drains_get_pending.c
new file mode 100644
index 00000000..a7044ebb
--- /dev/null
+++ b/src/exchangedb/pg_profit_drains_get_pending.c
@@ -0,0 +1,79 @@
+/*
+   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 exchangedb/pg_profit_drains_get_pending.c
+ * @brief Implementation of the profit_drains_get_pending function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_profit_drains_get_pending.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_profit_drains_get_pending (
+  void *cls,
+  uint64_t *serial,
+  struct TALER_WireTransferIdentifierRawP *wtid,
+  char **account_section,
+  char **payto_uri,
+  struct GNUNET_TIME_Timestamp *request_timestamp,
+  struct TALER_Amount *amount,
+  struct TALER_MasterSignatureP *master_sig)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_uint64 ("profit_drain_serial_id",
+                                  serial),
+    GNUNET_PQ_result_spec_auto_from_type ("wtid",
+                                          wtid),
+    GNUNET_PQ_result_spec_string ("account_section",
+                                  account_section),
+    GNUNET_PQ_result_spec_string ("payto_uri",
+                                  payto_uri),
+    GNUNET_PQ_result_spec_timestamp ("trigger_date",
+                                     request_timestamp),
+    TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
+                                 amount),
+    GNUNET_PQ_result_spec_auto_from_type ("master_sig",
+                                          master_sig),
+    GNUNET_PQ_result_spec_end
+  };
+ /* Used in #postgres_profit_drains_get_pending() */
+  PREPARE (pg,
+           "get_ready_profit_drain",
+           "SELECT"
+           " profit_drain_serial_id"
+           ",wtid"
+           ",account_section"
+           ",payto_uri"
+           ",trigger_date"
+           ",amount_val"
+           ",amount_frac"
+           ",master_sig"
+           " FROM profit_drains"
+           " WHERE NOT executed"
+           " ORDER BY trigger_date ASC;");
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "get_ready_profit_drain",
+                                                   params,
+                                                   rs);
+}
diff --git a/src/exchangedb/pg_profit_drains_get_pending.h 
b/src/exchangedb/pg_profit_drains_get_pending.h
new file mode 100644
index 00000000..cd793a12
--- /dev/null
+++ b/src/exchangedb/pg_profit_drains_get_pending.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 exchangedb/pg_profit_drains_get_pending.h
+ * @brief implementation of the profit_drains_get_pending function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_PROFIT_DRAINS_GET_PENDING_H
+#define PG_PROFIT_DRAINS_GET_PENDING_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+/**
+ * Get profit drain operation ready to execute.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param[out] serial set to serial ID of the entry
+ * @param[out] wtid set set to wire transfer ID to use
+ * @param[out] account_section set to  account to drain
+ * @param[out] payto_uri set to account to wire funds to
+ * @param[out] request_timestamp set to time of the signature
+ * @param[out] amount set to amount to wire
+ * @param[out] master_sig set to signature affirming the operation
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_profit_drains_get_pending (
+  void *cls,
+  uint64_t *serial,
+  struct TALER_WireTransferIdentifierRawP *wtid,
+  char **account_section,
+  char **payto_uri,
+  struct GNUNET_TIME_Timestamp *request_timestamp,
+  struct TALER_Amount *amount,
+  struct TALER_MasterSignatureP *master_sig);
+
+#endif
diff --git a/src/exchangedb/pg_setup_partitions.c 
b/src/exchangedb/pg_profit_drains_set_finished.c
similarity index 51%
copy from src/exchangedb/pg_setup_partitions.c
copy to src/exchangedb/pg_profit_drains_set_finished.c
index 7a472ed1..b70af31f 100644
--- a/src/exchangedb/pg_setup_partitions.c
+++ b/src/exchangedb/pg_profit_drains_set_finished.c
@@ -14,13 +14,42 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_setup_partitions.c
- * @brief Implementation of the setup_partitions function for Postgres
+ * @file exchangedb/pg_profit_drains_set_finished.c
+ * @brief Implementation of the profit_drains_set_finished function for 
Postgres
  * @author Christian Grothoff
  */
 #include "platform.h"
 #include "taler_error_codes.h"
 #include "taler_dbevents.h"
 #include "taler_pq_lib.h"
-#include "pg_setup_partitions.h"
+#include "pg_profit_drains_set_finished.h"
 #include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_profit_drains_set_finished (
+  void *cls,
+  uint64_t serial)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_uint64 (&serial),
+    GNUNET_PQ_query_param_end
+  };
+
+  PREPARE (pg,
+            "drain_profit_set_finished",
+            "UPDATE profit_drains"
+            " SET"
+            " executed=TRUE"
+            " WHERE profit_drain_serial_id=$1;");
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "drain_profit_set_finished",
+                                             params);
+}
+
+
+
+
+
+
diff --git a/src/exchangedb/pg_insert_aggregation_tracking.h 
b/src/exchangedb/pg_profit_drains_set_finished.h
similarity index 61%
copy from src/exchangedb/pg_insert_aggregation_tracking.h
copy to src/exchangedb/pg_profit_drains_set_finished.h
index e67c0e8e..b0878b5b 100644
--- a/src/exchangedb/pg_insert_aggregation_tracking.h
+++ b/src/exchangedb/pg_profit_drains_set_finished.h
@@ -14,29 +14,27 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_insert_aggregation_tracking.h
- * @brief implementation of the insert_aggregation_tracking function for 
Postgres
+ * @file exchangedb/pg_profit_drains_set_finished.h
+ * @brief implementation of the profit_drains_set_finished function for 
Postgres
  * @author Christian Grothoff
  */
-#ifndef PG_INSERT_AGGREGATION_TRACKING_H
-#define PG_INSERT_AGGREGATION_TRACKING_H
+#ifndef PG_PROFIT_DRAINS_SET_FINISHED_H
+#define PG_PROFIT_DRAINS_SET_FINISHED_H
 
 #include "taler_util.h"
 #include "taler_json_lib.h"
 #include "taler_exchangedb_plugin.h"
 
 /**
- * Function called to insert aggregation information into the DB.
+ * Set profit drain operation to finished.
  *
- * @param cls closure
- * @param wtid the raw wire transfer identifier we used
- * @param deposit_serial_id row in the deposits table for which this is 
aggregation data
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param serial serial ID of the entry to mark finished
  * @return transaction status code
  */
 enum GNUNET_DB_QueryStatus
-TEH_PG_insert_aggregation_tracking (
+TEH_PG_profit_drains_set_finished (
   void *cls,
-  const struct TALER_WireTransferIdentifierRawP *wtid,
-  unsigned long long deposit_serial_id);
+  uint64_t serial);
 
 #endif
diff --git a/src/exchangedb/pg_prefligth.c b/src/exchangedb/pg_rollback.c
similarity index 57%
copy from src/exchangedb/pg_prefligth.c
copy to src/exchangedb/pg_rollback.c
index 9336b6d4..6b200b55 100644
--- a/src/exchangedb/pg_prefligth.c
+++ b/src/exchangedb/pg_rollback.c
@@ -14,20 +14,20 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_prefligth.c
- * @brief Implementation of the prefligth function for Postgres
+ * @file exchangedb/pg_rollback.c
+ * @brief Implementation of the rollback function for Postgres
  * @author Christian Grothoff
  */
 #include "platform.h"
 #include "taler_error_codes.h"
 #include "taler_dbevents.h"
 #include "taler_pq_lib.h"
-#include "pg_prefligth.h"
+#include "pg_rollback.h"
 #include "pg_helper.h"
 
 
-enum GNUNET_GenericReturnValue
-TEH_PG_preflight (void *cls)
+void
+TEH_PG_rollback (void *cls)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_ExecuteStatement es[] = {
@@ -35,30 +35,18 @@ TEH_PG_preflight (void *cls)
     GNUNET_PQ_EXECUTE_STATEMENT_END
   };
 
-  if (! pg->init)
-  {
-    if (GNUNET_OK !=
-        
-        internal_setup (pg,
-                        false))
-      return GNUNET_SYSERR;
-  }
   if (NULL == pg->transaction_name)
-    return GNUNET_OK; /* all good */
-  if (GNUNET_OK ==
-      GNUNET_PQ_exec_statements (pg->conn,
-                                 es))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "BUG: Preflight check rolled back transaction `%s'!\n",
-                pg->transaction_name);
-  }
-  else
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "BUG: Preflight check failed to rollback transaction `%s'!\n",
-                pg->transaction_name);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Skipping rollback, no transaction active\n");
+    return;
   }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Rolling back transaction\n");
+  GNUNET_break (GNUNET_OK ==
+                GNUNET_PQ_exec_statements (pg->conn,
+                                           es));
   pg->transaction_name = NULL;
-  return GNUNET_NO;
 }
+
+
diff --git a/src/exchangedb/pg_setup_partitions.c b/src/exchangedb/pg_rollback.h
similarity index 63%
copy from src/exchangedb/pg_setup_partitions.c
copy to src/exchangedb/pg_rollback.h
index 7a472ed1..ddb9e411 100644
--- a/src/exchangedb/pg_setup_partitions.c
+++ b/src/exchangedb/pg_rollback.h
@@ -14,13 +14,23 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_setup_partitions.c
- * @brief Implementation of the setup_partitions function for Postgres
+ * @file exchangedb/pg_rollback.h
+ * @brief implementation of the rollback function for Postgres
  * @author Christian Grothoff
  */
-#include "platform.h"
-#include "taler_error_codes.h"
-#include "taler_dbevents.h"
-#include "taler_pq_lib.h"
-#include "pg_setup_partitions.h"
-#include "pg_helper.h"
+#ifndef PG_ROLLBACK_H
+#define PG_ROLLBACK_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+/**
+ * Roll back the current transaction of a database connection.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ */
+void
+TEH_PG_rollback (void *cls);
+
+#endif
diff --git a/src/exchangedb/pg_select_aggregation_amounts_for_kyc_check.c 
b/src/exchangedb/pg_select_aggregation_amounts_for_kyc_check.c
new file mode 100644
index 00000000..abddab52
--- /dev/null
+++ b/src/exchangedb/pg_select_aggregation_amounts_for_kyc_check.c
@@ -0,0 +1,158 @@
+/*
+   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 exchangedb/pg_select_aggregation_amounts_for_kyc_check.c
+ * @brief Implementation of the select_aggregation_amounts_for_kyc_check 
function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_select_aggregation_amounts_for_kyc_check.h"
+#include "pg_helper.h"
+
+
+
+
+/**
+ * Closure for #get_kyc_amounts_cb().
+ */
+struct KycAmountCheckContext
+{
+  /**
+   * Function to call per result.
+   */
+  TALER_EXCHANGEDB_KycAmountCallback cb;
+
+  /**
+   * Closure for @e cb.
+   */
+  void *cb_cls;
+
+  /**
+   * Plugin context.
+   */
+  struct PostgresClosure *pg;
+
+  /**
+   * Flag set to #GNUNET_OK as long as everything is fine.
+   */
+  enum GNUNET_GenericReturnValue status;
+
+};
+
+
+/**
+ * Invoke the callback for each result.
+ *
+ * @param cls a `struct KycAmountCheckContext *`
+ * @param result SQL result
+ * @param num_results number of rows in @a result
+ */
+static void
+get_kyc_amounts_cb (void *cls,
+                    PGresult *result,
+                    unsigned int num_results)
+{
+  struct KycAmountCheckContext *ctx = cls;
+  struct PostgresClosure *pg = ctx->pg;
+
+  for (unsigned int i = 0; i < num_results; i++)
+  {
+    struct GNUNET_TIME_Absolute date;
+    struct TALER_Amount amount;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
+                                   &amount),
+      GNUNET_PQ_result_spec_absolute_time ("date",
+                                           &date),
+      GNUNET_PQ_result_spec_end
+    };
+    enum GNUNET_GenericReturnValue ret;
+
+    if (GNUNET_OK !=
+        GNUNET_PQ_extract_result (result,
+                                  rs,
+                                  i))
+    {
+      GNUNET_break (0);
+      ctx->status = GNUNET_SYSERR;
+      return;
+    }
+    ret = ctx->cb (ctx->cb_cls,
+                   &amount,
+                   date);
+    GNUNET_PQ_cleanup_result (rs);
+    switch (ret)
+    {
+    case GNUNET_OK:
+      continue;
+    case GNUNET_NO:
+      break;
+    case GNUNET_SYSERR:
+      ctx->status = GNUNET_SYSERR;
+      break;
+    }
+    break;
+  }
+}
+
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_aggregation_amounts_for_kyc_check (
+  void *cls,
+  const struct TALER_PaytoHashP *h_payto,
+  struct GNUNET_TIME_Absolute time_limit,
+  TALER_EXCHANGEDB_KycAmountCallback kac,
+  void *kac_cls)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (h_payto),
+    GNUNET_PQ_query_param_absolute_time (&time_limit),
+    GNUNET_PQ_query_param_end
+  };
+  struct KycAmountCheckContext ctx = {
+    .cb = kac,
+    .cb_cls = kac_cls,
+    .pg = pg,
+    .status = GNUNET_OK
+  };
+  enum GNUNET_DB_QueryStatus qs;
+
+  PREPARE (pg,
+           "select_kyc_relevant_aggregation_events",
+           "SELECT"
+           " amount_val"
+           ",amount_frac"
+           ",execution_date AS date"
+           " FROM wire_out"
+           " WHERE wire_target_h_payto=$1"
+           "   AND execution_date >= $2"
+           " ORDER BY execution_date DESC");
+
+  qs = GNUNET_PQ_eval_prepared_multi_select (
+    pg->conn,
+    "select_kyc_relevant_aggregation_events",
+    params,
+    &get_kyc_amounts_cb,
+    &ctx);
+  if (GNUNET_OK != ctx.status)
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  return qs;
+}
diff --git a/src/exchangedb/pg_select_aggregation_amounts_for_kyc_check.h 
b/src/exchangedb/pg_select_aggregation_amounts_for_kyc_check.h
new file mode 100644
index 00000000..87fc8677
--- /dev/null
+++ b/src/exchangedb/pg_select_aggregation_amounts_for_kyc_check.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 exchangedb/pg_select_aggregation_amounts_for_kyc_check.h
+ * @brief implementation of the select_aggregation_amounts_for_kyc_check 
function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_SELECT_AGGREGATION_AMOUNTS_FOR_KYC_CHECK_H
+#define PG_SELECT_AGGREGATION_AMOUNTS_FOR_KYC_CHECK_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+
+/**
+ * Call @a kac on deposited amounts after @a time_limit which are relevant for 
a
+ * KYC trigger for a the (credited) account identified by @a h_payto.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param h_payto account identifier
+ * @param time_limit oldest transaction that could be relevant
+ * @param kac function to call for each applicable amount, in reverse 
chronological order (or until @a kac aborts by returning anything except 
#GNUNET_OK).
+ * @param kac_cls closure for @a kac
+ * @return transaction status code, @a kac aborting with #GNUNET_NO is not an 
error
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_aggregation_amounts_for_kyc_check (
+  void *cls,
+  const struct TALER_PaytoHashP *h_payto,
+  struct GNUNET_TIME_Absolute time_limit,
+  TALER_EXCHANGEDB_KycAmountCallback kac,
+  void *kac_cls);
+#endif
diff --git a/src/exchangedb/pg_select_contract.c 
b/src/exchangedb/pg_select_contract.c
new file mode 100644
index 00000000..4f4a525b
--- /dev/null
+++ b/src/exchangedb/pg_select_contract.c
@@ -0,0 +1,66 @@
+/*
+   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 exchangedb/pg_select_contract.c
+ * @brief Implementation of the select_contract function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_select_contract.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_contract (void *cls,
+                          const struct TALER_ContractDiffiePublicP *pub_ckey,
+                          struct TALER_PurseContractPublicKeyP *purse_pub,
+                          struct TALER_PurseContractSignatureP *econtract_sig,
+                          size_t *econtract_size,
+                          void **econtract)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (pub_ckey),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_auto_from_type ("purse_pub",
+                                          purse_pub),
+    GNUNET_PQ_result_spec_auto_from_type ("contract_sig",
+                                          econtract_sig),
+    GNUNET_PQ_result_spec_variable_size ("e_contract",
+                                         econtract,
+                                         econtract_size),
+    GNUNET_PQ_result_spec_end
+  };
+
+    /* Used in #postgres_select_contract */
+  PREPARE (pg,
+      "select_contract",
+      "SELECT "
+      " purse_pub"
+      ",e_contract"
+      ",contract_sig"
+      " FROM contracts"
+      "   WHERE pub_ckey=$1;");
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "select_contract",
+                                                   params,
+                                                   rs);
+
+}
diff --git a/src/exchangedb/pg_select_contract.h 
b/src/exchangedb/pg_select_contract.h
new file mode 100644
index 00000000..a503c8da
--- /dev/null
+++ b/src/exchangedb/pg_select_contract.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 exchangedb/pg_select_contract.h
+ * @brief implementation of the select_contract function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_SELECT_CONTRACT_H
+#define PG_SELECT_CONTRACT_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+/**
+ * Function called to retrieve an encrypted contract.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param purse_pub key to lookup the contract by
+ * @param[out] pub_ckey set to the ephemeral DH used to encrypt the contract
+ * @param[out] econtract_sig set to the signature over the encrypted contract
+ * @param[out] econtract_size set to the number of bytes in @a econtract
+ * @param[out] econtract set to the encrypted contract on success, to be freed 
by the caller
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_contract (void *cls,
+                          const struct TALER_ContractDiffiePublicP *pub_ckey,
+                          struct TALER_PurseContractPublicKeyP *purse_pub,
+                          struct TALER_PurseContractSignatureP *econtract_sig,
+                          size_t *econtract_size,
+                        void **econtract);
+
+#endif
diff --git a/src/exchangedb/pg_select_contract_by_purse.c 
b/src/exchangedb/pg_select_contract_by_purse.c
new file mode 100644
index 00000000..aeeb56d4
--- /dev/null
+++ b/src/exchangedb/pg_select_contract_by_purse.c
@@ -0,0 +1,63 @@
+/*
+   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 exchangedb/pg_select_contract_by_purse.c
+ * @brief Implementation of the select_contract_by_purse function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_select_contract_by_purse.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_contract_by_purse (
+  void *cls,
+  const struct TALER_PurseContractPublicKeyP *purse_pub,
+  struct TALER_EncryptedContract *econtract)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (purse_pub),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_auto_from_type ("pub_ckey",
+                                          &econtract->contract_pub),
+    GNUNET_PQ_result_spec_auto_from_type ("contract_sig",
+                                          &econtract->econtract_sig),
+    GNUNET_PQ_result_spec_variable_size ("e_contract",
+                                         &econtract->econtract,
+                                         &econtract->econtract_size),
+    GNUNET_PQ_result_spec_end
+  };
+ /* Used in #postgres_select_contract_by_purse */
+  PREPARE (pg,
+           "select_contract_by_purse",
+           "SELECT "
+           " pub_ckey"
+           ",e_contract"
+           ",contract_sig"
+           " FROM contracts"
+           "   WHERE purse_pub=$1;");
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "select_contract_by_purse",
+                                                   params,
+                                                   rs);
+
+}
diff --git a/src/exchangedb/pg_insert_aggregation_tracking.h 
b/src/exchangedb/pg_select_contract_by_purse.h
similarity index 60%
copy from src/exchangedb/pg_insert_aggregation_tracking.h
copy to src/exchangedb/pg_select_contract_by_purse.h
index e67c0e8e..0e33a6ba 100644
--- a/src/exchangedb/pg_insert_aggregation_tracking.h
+++ b/src/exchangedb/pg_select_contract_by_purse.h
@@ -14,29 +14,29 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_insert_aggregation_tracking.h
- * @brief implementation of the insert_aggregation_tracking function for 
Postgres
+ * @file exchangedb/pg_select_contract_by_purse.h
+ * @brief implementation of the select_contract_by_purse function for Postgres
  * @author Christian Grothoff
  */
-#ifndef PG_INSERT_AGGREGATION_TRACKING_H
-#define PG_INSERT_AGGREGATION_TRACKING_H
+#ifndef PG_SELECT_CONTRACT_BY_PURSE_H
+#define PG_SELECT_CONTRACT_BY_PURSE_H
 
 #include "taler_util.h"
 #include "taler_json_lib.h"
 #include "taler_exchangedb_plugin.h"
 
+
 /**
- * Function called to insert aggregation information into the DB.
+ * Function called to retrieve an encrypted contract.
  *
- * @param cls closure
- * @param wtid the raw wire transfer identifier we used
- * @param deposit_serial_id row in the deposits table for which this is 
aggregation data
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param purse_pub key to lookup the contract by
+ * @param[out] econtract set to the encrypted contract on success, to be freed 
by the caller
  * @return transaction status code
  */
 enum GNUNET_DB_QueryStatus
-TEH_PG_insert_aggregation_tracking (
+TEH_PG_select_contract_by_purse (
   void *cls,
-  const struct TALER_WireTransferIdentifierRawP *wtid,
-  unsigned long long deposit_serial_id);
-
+  const struct TALER_PurseContractPublicKeyP *purse_pub,
+  struct TALER_EncryptedContract *econtract);
 #endif
diff --git a/src/exchangedb/pg_select_merge_amounts_for_kyc_check.c 
b/src/exchangedb/pg_select_merge_amounts_for_kyc_check.c
new file mode 100644
index 00000000..5cb665fa
--- /dev/null
+++ b/src/exchangedb/pg_select_merge_amounts_for_kyc_check.c
@@ -0,0 +1,160 @@
+/*
+   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 exchangedb/pg_select_merge_amounts_for_kyc_check.c
+ * @brief Implementation of the select_merge_amounts_for_kyc_check function 
for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_select_merge_amounts_for_kyc_check.h"
+#include "pg_helper.h"
+
+
+
+/**
+ * Closure for #get_kyc_amounts_cb().
+ */
+struct KycAmountCheckContext
+{
+  /**
+   * Function to call per result.
+   */
+  TALER_EXCHANGEDB_KycAmountCallback cb;
+
+  /**
+   * Closure for @e cb.
+   */
+  void *cb_cls;
+
+  /**
+   * Plugin context.
+   */
+  struct PostgresClosure *pg;
+
+  /**
+   * Flag set to #GNUNET_OK as long as everything is fine.
+   */
+  enum GNUNET_GenericReturnValue status;
+
+};
+
+/**
+ * Invoke the callback for each result.
+ *
+ * @param cls a `struct KycAmountCheckContext *`
+ * @param result SQL result
+ * @param num_results number of rows in @a result
+ */
+static void
+get_kyc_amounts_cb (void *cls,
+                    PGresult *result,
+                    unsigned int num_results)
+{
+  struct KycAmountCheckContext *ctx = cls;
+  struct PostgresClosure *pg = ctx->pg;
+
+  for (unsigned int i = 0; i < num_results; i++)
+  {
+    struct GNUNET_TIME_Absolute date;
+    struct TALER_Amount amount;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
+                                   &amount),
+      GNUNET_PQ_result_spec_absolute_time ("date",
+                                           &date),
+      GNUNET_PQ_result_spec_end
+    };
+    enum GNUNET_GenericReturnValue ret;
+
+    if (GNUNET_OK !=
+        GNUNET_PQ_extract_result (result,
+                                  rs,
+                                  i))
+    {
+      GNUNET_break (0);
+      ctx->status = GNUNET_SYSERR;
+      return;
+    }
+    ret = ctx->cb (ctx->cb_cls,
+                   &amount,
+                   date);
+    GNUNET_PQ_cleanup_result (rs);
+    switch (ret)
+    {
+    case GNUNET_OK:
+      continue;
+    case GNUNET_NO:
+      break;
+    case GNUNET_SYSERR:
+      ctx->status = GNUNET_SYSERR;
+      break;
+    }
+    break;
+  }
+}
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_merge_amounts_for_kyc_check (
+  void *cls,
+  const struct TALER_PaytoHashP *h_payto,
+  struct GNUNET_TIME_Absolute time_limit,
+  TALER_EXCHANGEDB_KycAmountCallback kac,
+  void *kac_cls)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (h_payto),
+    GNUNET_PQ_query_param_absolute_time (&time_limit),
+    GNUNET_PQ_query_param_end
+  };
+  struct KycAmountCheckContext ctx = {
+    .cb = kac,
+    .cb_cls = kac_cls,
+    .pg = pg,
+    .status = GNUNET_OK
+  };
+  enum GNUNET_DB_QueryStatus qs;
+
+  
+  PREPARE (pg,
+           "select_kyc_relevant_merge_events",
+           "SELECT"
+           " amount_with_fee_val AS amount_val"
+           ",amount_with_fee_frac AS amount_frac"
+           ",merge_timestamp AS date"
+           " FROM account_merges"
+           " JOIN purse_merges USING (purse_pub)"
+           " JOIN purse_requests USING (purse_pub)"
+           " JOIN purse_decision USING (purse_pub)"
+           " WHERE wallet_h_payto=$1"
+           "   AND merge_timestamp >= $2"
+           "   AND NOT refunded"
+           " ORDER BY merge_timestamp DESC");
+  qs = GNUNET_PQ_eval_prepared_multi_select (
+    pg->conn,
+    "select_kyc_relevant_merge_events",
+    params,
+    &get_kyc_amounts_cb,
+    &ctx);
+  if (GNUNET_OK != ctx.status)
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  return qs;
+}
+
diff --git a/src/exchangedb/pg_select_merge_amounts_for_kyc_check.h 
b/src/exchangedb/pg_select_merge_amounts_for_kyc_check.h
new file mode 100644
index 00000000..5d0a9635
--- /dev/null
+++ b/src/exchangedb/pg_select_merge_amounts_for_kyc_check.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 exchangedb/pg_select_merge_amounts_for_kyc_check.h
+ * @brief implementation of the select_merge_amounts_for_kyc_check function 
for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_SELECT_MERGE_AMOUNTS_FOR_KYC_CHECK_H
+#define PG_SELECT_MERGE_AMOUNTS_FOR_KYC_CHECK_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+/**
+ * Call @a kac on merged reserve amounts after @a time_limit which are 
relevant for a
+ * KYC trigger for a the wallet identified by @a h_payto.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param h_payto account identifier
+ * @param time_limit oldest transaction that could be relevant
+ * @param kac function to call for each applicable amount, in reverse 
chronological order (or until @a kac aborts by returning anything except 
#GNUNET_OK).
+ * @param kac_cls closure for @a kac
+ * @return transaction status code, @a kac aborting with #GNUNET_NO is not an 
error
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_merge_amounts_for_kyc_check (
+  void *cls,
+  const struct TALER_PaytoHashP *h_payto,
+  struct GNUNET_TIME_Absolute time_limit,
+  TALER_EXCHANGEDB_KycAmountCallback kac,
+  void *kac_cls);
+
+#endif
diff --git a/src/exchangedb/pg_select_purse_merge.c 
b/src/exchangedb/pg_select_purse_merge.c
new file mode 100644
index 00000000..d1f6a539
--- /dev/null
+++ b/src/exchangedb/pg_select_purse_merge.c
@@ -0,0 +1,74 @@
+/*
+   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 exchangedb/pg_select_purse_merge.c
+ * @brief Implementation of the select_purse_merge function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_select_purse_merge.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_purse_merge (
+  void *cls,
+  const struct TALER_PurseContractPublicKeyP *purse_pub,
+  struct TALER_PurseMergeSignatureP *merge_sig,
+  struct GNUNET_TIME_Timestamp *merge_timestamp,
+  char **partner_url,
+  struct TALER_ReservePublicKeyP *reserve_pub)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (purse_pub),
+    GNUNET_PQ_query_param_end
+  };
+  bool is_null;
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_auto_from_type ("merge_sig",
+                                          merge_sig),
+    GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
+                                          reserve_pub),
+    GNUNET_PQ_result_spec_timestamp ("merge_timestamp",
+                                     merge_timestamp),
+    GNUNET_PQ_result_spec_allow_null (
+      GNUNET_PQ_result_spec_string ("partner_base_url",
+                                    partner_url),
+      &is_null),
+    GNUNET_PQ_result_spec_end
+  };
+
+  *partner_url = NULL;
+ /* Used in #postgres_select_purse_merge */
+  PREPARE (pg,
+           "select_purse_merge",
+           "SELECT "
+           " reserve_pub"
+           ",merge_sig"
+           ",merge_timestamp"
+           ",partner_base_url"
+           " FROM purse_merges"
+           " LEFT JOIN partners USING (partner_serial_id)"
+           " WHERE purse_pub=$1;");
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "select_purse_merge",
+                                                   params,
+                                                   rs);
+}
diff --git a/src/exchangedb/pg_select_purse_merge.h 
b/src/exchangedb/pg_select_purse_merge.h
new file mode 100644
index 00000000..98222512
--- /dev/null
+++ b/src/exchangedb/pg_select_purse_merge.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 exchangedb/pg_select_purse_merge.h
+ * @brief implementation of the select_purse_merge function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_SELECT_PURSE_MERGE_H
+#define PG_SELECT_PURSE_MERGE_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+/**
+ * Function called to approve merging of a purse with
+ * an account, made by the receiving account.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param purse_pub public key of the purse
+ * @param[out] merge_sig set to the signature confirming the merge
+ * @param[out] merge_timestamp set to the time of the merge
+ * @param[out] partner_url set to the URL of the target exchange, or NULL if 
the target exchange is us. To be freed by the caller.
+ * @param[out] reserve_pub set to the public key of the reserve/account being 
credited
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_purse_merge (
+  void *cls,
+  const struct TALER_PurseContractPublicKeyP *purse_pub,
+  struct TALER_PurseMergeSignatureP *merge_sig,
+  struct GNUNET_TIME_Timestamp *merge_timestamp,
+  char **partner_url,
+  struct TALER_ReservePublicKeyP *reserve_pub);
+
+#endif
diff --git a/src/exchangedb/pg_select_satisfied_kyc_processes.c 
b/src/exchangedb/pg_select_satisfied_kyc_processes.c
new file mode 100644
index 00000000..f2191581
--- /dev/null
+++ b/src/exchangedb/pg_select_satisfied_kyc_processes.c
@@ -0,0 +1,152 @@
+/*
+   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 exchangedb/pg_select_satisfied_kyc_processes.c
+ * @brief Implementation of the select_satisfied_kyc_processes function for 
Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_select_satisfied_kyc_processes.h"
+#include "pg_helper.h"
+
+
+
+
+
+
+
+
+
+
+
+/**
+ * Closure for #get_wire_fees_cb().
+ */
+struct GetLegitimizationsContext
+{
+  /**
+   * Function to call per result.
+   */
+  TALER_EXCHANGEDB_SatisfiedProviderCallback cb;
+
+  /**
+   * Closure for @e cb.
+   */
+  void *cb_cls;
+
+  /**
+   * Plugin context.
+   */
+  struct PostgresClosure *pg;
+
+  /**
+   * Flag set to #GNUNET_OK as long as everything is fine.
+   */
+  enum GNUNET_GenericReturnValue status;
+
+};
+
+
+/**
+ * Invoke the callback for each result.
+ *
+ * @param cls a `struct GetLegitimizationsContext *`
+ * @param result SQL result
+ * @param num_results number of rows in @a result
+ */
+static void
+get_legitimizations_cb (void *cls,
+                        PGresult *result,
+                        unsigned int num_results)
+{
+  struct GetLegitimizationsContext *ctx = cls;
+
+  for (unsigned int i = 0; i < num_results; i++)
+  {
+    char *provider_section;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      GNUNET_PQ_result_spec_string ("provider_section",
+                                    &provider_section),
+      GNUNET_PQ_result_spec_end
+    };
+
+    if (GNUNET_OK !=
+        GNUNET_PQ_extract_result (result,
+                                  rs,
+                                  i))
+    {
+      GNUNET_break (0);
+      ctx->status = GNUNET_SYSERR;
+      return;
+    }
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Found satisfied LEGI: %s\n",
+                provider_section);
+    ctx->cb (ctx->cb_cls,
+             provider_section);
+    GNUNET_PQ_cleanup_result (rs);
+  }
+}
+
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_satisfied_kyc_processes (
+  void *cls,
+  const struct TALER_PaytoHashP *h_payto,
+  TALER_EXCHANGEDB_SatisfiedProviderCallback spc,
+  void *spc_cls)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_TIME_Absolute now
+    = GNUNET_TIME_absolute_get ();
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (h_payto),
+    GNUNET_PQ_query_param_absolute_time (&now),
+    GNUNET_PQ_query_param_end
+  };
+  struct GetLegitimizationsContext ctx = {
+    .cb = spc,
+    .cb_cls = spc_cls,
+    .pg = pg,
+    .status = GNUNET_OK
+  };
+  enum GNUNET_DB_QueryStatus qs;
+   /* Used in #postgres_select_satisfied_kyc_processes() */
+  PREPARE (pg,
+           "get_satisfied_legitimizations",
+           "SELECT "
+           " provider_section"
+           " FROM legitimization_processes"
+           " WHERE h_payto=$1"
+           "   AND expiration_time>=$2;");
+
+  qs = GNUNET_PQ_eval_prepared_multi_select (
+    pg->conn,
+    "get_satisfied_legitimizations",
+    params,
+    &get_legitimizations_cb,
+    &ctx);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Satisfied LEGI check returned %d\n",
+              qs);
+  if (GNUNET_OK != ctx.status)
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  return qs;
+}
diff --git a/src/exchangedb/pg_insert_aggregation_tracking.h 
b/src/exchangedb/pg_select_satisfied_kyc_processes.h
similarity index 58%
copy from src/exchangedb/pg_insert_aggregation_tracking.h
copy to src/exchangedb/pg_select_satisfied_kyc_processes.h
index e67c0e8e..bc1639ff 100644
--- a/src/exchangedb/pg_insert_aggregation_tracking.h
+++ b/src/exchangedb/pg_select_satisfied_kyc_processes.h
@@ -14,29 +14,34 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_insert_aggregation_tracking.h
- * @brief implementation of the insert_aggregation_tracking function for 
Postgres
+ * @file exchangedb/pg_select_satisfied_kyc_processes.h
+ * @brief implementation of the select_satisfied_kyc_processes function for 
Postgres
  * @author Christian Grothoff
  */
-#ifndef PG_INSERT_AGGREGATION_TRACKING_H
-#define PG_INSERT_AGGREGATION_TRACKING_H
+#ifndef PG_SELECT_SATISFIED_KYC_PROCESSES_H
+#define PG_SELECT_SATISFIED_KYC_PROCESSES_H
 
 #include "taler_util.h"
 #include "taler_json_lib.h"
 #include "taler_exchangedb_plugin.h"
 
 /**
- * Function called to insert aggregation information into the DB.
+ * Call us on KYC processes satisfied for the given
+ * account.
  *
- * @param cls closure
- * @param wtid the raw wire transfer identifier we used
- * @param deposit_serial_id row in the deposits table for which this is 
aggregation data
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param h_payto account identifier
+ * @param spc function to call for each satisfied KYC process
+ * @param spc_cls closure for @a spc
  * @return transaction status code
  */
+
+
 enum GNUNET_DB_QueryStatus
-TEH_PG_insert_aggregation_tracking (
+TEH_PG_select_satisfied_kyc_processes (
   void *cls,
-  const struct TALER_WireTransferIdentifierRawP *wtid,
-  unsigned long long deposit_serial_id);
+  const struct TALER_PaytoHashP *h_payto,
+  TALER_EXCHANGEDB_SatisfiedProviderCallback spc,
+  void *spc_cls);
 
 #endif
diff --git a/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.c 
b/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.c
new file mode 100644
index 00000000..e200da8d
--- /dev/null
+++ b/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.c
@@ -0,0 +1,158 @@
+/*
+   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 exchangedb/pg_select_withdraw_amounts_for_kyc_check.c
+ * @brief Implementation of the select_withdraw_amounts_for_kyc_check function 
for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_select_withdraw_amounts_for_kyc_check.h"
+#include "pg_select_aggregation_amounts_for_kyc_check.h"
+#include "pg_helper.h"
+
+
+/**
+ * Closure for #get_kyc_amounts_cb().
+ */
+struct KycAmountCheckContext
+{
+  /**
+   * Function to call per result.
+   */
+  TALER_EXCHANGEDB_KycAmountCallback cb;
+
+  /**
+   * Closure for @e cb.
+   */
+  void *cb_cls;
+
+  /**
+   * Plugin context.
+   */
+  struct PostgresClosure *pg;
+
+  /**
+   * Flag set to #GNUNET_OK as long as everything is fine.
+   */
+  enum GNUNET_GenericReturnValue status;
+
+};
+
+/**
+ * Invoke the callback for each result.
+ *
+ * @param cls a `struct KycAmountCheckContext *`
+ * @param result SQL result
+ * @param num_results number of rows in @a result
+ */
+static void
+get_kyc_amounts_cb (void *cls,
+                    PGresult *result,
+                    unsigned int num_results)
+{
+  struct KycAmountCheckContext *ctx = cls;
+  struct PostgresClosure *pg = ctx->pg;
+
+  for (unsigned int i = 0; i < num_results; i++)
+  {
+    struct GNUNET_TIME_Absolute date;
+    struct TALER_Amount amount;
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
+                                   &amount),
+      GNUNET_PQ_result_spec_absolute_time ("date",
+                                           &date),
+      GNUNET_PQ_result_spec_end
+    };
+    enum GNUNET_GenericReturnValue ret;
+
+    if (GNUNET_OK !=
+        GNUNET_PQ_extract_result (result,
+                                  rs,
+                                  i))
+    {
+      GNUNET_break (0);
+      ctx->status = GNUNET_SYSERR;
+      return;
+    }
+    ret = ctx->cb (ctx->cb_cls,
+                   &amount,
+                   date);
+    GNUNET_PQ_cleanup_result (rs);
+    switch (ret)
+    {
+    case GNUNET_OK:
+      continue;
+    case GNUNET_NO:
+      break;
+    case GNUNET_SYSERR:
+      ctx->status = GNUNET_SYSERR;
+      break;
+    }
+    break;
+  }
+}
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_withdraw_amounts_for_kyc_check (
+  void *cls,
+  const struct TALER_PaytoHashP *h_payto,
+  struct GNUNET_TIME_Absolute time_limit,
+  TALER_EXCHANGEDB_KycAmountCallback kac,
+  void *kac_cls)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (h_payto),
+    GNUNET_PQ_query_param_absolute_time (&time_limit),
+    GNUNET_PQ_query_param_end
+  };
+  struct KycAmountCheckContext ctx = {
+    .cb = kac,
+    .cb_cls = kac_cls,
+    .pg = pg,
+    .status = GNUNET_OK
+  };
+  enum GNUNET_DB_QueryStatus qs;
+ /* Used in #postgres_select_withdraw_amounts_for_kyc_check (
+() */
+  PREPARE (pg,
+             "select_kyc_relevant_withdraw_events",
+             "SELECT"
+             " ro.amount_with_fee_val AS amount_val"
+             ",ro.amount_with_fee_frac AS amount_frac"
+             ",ro.execution_date AS date"
+             " FROM reserves_out ro"
+             " JOIN reserves_out_by_reserve USING (h_blind_ev)"
+             " JOIN reserves res ON (ro.reserve_uuid = res.reserve_uuid)"
+             " JOIN reserves_in ri ON (res.reserve_pub = ri.reserve_pub)"
+             " WHERE wire_source_h_payto=$1"
+             "   AND ro.execution_date >= $2"
+             " ORDER BY ro.execution_date DESC");
+  qs = GNUNET_PQ_eval_prepared_multi_select (
+    pg->conn,
+    "select_kyc_relevant_withdraw_events",
+    params,
+    &get_kyc_amounts_cb,
+    &ctx);
+  if (GNUNET_OK != ctx.status)
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  return qs;
+}
diff --git a/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.h 
b/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.h
new file mode 100644
index 00000000..4c128374
--- /dev/null
+++ b/src/exchangedb/pg_select_withdraw_amounts_for_kyc_check.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 exchangedb/pg_select_withdraw_amounts_for_kyc_check.h
+ * @brief implementation of the select_withdraw_amounts_for_kyc_check function 
for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_SELECT_WITHDRAW_AMOUNTS_FOR_KYC_CHECK_H
+#define PG_SELECT_WITHDRAW_AMOUNTS_FOR_KYC_CHECK_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+
+/**
+ * Call @a kac on withdrawn amounts after @a time_limit which are relevant
+ * for a KYC trigger for a the (debited) account identified by @a h_payto.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param h_payto account identifier
+ * @param time_limit oldest transaction that could be relevant
+ * @param kac function to call for each applicable amount, in reverse 
chronological order (or until @a kac aborts by returning anything except 
#GNUNET_OK).
+ * @param kac_cls closure for @a kac
+ * @return transaction status code, @a kac aborting with #GNUNET_NO is not an 
error
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_select_withdraw_amounts_for_kyc_check (
+  void *cls,
+  const struct TALER_PaytoHashP *h_payto,
+  struct GNUNET_TIME_Absolute time_limit,
+  TALER_EXCHANGEDB_KycAmountCallback kac,
+  void *kac_cls);
+#endif
diff --git a/src/exchangedb/pg_setup_partitions.c 
b/src/exchangedb/pg_setup_partitions.c
index 7a472ed1..6785931a 100644
--- a/src/exchangedb/pg_setup_partitions.c
+++ b/src/exchangedb/pg_setup_partitions.c
@@ -24,3 +24,50 @@
 #include "taler_pq_lib.h"
 #include "pg_setup_partitions.h"
 #include "pg_helper.h"
+
+/**
+ * Setup partitions of already existing tables
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param num the number of partitions to create for each partitioned table
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ */
+enum GNUNET_GenericReturnValue
+TEH_PG_setup_partitions (void *cls,
+                           uint32_t num)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_Context *conn;
+  enum GNUNET_GenericReturnValue ret = GNUNET_OK;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_uint32 (&num),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_PreparedStatement ps[] = {
+    GNUNET_PQ_make_prepare ("setup_partitions",
+                            "SELECT"
+                            " create_partitions"
+                            " ($1);"),
+    GNUNET_PQ_PREPARED_STATEMENT_END
+  };
+  struct GNUNET_PQ_ExecuteStatement es[] = {
+    GNUNET_PQ_make_try_execute ("SET search_path TO exchange;"),
+    GNUNET_PQ_EXECUTE_STATEMENT_END
+  };
+
+  conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
+                                     "exchangedb-postgres",
+                                     NULL,
+                                     es,
+                                     ps);
+  if (NULL == conn)
+    return GNUNET_SYSERR;
+  ret = GNUNET_OK;
+  if (0 > GNUNET_PQ_eval_prepared_non_select (conn,
+                                              "setup_partitions",
+                                              params))
+    ret = GNUNET_SYSERR;
+  GNUNET_PQ_disconnect (conn);
+  return ret;
+}
+
diff --git a/src/exchangedb/pg_prefligth.c b/src/exchangedb/pg_start.c
similarity index 57%
copy from src/exchangedb/pg_prefligth.c
copy to src/exchangedb/pg_start.c
index 9336b6d4..395b8773 100644
--- a/src/exchangedb/pg_prefligth.c
+++ b/src/exchangedb/pg_start.c
@@ -14,51 +14,44 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_prefligth.c
- * @brief Implementation of the prefligth function for Postgres
+ * @file exchangedb/pg_start.c
+ * @brief Implementation of the start function for Postgres
  * @author Christian Grothoff
  */
 #include "platform.h"
 #include "taler_error_codes.h"
 #include "taler_dbevents.h"
 #include "taler_pq_lib.h"
-#include "pg_prefligth.h"
+#include "pg_preflight.h"
+#include "pg_start.h"
 #include "pg_helper.h"
 
-
 enum GNUNET_GenericReturnValue
-TEH_PG_preflight (void *cls)
+TEH_PG_start (void *cls,
+                const char *name)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_ExecuteStatement es[] = {
-    GNUNET_PQ_make_execute ("ROLLBACK"),
+    GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL SERIALIZABLE"),
     GNUNET_PQ_EXECUTE_STATEMENT_END
   };
 
-  if (! pg->init)
-  {
-    if (GNUNET_OK !=
-        
-        internal_setup (pg,
-                        false))
-      return GNUNET_SYSERR;
-  }
-  if (NULL == pg->transaction_name)
-    return GNUNET_OK; /* all good */
-  if (GNUNET_OK ==
+  GNUNET_assert (NULL != name);
+  if (GNUNET_SYSERR ==
+      TEH_PG_preflight (pg))
+    return GNUNET_SYSERR;
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Starting transaction `%s'\n",
+              name);
+  if (GNUNET_OK !=
       GNUNET_PQ_exec_statements (pg->conn,
                                  es))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "BUG: Preflight check rolled back transaction `%s'!\n",
-                pg->transaction_name);
+    TALER_LOG_ERROR ("Failed to start transaction\n");
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
   }
-  else
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "BUG: Preflight check failed to rollback transaction `%s'!\n",
-                pg->transaction_name);
-  }
-  pg->transaction_name = NULL;
-  return GNUNET_NO;
+  pg->transaction_name = name;
+  return GNUNET_OK;
 }
+
diff --git a/src/exchangedb/pg_prefligth.h b/src/exchangedb/pg_start.h
similarity index 63%
copy from src/exchangedb/pg_prefligth.h
copy to src/exchangedb/pg_start.h
index 719d9095..0a3bb9e4 100644
--- a/src/exchangedb/pg_prefligth.h
+++ b/src/exchangedb/pg_start.h
@@ -14,30 +14,27 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_prefligth.h
- * @brief implementation of the prefligth function for Postgres
+ * @file exchangedb/pg_start.h
+ * @brief implementation of the start function for Postgres
  * @author Christian Grothoff
  */
-#ifndef PG_PREFLIGTH_H
-#define PG_PREFLIGTH_H
+#ifndef PG_START_H
+#define PG_START_H
 
 #include "taler_util.h"
 #include "taler_json_lib.h"
 #include "taler_exchangedb_plugin.h"
 
-
 /**
- * Do a pre-flight check that we are not in an uncommitted transaction.
- * If we are, try to commit the previous transaction and output a warning.
- * Does not return anything, as we will continue regardless of the outcome.
+ * Start a transaction.
  *
  * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @return #GNUNET_OK if everything is fine
- *         #GNUNET_NO if a transaction was rolled back
- *         #GNUNET_SYSERR on hard errors
+ * @param name unique name identifying the transaction (for debugging)
+ *             must point to a constant
+ * @return #GNUNET_OK on success
  */
-
-
 enum GNUNET_GenericReturnValue
-TEH_PG_preflight (void *cls);
+TEH_PG_start (void *cls,
+              const char *name);
+
 #endif
diff --git a/src/exchangedb/pg_prefligth.c 
b/src/exchangedb/pg_start_read_committed.c
similarity index 57%
copy from src/exchangedb/pg_prefligth.c
copy to src/exchangedb/pg_start_read_committed.c
index 9336b6d4..ec207f0c 100644
--- a/src/exchangedb/pg_prefligth.c
+++ b/src/exchangedb/pg_start_read_committed.c
@@ -14,51 +14,43 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_prefligth.c
- * @brief Implementation of the prefligth function for Postgres
+ * @file exchangedb/pg_start_read_commited.c
+ * @brief Implementation of the start_read_commited function for Postgres
  * @author Christian Grothoff
  */
 #include "platform.h"
 #include "taler_error_codes.h"
 #include "taler_dbevents.h"
 #include "taler_pq_lib.h"
-#include "pg_prefligth.h"
+#include "pg_start_read_committed.h"
+#include "pg_preflight.h"
 #include "pg_helper.h"
 
-
 enum GNUNET_GenericReturnValue
-TEH_PG_preflight (void *cls)
+TEH_PG_start_read_committed (void *cls,
+                               const char *name)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_ExecuteStatement es[] = {
-    GNUNET_PQ_make_execute ("ROLLBACK"),
+    GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL READ 
COMMITTED"),
     GNUNET_PQ_EXECUTE_STATEMENT_END
   };
 
-  if (! pg->init)
-  {
-    if (GNUNET_OK !=
-        
-        internal_setup (pg,
-                        false))
-      return GNUNET_SYSERR;
-  }
-  if (NULL == pg->transaction_name)
-    return GNUNET_OK; /* all good */
-  if (GNUNET_OK ==
+  GNUNET_assert (NULL != name);
+  if (GNUNET_SYSERR ==
+      TEH_PG_preflight (pg))
+    return GNUNET_SYSERR;
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Starting READ COMMITTED transaction `%s`\n",
+              name);
+  if (GNUNET_OK !=
       GNUNET_PQ_exec_statements (pg->conn,
                                  es))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "BUG: Preflight check rolled back transaction `%s'!\n",
-                pg->transaction_name);
-  }
-  else
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "BUG: Preflight check failed to rollback transaction `%s'!\n",
-                pg->transaction_name);
+    TALER_LOG_ERROR ("Failed to start transaction\n");
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
   }
-  pg->transaction_name = NULL;
-  return GNUNET_NO;
+  pg->transaction_name = name;
+  return GNUNET_OK;
 }
diff --git a/src/exchangedb/pg_prefligth.h 
b/src/exchangedb/pg_start_read_committed.h
similarity index 63%
copy from src/exchangedb/pg_prefligth.h
copy to src/exchangedb/pg_start_read_committed.h
index 719d9095..6330a138 100644
--- a/src/exchangedb/pg_prefligth.h
+++ b/src/exchangedb/pg_start_read_committed.h
@@ -14,30 +14,26 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_prefligth.h
- * @brief implementation of the prefligth function for Postgres
+ * @file exchangedb/pg_start_read_commited.h
+ * @brief implementation of the start_read_commited function for Postgres
  * @author Christian Grothoff
  */
-#ifndef PG_PREFLIGTH_H
-#define PG_PREFLIGTH_H
+#ifndef PG_START_READ_COMMITTED_H
+#define PG_START_READ_COMMITTED_H
 
 #include "taler_util.h"
 #include "taler_json_lib.h"
 #include "taler_exchangedb_plugin.h"
-
-
 /**
- * Do a pre-flight check that we are not in an uncommitted transaction.
- * If we are, try to commit the previous transaction and output a warning.
- * Does not return anything, as we will continue regardless of the outcome.
+ * Start a READ COMMITTED transaction.
  *
  * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @return #GNUNET_OK if everything is fine
- *         #GNUNET_NO if a transaction was rolled back
- *         #GNUNET_SYSERR on hard errors
+ * @param name unique name identifying the transaction (for debugging)
+ *             must point to a constant
+ * @return #GNUNET_OK on success
  */
-
-
 enum GNUNET_GenericReturnValue
-TEH_PG_preflight (void *cls);
+TEH_PG_start_read_committed (void *cls,
+                             const char *name);
+
 #endif
diff --git a/src/exchangedb/pg_prefligth.c b/src/exchangedb/pg_start_read_only.c
similarity index 57%
rename from src/exchangedb/pg_prefligth.c
rename to src/exchangedb/pg_start_read_only.c
index 9336b6d4..103f9b92 100644
--- a/src/exchangedb/pg_prefligth.c
+++ b/src/exchangedb/pg_start_read_only.c
@@ -14,51 +14,43 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_prefligth.c
- * @brief Implementation of the prefligth function for Postgres
+ * @file exchangedb/pg_start_read_only.c
+ * @brief Implementation of the start_read_only function for Postgres
  * @author Christian Grothoff
  */
 #include "platform.h"
 #include "taler_error_codes.h"
 #include "taler_dbevents.h"
 #include "taler_pq_lib.h"
-#include "pg_prefligth.h"
+#include "pg_start_read_only.h"
 #include "pg_helper.h"
 
-
 enum GNUNET_GenericReturnValue
-TEH_PG_preflight (void *cls)
+TEH_PG_start_read_only (void *cls,
+                          const char *name)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_ExecuteStatement es[] = {
-    GNUNET_PQ_make_execute ("ROLLBACK"),
+    GNUNET_PQ_make_execute (
+      "START TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY"),
     GNUNET_PQ_EXECUTE_STATEMENT_END
   };
 
-  if (! pg->init)
-  {
-    if (GNUNET_OK !=
-        
-        internal_setup (pg,
-                        false))
-      return GNUNET_SYSERR;
-  }
-  if (NULL == pg->transaction_name)
-    return GNUNET_OK; /* all good */
-  if (GNUNET_OK ==
+  GNUNET_assert (NULL != name);
+  if (GNUNET_SYSERR ==
+      TEH_PG_preflight (pg))
+    return GNUNET_SYSERR;
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Starting READ ONLY transaction `%s`\n",
+              name);
+  if (GNUNET_OK !=
       GNUNET_PQ_exec_statements (pg->conn,
                                  es))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "BUG: Preflight check rolled back transaction `%s'!\n",
-                pg->transaction_name);
-  }
-  else
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "BUG: Preflight check failed to rollback transaction `%s'!\n",
-                pg->transaction_name);
+    TALER_LOG_ERROR ("Failed to start transaction\n");
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
   }
-  pg->transaction_name = NULL;
-  return GNUNET_NO;
+  pg->transaction_name = name;
+  return GNUNET_OK;
 }
diff --git a/src/exchangedb/pg_prefligth.h b/src/exchangedb/pg_start_read_only.h
similarity index 63%
rename from src/exchangedb/pg_prefligth.h
rename to src/exchangedb/pg_start_read_only.h
index 719d9095..bf639c19 100644
--- a/src/exchangedb/pg_prefligth.h
+++ b/src/exchangedb/pg_start_read_only.h
@@ -14,30 +14,27 @@
    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 /**
- * @file exchangedb/pg_prefligth.h
- * @brief implementation of the prefligth function for Postgres
+ * @file exchangedb/pg_start_read_only.h
+ * @brief implementation of the start_read_only function for Postgres
  * @author Christian Grothoff
  */
-#ifndef PG_PREFLIGTH_H
-#define PG_PREFLIGTH_H
+#ifndef PG_START_READ_ONLY_H
+#define PG_START_READ_ONLY_H
 
 #include "taler_util.h"
 #include "taler_json_lib.h"
 #include "taler_exchangedb_plugin.h"
 
-
 /**
- * Do a pre-flight check that we are not in an uncommitted transaction.
- * If we are, try to commit the previous transaction and output a warning.
- * Does not return anything, as we will continue regardless of the outcome.
+ * Start a READ ONLY serializable transaction.
  *
  * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @return #GNUNET_OK if everything is fine
- *         #GNUNET_NO if a transaction was rolled back
- *         #GNUNET_SYSERR on hard errors
+ * @param name unique name identifying the transaction (for debugging)
+ *             must point to a constant
+ * @return #GNUNET_OK on success
  */
-
-
 enum GNUNET_GenericReturnValue
-TEH_PG_preflight (void *cls);
+TEH_PG_start_read_only (void *cls,
+                        const char *name);
+
 #endif
diff --git a/src/exchangedb/pg_update_auditor.c 
b/src/exchangedb/pg_update_auditor.c
new file mode 100644
index 00000000..9d82f25d
--- /dev/null
+++ b/src/exchangedb/pg_update_auditor.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 exchangedb/pg_update_auditor.c
+ * @brief Implementation of the update_auditor function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_update_auditor.h"
+#include "pg_helper.h"
+
+
+enum GNUNET_DB_QueryStatus
+TEH_PG_update_auditor (void *cls,
+                         const struct TALER_AuditorPublicKeyP *auditor_pub,
+                         const char *auditor_url,
+                         const char *auditor_name,
+                         struct GNUNET_TIME_Timestamp change_date,
+                         bool enabled)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_auto_from_type (auditor_pub),
+    GNUNET_PQ_query_param_string (auditor_url),
+    GNUNET_PQ_query_param_string (auditor_name),
+    GNUNET_PQ_query_param_bool (enabled),
+    GNUNET_PQ_query_param_timestamp (&change_date),
+    GNUNET_PQ_query_param_end
+  };
+    /* used in #postgres_update_auditor() */
+  PREPARE(pg,
+          "update_auditor",
+          "UPDATE auditors"
+          " SET"
+          "  auditor_url=$2"
+          " ,auditor_name=$3"
+          " ,is_active=$4"
+          " ,last_change=$5"
+          " WHERE auditor_pub=$1");
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "update_auditor",
+                                             params);
+}
diff --git a/src/exchangedb/pg_update_auditor.h 
b/src/exchangedb/pg_update_auditor.h
new file mode 100644
index 00000000..af8d0606
--- /dev/null
+++ b/src/exchangedb/pg_update_auditor.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 exchangedb/pg_update_auditor.h
+ * @brief implementation of the update_auditor function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_UPDATE_AUDITOR_H
+#define PG_UPDATE_AUDITOR_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+/**
+ * Update information about an auditor that will audit this exchange.
+ *
+ * @param cls closure
+ * @param auditor_pub key of the auditor (primary key for the existing record)
+ * @param auditor_url base URL of the auditor's REST service, to be updated
+ * @param auditor_name name of the auditor (for humans)
+ * @param change_date date when the auditor status was last changed
+ *                      (only to be used for replay detection)
+ * @param enabled true to enable, false to disable
+ * @return transaction status code
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_update_auditor (void *cls,
+                         const struct TALER_AuditorPublicKeyP *auditor_pub,
+                         const char *auditor_url,
+                         const char *auditor_name,
+                         struct GNUNET_TIME_Timestamp change_date,
+                       bool enabled);
+
+#endif
diff --git a/src/exchangedb/pg_update_kyc_process_by_row.c 
b/src/exchangedb/pg_update_kyc_process_by_row.c
new file mode 100644
index 00000000..444f108b
--- /dev/null
+++ b/src/exchangedb/pg_update_kyc_process_by_row.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 exchangedb/pg_update_kyc_process_by_row.c
+ * @brief Implementation of the update_kyc_process_by_row function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_error_codes.h"
+#include "taler_dbevents.h"
+#include "taler_pq_lib.h"
+#include "pg_update_kyc_process_by_row.h"
+#include "pg_helper.h"
+
+enum GNUNET_DB_QueryStatus
+TEh_PG_update_kyc_process_by_row (
+  void *cls,
+  uint64_t process_row,
+  const char *provider_section,
+  const struct TALER_PaytoHashP *h_payto,
+  const char *provider_account_id,
+  const char *provider_legitimization_id,
+  struct GNUNET_TIME_Absolute expiration)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_uint64 (&process_row),
+    GNUNET_PQ_query_param_string (provider_section),
+    GNUNET_PQ_query_param_auto_from_type (h_payto),
+    (NULL != provider_account_id)
+    ? GNUNET_PQ_query_param_string (provider_account_id)
+    : GNUNET_PQ_query_param_null (),
+    (NULL != provider_legitimization_id)
+    ? GNUNET_PQ_query_param_string (provider_legitimization_id)
+    : GNUNET_PQ_query_param_null (),
+    GNUNET_PQ_query_param_absolute_time (&expiration),
+    GNUNET_PQ_query_param_end
+  };
+  enum GNUNET_DB_QueryStatus qs;
+
+  qs = GNUNET_PQ_eval_prepared_non_select (
+    pg->conn,
+    "update_legitimization_process",
+    params);
+  if (qs <= 0)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Failed to update legitimization process: %d\n",
+                qs);
+    return qs;
+  }
+  if (GNUNET_TIME_absolute_is_future (expiration))
+  {
+    enum GNUNET_DB_QueryStatus qs2;
+    struct TALER_KycCompletedEventP rep = {
+      .header.size = htons (sizeof (rep)),
+      .header.type = htons (TALER_DBEVENT_EXCHANGE_KYC_COMPLETED),
+      .h_payto = *h_payto
+    };
+    uint32_t trigger_type = 1;
+    struct GNUNET_PQ_QueryParam params2[] = {
+      GNUNET_PQ_query_param_auto_from_type (h_payto),
+      GNUNET_PQ_query_param_uint32 (&trigger_type),
+      GNUNET_PQ_query_param_end
+    };
+
+    postgres_event_notify (pg,
+                           &rep.header,
+                           NULL,
+                           0);
+    PREPARE (pg,
+             "alert_kyc_status_change",
+             "INSERT INTO kyc_alerts"
+             " (h_payto"
+             " ,trigger_type)"
+             " VALUES"
+             " ($1,$2);");
+    qs2 = GNUNET_PQ_eval_prepared_non_select (
+      pg->conn,
+      "alert_kyc_status_change",
+      params2);
+    if (qs2 < 0)
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Failed to store KYC alert: %d\n",
+                  qs2);
+  }
+  return qs;
+}
+
+
diff --git a/src/exchangedb/pg_update_kyc_process_by_row.h 
b/src/exchangedb/pg_update_kyc_process_by_row.h
new file mode 100644
index 00000000..07e896db
--- /dev/null
+++ b/src/exchangedb/pg_update_kyc_process_by_row.h
@@ -0,0 +1,51 @@
+/*
+   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 exchangedb/pg_update_kyc_process_by_row.h
+ * @brief implementation of the update_kyc_process_by_row function for Postgres
+ * @author Christian Grothoff
+ */
+#ifndef PG_UPDATE_KYC_PROCESS_BY_ROW_H
+#define PG_UPDATE_KYC_PROCESS_BY_ROW_H
+
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+/**
+ * Update KYC requirement check with provider-linkage and/or
+ * expiration data.
+ *
+ * @param cls closure
+ * @param process_row row to select by
+ * @param provider_section provider that must be checked (technically 
redundant)
+ * @param h_payto account that must be KYC'ed (helps access by shard, 
otherwise also redundant)
+ * @param provider_account_id provider account ID
+ * @param provider_legitimization_id provider legitimization ID
+ * @param expiration how long is this KYC check set to be valid (in the past 
if invalid)
+ * @return database transaction status
+ */
+enum GNUNET_DB_QueryStatus
+TEH_PG_update_kyc_process_by_row (
+  void *cls,
+  uint64_t process_row,
+  const char *provider_section,
+  const struct TALER_PaytoHashP *h_payto,
+  const char *provider_account_id,
+  const char *provider_legitimization_id,
+  struct GNUNET_TIME_Absolute expiration);
+
+#endif
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c 
b/src/exchangedb/plugin_exchangedb_postgres.c
index 7bd5fed0..7d3e49cb 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -63,12 +63,47 @@
 /**WHAT I ADD**/
 #include "pg_insert_purse_request.h"
 #include "pg_iterate_active_signkeys.h"
-#include "pg_prefligth.h"
+#include "pg_preflight.h"
 #include "pg_commit.h"
 #include "pg_create_shard_tables.h"
 #include "pg_insert_aggregation_tracking.h"
 #include "pg_drop_tables.h"
 #include "pg_setup_partitions.h"
+#include "pg_select_satisfied_kyc_processes.h"
+#include "pg_select_aggregation_amounts_for_kyc_check.h"
+#include "pg_kyc_provider_account_lookup.h"
+#include "pg_lookup_kyc_requirement_by_row.h"
+#include "pg_insert_kyc_requirement_for_account.h"
+#include "pg_lookup_kyc_process_by_account.h"
+#include "pg_update_kyc_process_by_row.h"
+#include "pg_insert_kyc_requirement_process.h"
+#include "pg_select_withdraw_amounts_for_kyc_check.h"
+#include "pg_select_merge_amounts_for_kyc_check.h"
+#include "pg_profit_drains_set_finished.h"
+#include "pg_profit_drains_get_pending.h"
+#include "pg_get_drain_profit.h"
+#include "pg_get_purse_deposit.h"
+#include "pg_insert_contract.h"
+#include "pg_select_contract.h"
+#include "pg_select_purse_merge.h"
+#include "pg_select_contract_by_purse.h"
+#include "pg_insert_drain_profit.h"
+#include "pg_do_reserve_purse.h"
+#include "pg_lookup_global_fee_by_time.h"
+#include "pg_do_purse_deposit.h"
+#include "pg_activate_signing_key.h"
+#include "pg_update_auditor.h"
+#include "pg_begin_revolving_shard.h"
+#include "pg_get_extension_manifest.h"
+#include "pg_insert_history_request.h"
+#include "pg_do_purse_merge.h"
+#include "pg_start_read_committed.h"
+#include "pg_start_read_only.h"
+#include "pg_insert_denomination_info.h"
+#include "pg_do_batch_withdraw_insert.h"
+#include "pg_lookup_wire_fee_by_time.h"
+#include "pg_start.h"
+#include "pg_rollback.h"
 /**
  * Set to 1 to enable Postgres auto_explain module. This will
  * slow down things a _lot_, but also provide extensive logging
@@ -456,54 +491,9 @@ prepare_statements (struct PostgresClosure *pg)
       ",closing_fee_frac"
       ",close_request_row"
       ") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9);"),
-    /* Used in #postgres_insert_drain_profit() */
-    GNUNET_PQ_make_prepare (
-      "drain_profit_insert",
-      "INSERT INTO profit_drains "
-      "(wtid"
-      ",account_section"
-      ",payto_uri"
-      ",trigger_date"
-      ",amount_val"
-      ",amount_frac"
-      ",master_sig"
-      ") VALUES ($1, $2, $3, $4, $5, $6, $7);"),
-       
-    /* Used in #postgres_profit_drains_get_pending() */
-    GNUNET_PQ_make_prepare (
-      "get_ready_profit_drain",
-      "SELECT"
-      " profit_drain_serial_id"
-      ",wtid"
-      ",account_section"
-      ",payto_uri"
-      ",trigger_date"
-      ",amount_val"
-      ",amount_frac"
-      ",master_sig"
-      " FROM profit_drains"
-      " WHERE NOT executed"
-      " ORDER BY trigger_date ASC;"),
-    /* Used in #postgres_profit_drains_get() */
-    GNUNET_PQ_make_prepare (
-      "get_profit_drain",
-      "SELECT"
-      " profit_drain_serial_id"
-      ",account_section"
-      ",payto_uri"
-      ",trigger_date"
-      ",amount_val"
-      ",amount_frac"
-      ",master_sig"
-      " FROM profit_drains"
-      " WHERE wtid=$1;"),
-    /* Used in #postgres_profit_drains_set_finished() */
-    GNUNET_PQ_make_prepare (
-      "drain_profit_set_finished",
-      "UPDATE profit_drains"
-      " SET"
-      " executed=TRUE"
-      " WHERE profit_drain_serial_id=$1;"),
+   
+   
+   
     /* Used in #postgres_reserves_update() when the reserve is updated */
     GNUNET_PQ_make_prepare (
       "reserve_update",
@@ -575,17 +565,7 @@ prepare_statements (struct PostgresClosure *pg)
       ",ruuid"
       " FROM exchange_do_batch_withdraw"
       " ($1,$2,$3,$4,$5);"),
-    /* Used in #postgres_do_batch_withdraw_insert() to store
-       the signature of a blinded coin with the blinded coin's
-       details. */
-    GNUNET_PQ_make_prepare (
-      "call_batch_withdraw_insert",
-      "SELECT "
-      " out_denom_unknown AS denom_unknown"
-      ",out_conflict AS conflict"
-      ",out_nonce_reuse AS nonce_reuse"
-      " FROM exchange_do_batch_withdraw_insert"
-      " ($1,$2,$3,$4,$5,$6,$7,$8,$9);"),
+   
     /* Used in #postgres_do_deposit() to execute a deposit,
        checking the coin's balance in the process as needed. */
     GNUNET_PQ_make_prepare (
@@ -596,14 +576,7 @@ prepare_statements (struct PostgresClosure *pg)
       ",out_conflict AS conflicted"
       " FROM exchange_do_deposit"
       " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17);"),
-    /* used in postgres_do_purse_deposit() */
-    GNUNET_PQ_make_prepare (
-      "call_purse_deposit",
-      "SELECT "
-      " out_balance_ok AS balance_ok"
-      ",out_conflict AS conflict"
-      " FROM exchange_do_purse_deposit"
-      " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10);"),
+
     /* Used in #postgres_update_aggregation_transient() */
     GNUNET_PQ_make_prepare (
       "set_purse_balance",
@@ -1645,16 +1618,7 @@ prepare_statements (struct PostgresClosure *pg)
       ",last_change"
       ") VALUES "
       "($1, $2, $3, true, $4);"),
-    /* used in #postgres_update_auditor() */
-    GNUNET_PQ_make_prepare (
-      "update_auditor",
-      "UPDATE auditors"
-      " SET"
-      "  auditor_url=$2"
-      " ,auditor_name=$3"
-      " ,is_active=$4"
-      " ,last_change=$5"
-      " WHERE auditor_pub=$1"),
+
     /* used in #postgres_insert_wire() */
     GNUNET_PQ_make_prepare (
       "insert_wire",
@@ -1713,17 +1677,7 @@ prepare_statements (struct PostgresClosure *pg)
       "   (SELECT esk_serial"
       "      FROM exchange_sign_keys"
       "     WHERE exchange_pub=$1);"),
-    /* used in #postgres_insert_signkey() */
-    GNUNET_PQ_make_prepare (
-      "insert_signkey",
-      "INSERT INTO exchange_sign_keys "
-      "(exchange_pub"
-      ",valid_from"
-      ",expire_sign"
-      ",expire_legal"
-      ",master_sig"
-      ") VALUES "
-      "($1, $2, $3, $4, $5);"),
+
     /* used in #postgres_lookup_signing_key() */
     GNUNET_PQ_make_prepare (
       "lookup_signing_key",
@@ -1783,34 +1737,8 @@ prepare_statements (struct PostgresClosure *pg)
       "  (SELECT denominations_serial"
       "    FROM denominations"
       "    WHERE denom_pub_hash=$2);"),
-    /* used in #postgres_lookup_wire_fee_by_time() */
-    GNUNET_PQ_make_prepare (
-      "lookup_wire_fee_by_time",
-      "SELECT"
-      " wire_fee_val"
-      ",wire_fee_frac"
-      ",closing_fee_val"
-      ",closing_fee_frac"
-      " FROM wire_fee"
-      " WHERE wire_method=$1"
-      " AND end_date > $2"
-      " AND start_date < $3;"),
-    /* used in #postgres_lookup_wire_fee_by_time() */
-    GNUNET_PQ_make_prepare (
-      "lookup_global_fee_by_time",
-      "SELECT"
-      " history_fee_val"
-      ",history_fee_frac"
-      ",account_fee_val"
-      ",account_fee_frac"
-      ",purse_fee_val"
-      ",purse_fee_frac"
-      ",purse_timeout"
-      ",history_expiration"
-      ",purse_account_limit"
-      " FROM global_fee"
-      " WHERE end_date > $1"
-      "   AND start_date < $2;"),
+
+
        /* Used in #postgres_begin_shard() */
     GNUNET_PQ_make_prepare (
       "get_open_shard",
@@ -1823,17 +1751,7 @@ prepare_statements (struct PostgresClosure *pg)
       "   AND last_attempt<$2"
       " ORDER BY last_attempt ASC"
       " LIMIT 1;"),
-    /* Used in #postgres_begin_revolving_shard() */
-    GNUNET_PQ_make_prepare (
-      "get_open_revolving_shard",
-      "SELECT"
-      " start_row"
-      ",end_row"
-      " FROM revolving_work_shards"
-      " WHERE job_name=$1"
-      "   AND active=FALSE"
-      " ORDER BY last_attempt ASC"
-      " LIMIT 1;"),
+
     /* Used in #postgres_begin_shard() */
     GNUNET_PQ_make_prepare (
       "reclaim_shard",
@@ -1842,15 +1760,7 @@ prepare_statements (struct PostgresClosure *pg)
       " WHERE job_name=$1"
       "   AND start_row=$3"
       "   AND end_row=$4"),
-    /* Used in #postgres_begin_revolving_shard() */
-    GNUNET_PQ_make_prepare (
-      "reclaim_revolving_shard",
-      "UPDATE revolving_work_shards"
-      " SET last_attempt=$2"
-      "    ,active=TRUE"
-      " WHERE job_name=$1"
-      "   AND start_row=$3"
-      "   AND end_row=$4"),
+
     /* Used in #postgres_begin_shard() */
     GNUNET_PQ_make_prepare (
       "get_last_shard",
@@ -1860,15 +1770,7 @@ prepare_statements (struct PostgresClosure *pg)
       " WHERE job_name=$1"
       " ORDER BY end_row DESC"
       " LIMIT 1;"),
-    /* Used in #postgres_begin_revolving_shard() */
-    GNUNET_PQ_make_prepare (
-      "get_last_revolving_shard",
-      "SELECT"
-      " end_row"
-      " FROM revolving_work_shards"
-      " WHERE job_name=$1"
-      " ORDER BY end_row DESC"
-      " LIMIT 1;"),
+
     /* Used in #postgres_abort_shard() */
     GNUNET_PQ_make_prepare (
       "abort_shard",
@@ -1887,17 +1789,7 @@ prepare_statements (struct PostgresClosure *pg)
       ",end_row"
       ") VALUES "
       "($1, $2, $3, $4);"),
-    /* Used in #postgres_claim_revolving_shard() */
-    GNUNET_PQ_make_prepare (
-      "create_revolving_shard",
-      "INSERT INTO revolving_work_shards"
-      "(job_name"
-      ",last_attempt"
-      ",start_row"
-      ",end_row"
-      ",active"
-      ") VALUES "
-      "($1, $2, $3, $4, TRUE);"),
+
     /* Used in #postgres_complete_shard() */
     GNUNET_PQ_make_prepare (
       "complete_shard",
@@ -1920,45 +1812,10 @@ prepare_statements (struct PostgresClosure *pg)
       "INSERT INTO extensions (name, manifest) VALUES ($1, $2) "
       "ON CONFLICT (name) "
       "DO UPDATE SET manifest=$2"),
-    /* Used in #postgres_get_extension_manifest */
-    GNUNET_PQ_make_prepare (
-      "get_extension_manifest",
-      "SELECT "
-      " manifest "
-      "FROM extensions"
-      "   WHERE name=$1;"),
-    /* Used in #postgres_insert_contract() */
-    GNUNET_PQ_make_prepare (
-      "insert_contract",
-      "INSERT INTO contracts"
-      "  (purse_pub"
-      "  ,pub_ckey"
-      "  ,e_contract"
-      "  ,contract_sig"
-      "  ,purse_expiration"
-      "  ) SELECT "
-      "  $1, $2, $3, $4, purse_expiration"
-      "  FROM purse_requests"
-      "  WHERE purse_pub=$1"
-      "  ON CONFLICT DO NOTHING;"),
-    /* Used in #postgres_select_contract */
-    GNUNET_PQ_make_prepare (
-      "select_contract",
-      "SELECT "
-      " purse_pub"
-      ",e_contract"
-      ",contract_sig"
-      " FROM contracts"
-      "   WHERE pub_ckey=$1;"),
-    /* Used in #postgres_select_contract_by_purse */
-    GNUNET_PQ_make_prepare (
-      "select_contract_by_purse",
-      "SELECT "
-      " pub_ckey"
-      ",e_contract"
-      ",contract_sig"
-      " FROM contracts"
-      "   WHERE purse_pub=$1;"),
+
+
+   
+   
    
     /* Used in #postgres_select_purse_by_merge_pub */
     GNUNET_PQ_make_prepare (
@@ -1975,92 +1832,17 @@ prepare_statements (struct PostgresClosure *pg)
       ",purse_sig"
       " FROM purse_requests"
       " WHERE merge_pub=$1;"),
-    /* Used in #postgres_get_purse_deposit */
-    GNUNET_PQ_make_prepare (
-      "select_purse_deposit_by_coin_pub",
-      "SELECT "
-      " coin_sig"
-      ",amount_with_fee_val"
-      ",amount_with_fee_frac"
-      ",denom_pub_hash"
-      ",age_commitment_hash"
-      ",partner_base_url"
-      " FROM purse_deposits"
-      " LEFT JOIN partners USING (partner_serial_id)"
-      " JOIN known_coins kc USING (coin_pub)"
-      " JOIN denominations USING (denominations_serial)"
-      " WHERE coin_pub=$2"
-      "   AND purse_pub=$1;"),
-    /* Used in #postgres_do_purse_merge() */
-    GNUNET_PQ_make_prepare (
-      "call_purse_merge",
-      "SELECT"
-      " out_no_partner AS no_partner"
-      ",out_no_balance AS no_balance"
-      ",out_conflict AS conflict"
-      " FROM exchange_do_purse_merge"
-      "  ($1, $2, $3, $4, $5, $6, $7, $8);"),
-    /* Used in #postgres_do_reserve_purse() */
-    GNUNET_PQ_make_prepare (
-      "call_reserve_purse",
-      "SELECT"
-      " out_no_funds AS insufficient_funds"
-      ",out_no_reserve AS no_reserve"
-      ",out_conflict AS conflict"
-      " FROM exchange_do_reserve_purse"
-      "  ($1, $2, $3, $4, $5, $6, $7, $8, $9);"),
-    /* Used in #postgres_select_purse_merge */
-    GNUNET_PQ_make_prepare (
-      "select_purse_merge",
-      "SELECT "
-      " reserve_pub"
-      ",merge_sig"
-      ",merge_timestamp"
-      ",partner_base_url"
-      " FROM purse_merges"
-      " LEFT JOIN partners USING (partner_serial_id)"
-      " WHERE purse_pub=$1;"),
+   
+     
     /* Used in #postgres_do_account_merge() */
     GNUNET_PQ_make_prepare (
       "call_account_merge",
       "SELECT 1"
       " FROM exchange_do_account_merge"
       "  ($1, $2, $3);"),
-    /* Used in #postgres_insert_history_request() */
-    GNUNET_PQ_make_prepare (
-      "call_history_request",
-      "SELECT"
-      "  out_balance_ok AS balance_ok"
-      " ,out_idempotent AS idempotent"
-      " FROM exchange_do_history_request"
-      "  ($1, $2, $3, $4, $5)"),
 
-    /* Used in #postgres_insert_kyc_requirement_for_account() */
-    GNUNET_PQ_make_prepare (
-      "insert_legitimization_requirement",
-      "INSERT INTO legitimization_requirements"
-      "  (h_payto"
-      "  ,required_checks"
-      "  ) VALUES "
-      "  ($1, $2)"
-      " ON CONFLICT (h_payto,required_checks) "
-      "   DO UPDATE SET h_payto=$1" /* syntax requirement: dummy op */
-      " RETURNING legitimization_requirement_serial_id"),
-    /* Used in #postgres_insert_kyc_requirement_process() */
-    GNUNET_PQ_make_prepare (
-      "insert_legitimization_process",
-      "INSERT INTO legitimization_processes"
-      "  (h_payto"
-      "  ,provider_section"
-      "  ,provider_user_id"
-      "  ,provider_legitimization_id"
-      "  ) VALUES "
-      "  ($1, $2, $3, $4)"
-      " ON CONFLICT (h_payto,provider_section) "
-      "   DO UPDATE SET"
-      "      provider_user_id=$3"
-      "     ,provider_legitimization_id=$4"
-      " RETURNING legitimization_process_serial_id"),
+
+   
     /* Used in #postgres_update_kyc_requirement_by_row() */
     GNUNET_PQ_make_prepare (
       "update_legitimization_process",
@@ -2072,94 +1854,12 @@ prepare_statements (struct PostgresClosure *pg)
       "      h_payto=$3"
       "  AND legitimization_process_serial_id=$1"
       "  AND provider_section=$2;"),
-    GNUNET_PQ_make_prepare (
-      "alert_kyc_status_change",
-      "INSERT INTO kyc_alerts"
-      " (h_payto"
-      " ,trigger_type)"
-      " VALUES"
-      " ($1,$2);"),
-    /* Used in #postgres_lookup_kyc_requirement_by_row() */
-    GNUNET_PQ_make_prepare (
-      "lookup_legitimization_requirement_by_row",
-      "SELECT "
-      " required_checks"
-      ",h_payto"
-      " FROM legitimization_requirements"
-      " WHERE legitimization_requirement_serial_id=$1;"),
-    /* Used in #postgres_lookup_kyc_process_by_account() */
-    GNUNET_PQ_make_prepare (
-      "lookup_process_by_account",
-      "SELECT "
-      " legitimization_process_serial_id"
-      ",expiration_time"
-      ",provider_user_id"
-      ",provider_legitimization_id"
-      " FROM legitimization_processes"
-      " WHERE h_payto=$1"
-      "   AND provider_section=$2;"),
-    /* Used in #postgres_kyc_provider_account_lookup() */
-    GNUNET_PQ_make_prepare (
-      "get_wire_target_by_legitimization_id",
-      "SELECT "
-      " h_payto"
-      ",legitimization_process_serial_id"
-      " FROM legitimization_processes"
-      " WHERE provider_legitimization_id=$1"
-      "   AND provider_section=$2;"),
-    /* Used in #postgres_select_satisfied_kyc_processes() */
-    GNUNET_PQ_make_prepare (
-      "get_satisfied_legitimizations",
-      "SELECT "
-      " provider_section"
-      " FROM legitimization_processes"
-      " WHERE h_payto=$1"
-      "   AND expiration_time>=$2;"),
-
-    /* Used in #postgres_select_withdraw_amounts_for_kyc_check (
-() */
-    GNUNET_PQ_make_prepare (
-      "select_kyc_relevant_withdraw_events",
-      "SELECT"
-      " ro.amount_with_fee_val AS amount_val"
-      ",ro.amount_with_fee_frac AS amount_frac"
-      ",ro.execution_date AS date"
-      " FROM reserves_out ro"
-      " JOIN reserves_out_by_reserve USING (h_blind_ev)"
-      " JOIN reserves res ON (ro.reserve_uuid = res.reserve_uuid)"
-      " JOIN reserves_in ri ON (res.reserve_pub = ri.reserve_pub)"
-      " WHERE wire_source_h_payto=$1"
-      "   AND ro.execution_date >= $2"
-      " ORDER BY ro.execution_date DESC"),
-    /* Used in #postgres_select_aggregation_amounts_for_kyc_check (
-() */
-    GNUNET_PQ_make_prepare (
-      "select_kyc_relevant_aggregation_events",
-      "SELECT"
-      " amount_val"
-      ",amount_frac"
-      ",execution_date AS date"
-      " FROM wire_out"
-      " WHERE wire_target_h_payto=$1"
-      "   AND execution_date >= $2"
-      " ORDER BY execution_date DESC"),
+   
+     
+   
+   
+   
 
-    /* Used in #postgres_select_merge_amounts_for_kyc_check (
-() */
-    GNUNET_PQ_make_prepare (
-      "select_kyc_relevant_merge_events",
-      "SELECT"
-      " amount_with_fee_val AS amount_val"
-      ",amount_with_fee_frac AS amount_frac"
-      ",merge_timestamp AS date"
-      " FROM account_merges"
-      " JOIN purse_merges USING (purse_pub)"
-      " JOIN purse_requests USING (purse_pub)"
-      " JOIN purse_decision USING (purse_pub)"
-      " WHERE wallet_h_payto=$1"
-      "   AND merge_timestamp >= $2"
-      "   AND NOT refunded"
-      " ORDER BY merge_timestamp DESC"),
 
     GNUNET_PQ_PREPARED_STATEMENT_END
   };
@@ -2237,277 +1937,73 @@ internal_setup (struct PostgresClosure *pg,
 
 
 
+
 /**
- * Start a transaction.
+ * Register callback to be invoked on events of type @a es.
  *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param name unique name identifying the transaction (for debugging)
- *             must point to a constant
- * @return #GNUNET_OK on success
+ * @param cls database context to use
+ * @param timeout how long until to generate a timeout event
+ * @param es specification of the event to listen for
+ * @param cb function to call when the event happens, possibly
+ *         multiple times (until cancel is invoked)
+ * @param cb_cls closure for @a cb
+ * @return handle useful to cancel the listener
  */
-static enum GNUNET_GenericReturnValue
-postgres_start (void *cls,
-                const char *name)
+static struct GNUNET_DB_EventHandler *
+postgres_event_listen (void *cls,
+                       struct GNUNET_TIME_Relative timeout,
+                       const struct GNUNET_DB_EventHeaderP *es,
+                       GNUNET_DB_EventCallback cb,
+                       void *cb_cls)
 {
   struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_ExecuteStatement es[] = {
-    GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL SERIALIZABLE"),
-    GNUNET_PQ_EXECUTE_STATEMENT_END
-  };
 
-  GNUNET_assert (NULL != name);
-  if (GNUNET_SYSERR ==
-      TEH_PG_preflight (pg))
-    return GNUNET_SYSERR;
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Starting transaction `%s'\n",
-              name);
-  if (GNUNET_OK !=
-      GNUNET_PQ_exec_statements (pg->conn,
-                                 es))
-  {
-    TALER_LOG_ERROR ("Failed to start transaction\n");
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  pg->transaction_name = name;
-  return GNUNET_OK;
+  return GNUNET_PQ_event_listen (pg->conn,
+                                 es,
+                                 timeout,
+                                 cb,
+                                 cb_cls);
 }
 
 
 /**
- * Start a READ COMMITTED transaction.
+ * Stop notifications.
  *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param name unique name identifying the transaction (for debugging)
- *             must point to a constant
- * @return #GNUNET_OK on success
+ * @param cls the plugin's `struct PostgresClosure`
+ * @param eh handle to unregister.
  */
-static enum GNUNET_GenericReturnValue
-postgres_start_read_committed (void *cls,
-                               const char *name)
+static void
+postgres_event_listen_cancel (void *cls,
+                              struct GNUNET_DB_EventHandler *eh)
 {
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_ExecuteStatement es[] = {
-    GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL READ 
COMMITTED"),
-    GNUNET_PQ_EXECUTE_STATEMENT_END
-  };
-
-  GNUNET_assert (NULL != name);
-  if (GNUNET_SYSERR ==
-      TEH_PG_preflight (pg))
-    return GNUNET_SYSERR;
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Starting READ COMMITTED transaction `%s`\n",
-              name);
-  if (GNUNET_OK !=
-      GNUNET_PQ_exec_statements (pg->conn,
-                                 es))
-  {
-    TALER_LOG_ERROR ("Failed to start transaction\n");
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  pg->transaction_name = name;
-  return GNUNET_OK;
+  (void) cls;
+  GNUNET_PQ_event_listen_cancel (eh);
 }
 
 
 /**
- * Start a READ ONLY serializable transaction.
+ * Notify all that listen on @a es of an event.
  *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param name unique name identifying the transaction (for debugging)
- *             must point to a constant
- * @return #GNUNET_OK on success
+ * @param cls database context to use
+ * @param es specification of the event to generate
+ * @param extra additional event data provided
+ * @param extra_size number of bytes in @a extra
  */
-static enum GNUNET_GenericReturnValue
-postgres_start_read_only (void *cls,
-                          const char *name)
+static void
+postgres_event_notify (void *cls,
+                       const struct GNUNET_DB_EventHeaderP *es,
+                       const void *extra,
+                       size_t extra_size)
 {
   struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_ExecuteStatement es[] = {
-    GNUNET_PQ_make_execute (
-      "START TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY"),
-    GNUNET_PQ_EXECUTE_STATEMENT_END
-  };
 
-  GNUNET_assert (NULL != name);
-  if (GNUNET_SYSERR ==
-      TEH_PG_preflight (pg))
-    return GNUNET_SYSERR;
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Starting READ ONLY transaction `%s`\n",
-              name);
-  if (GNUNET_OK !=
-      GNUNET_PQ_exec_statements (pg->conn,
-                                 es))
-  {
-    TALER_LOG_ERROR ("Failed to start transaction\n");
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  pg->transaction_name = name;
-  return GNUNET_OK;
+  GNUNET_PQ_event_notify (pg->conn,
+                          es,
+                          extra,
+                          extra_size);
 }
 
 
-/**
- * Roll back the current transaction of a database connection.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- */
-static void
-postgres_rollback (void *cls)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_ExecuteStatement es[] = {
-    GNUNET_PQ_make_execute ("ROLLBACK"),
-    GNUNET_PQ_EXECUTE_STATEMENT_END
-  };
-
-  if (NULL == pg->transaction_name)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Skipping rollback, no transaction active\n");
-    return;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Rolling back transaction\n");
-  GNUNET_break (GNUNET_OK ==
-                GNUNET_PQ_exec_statements (pg->conn,
-                                           es));
-  pg->transaction_name = NULL;
-}
-
-
-
-
-/**
- * Register callback to be invoked on events of type @a es.
- *
- * @param cls database context to use
- * @param timeout how long until to generate a timeout event
- * @param es specification of the event to listen for
- * @param cb function to call when the event happens, possibly
- *         multiple times (until cancel is invoked)
- * @param cb_cls closure for @a cb
- * @return handle useful to cancel the listener
- */
-static struct GNUNET_DB_EventHandler *
-postgres_event_listen (void *cls,
-                       struct GNUNET_TIME_Relative timeout,
-                       const struct GNUNET_DB_EventHeaderP *es,
-                       GNUNET_DB_EventCallback cb,
-                       void *cb_cls)
-{
-  struct PostgresClosure *pg = cls;
-
-  return GNUNET_PQ_event_listen (pg->conn,
-                                 es,
-                                 timeout,
-                                 cb,
-                                 cb_cls);
-}
-
-
-/**
- * Stop notifications.
- *
- * @param cls the plugin's `struct PostgresClosure`
- * @param eh handle to unregister.
- */
-static void
-postgres_event_listen_cancel (void *cls,
-                              struct GNUNET_DB_EventHandler *eh)
-{
-  (void) cls;
-  GNUNET_PQ_event_listen_cancel (eh);
-}
-
-
-/**
- * Notify all that listen on @a es of an event.
- *
- * @param cls database context to use
- * @param es specification of the event to generate
- * @param extra additional event data provided
- * @param extra_size number of bytes in @a extra
- */
-static void
-postgres_event_notify (void *cls,
-                       const struct GNUNET_DB_EventHeaderP *es,
-                       const void *extra,
-                       size_t extra_size)
-{
-  struct PostgresClosure *pg = cls;
-
-  GNUNET_PQ_event_notify (pg->conn,
-                          es,
-                          extra,
-                          extra_size);
-}
-
-
-/**
- * Insert a denomination key's public information into the database for
- * reference by auditors and other consistency checks.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param denom_pub the public key used for signing coins of this denomination
- * @param issue issuing information with value, fees and other info about the 
coin
- * @return status of the query
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_denomination_info (
-  void *cls,
-  const struct TALER_DenominationPublicKey *denom_pub,
-  const struct TALER_EXCHANGEDB_DenominationKeyInformation *issue)
-{
-  struct PostgresClosure *pg = cls;
-  struct TALER_DenominationHashP denom_hash;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (&issue->denom_hash),
-    TALER_PQ_query_param_denom_pub (denom_pub),
-    GNUNET_PQ_query_param_auto_from_type (&issue->signature),
-    GNUNET_PQ_query_param_timestamp (&issue->start),
-    GNUNET_PQ_query_param_timestamp (&issue->expire_withdraw),
-    GNUNET_PQ_query_param_timestamp (&issue->expire_deposit),
-    GNUNET_PQ_query_param_timestamp (&issue->expire_legal),
-    TALER_PQ_query_param_amount (&issue->value),
-    TALER_PQ_query_param_amount (&issue->fees.withdraw),
-    TALER_PQ_query_param_amount (&issue->fees.deposit),
-    TALER_PQ_query_param_amount (&issue->fees.refresh),
-    TALER_PQ_query_param_amount (&issue->fees.refund),
-    GNUNET_PQ_query_param_uint32 (&denom_pub->age_mask.bits),
-    GNUNET_PQ_query_param_end
-  };
-
-  GNUNET_assert (denom_pub->age_mask.bits ==
-                 issue->age_mask.bits);
-  TALER_denom_pub_hash (denom_pub,
-                        &denom_hash);
-  GNUNET_assert (0 ==
-                 GNUNET_memcmp (&denom_hash,
-                                &issue->denom_hash));
-  GNUNET_assert (! GNUNET_TIME_absolute_is_zero (
-                   issue->start.abs_time));
-  GNUNET_assert (! GNUNET_TIME_absolute_is_zero (
-                   issue->expire_withdraw.abs_time));
-  GNUNET_assert (! GNUNET_TIME_absolute_is_zero (
-                   issue->expire_deposit.abs_time));
-  GNUNET_assert (! GNUNET_TIME_absolute_is_zero (
-                   issue->expire_legal.abs_time));
-  /* check fees match denomination currency */
-  GNUNET_assert (GNUNET_YES ==
-                 TALER_denom_fee_check_currency (
-                   issue->value.currency,
-                   &issue->fees));
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "denomination_insert",
-                                             params);
-}
-
 
 /**
  * Fetch information about a denomination key.
@@ -3343,7 +2839,7 @@ postgres_reserves_in_insert (void *cls,
     if (cs < 0)
       return cs;
     if (GNUNET_OK !=
-        postgres_start (pg,
+        TEH_PG_start (pg,
                         "reserve-update-serializable"))
     {
       GNUNET_break (0);
@@ -3424,8 +2920,7 @@ postgres_reserves_in_insert (void *cls,
     if (cs < 0)
       return cs;
     if (GNUNET_OK !=
-        postgres_start_read_committed (pg,
-                                       "reserve-insert-continued"))
+       TEH_PG_start_read_committed (pg, "reserve-insert-continued"))
     {
       GNUNET_break (0);
       return GNUNET_DB_STATUS_HARD_ERROR;
@@ -3534,60 +3029,6 @@ postgres_do_batch_withdraw (
 }
 
 
-/**
- * Perform insert as part of a batch withdraw operation, and persisting the
- * withdrawal details.
- *
- * @param cls the `struct PostgresClosure` with the plugin-specific state
- * @param nonce client-contributed input for CS denominations that must be 
checked for idempotency, or NULL for non-CS withdrawals
- * @param collectable corresponding collectable coin (blind signature)
- * @param now current time (rounded)
- * @param ruuid reserve UUID
- * @param[out] denom_unknown set if the denomination is unknown in the DB
- * @param[out] conflict if the envelope was already in the DB
- * @param[out] nonce_reuse if @a nonce was non-NULL and reused
- * @return query execution status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_do_batch_withdraw_insert (
-  void *cls,
-  const struct TALER_CsNonce *nonce,
-  const struct TALER_EXCHANGEDB_CollectableBlindcoin *collectable,
-  struct GNUNET_TIME_Timestamp now,
-  uint64_t ruuid,
-  bool *denom_unknown,
-  bool *conflict,
-  bool *nonce_reuse)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    NULL == nonce
-    ? GNUNET_PQ_query_param_null ()
-    : GNUNET_PQ_query_param_auto_from_type (nonce),
-    TALER_PQ_query_param_amount (&collectable->amount_with_fee),
-    GNUNET_PQ_query_param_auto_from_type (&collectable->denom_pub_hash),
-    GNUNET_PQ_query_param_uint64 (&ruuid),
-    GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_sig),
-    GNUNET_PQ_query_param_auto_from_type (&collectable->h_coin_envelope),
-    TALER_PQ_query_param_blinded_denom_sig (&collectable->sig),
-    GNUNET_PQ_query_param_timestamp (&now),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_bool ("denom_unknown",
-                                denom_unknown),
-    GNUNET_PQ_result_spec_bool ("conflict",
-                                conflict),
-    GNUNET_PQ_result_spec_bool ("nonce_reuse",
-                                nonce_reuse),
-    GNUNET_PQ_result_spec_end
-  };
-
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   
"call_batch_withdraw_insert",
-                                                   params,
-                                                   rs);
-}
 
 
 /**
@@ -6385,7 +5826,7 @@ postgres_start_deferred_wire_out (void *cls)
     TALER_LOG_ERROR (
       "Failed to defer wire_out_ref constraint on transaction\n");
     GNUNET_break (0);
-    postgres_rollback (pg);
+    TEH_PG_rollback (pg);
     return GNUNET_SYSERR;
   }
   pg->transaction_name = "deferred wire out";
@@ -8519,40 +7960,6 @@ postgres_insert_auditor (void *cls,
 }
 
 
-/**
- * Update information about an auditor that will audit this exchange.
- *
- * @param cls closure
- * @param auditor_pub key of the auditor (primary key for the existing record)
- * @param auditor_url base URL of the auditor's REST service, to be updated
- * @param auditor_name name of the auditor (for humans)
- * @param change_date date when the auditor status was last changed
- *                      (only to be used for replay detection)
- * @param enabled true to enable, false to disable
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_update_auditor (void *cls,
-                         const struct TALER_AuditorPublicKeyP *auditor_pub,
-                         const char *auditor_url,
-                         const char *auditor_name,
-                         struct GNUNET_TIME_Timestamp change_date,
-                         bool enabled)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (auditor_pub),
-    GNUNET_PQ_query_param_string (auditor_url),
-    GNUNET_PQ_query_param_string (auditor_name),
-    GNUNET_PQ_query_param_bool (enabled),
-    GNUNET_PQ_query_param_timestamp (&change_date),
-    GNUNET_PQ_query_param_end
-  };
-
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "update_auditor",
-                                             params);
-}
 
 
 /**
@@ -9027,36 +8434,6 @@ postgres_add_denomination_key (
 }
 
 
-/**
- * Add signing key.
- *
- * @param cls closure
- * @param exchange_pub the exchange online signing public key
- * @param meta meta data about @a exchange_pub
- * @param master_sig master signature to add
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_activate_signing_key (
-  void *cls,
-  const struct TALER_ExchangePublicKeyP *exchange_pub,
-  const struct TALER_EXCHANGEDB_SignkeyMetaData *meta,
-  const struct TALER_MasterSignatureP *master_sig)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam iparams[] = {
-    GNUNET_PQ_query_param_auto_from_type (exchange_pub),
-    GNUNET_PQ_query_param_timestamp (&meta->start),
-    GNUNET_PQ_query_param_timestamp (&meta->expire_sign),
-    GNUNET_PQ_query_param_timestamp (&meta->expire_legal),
-    GNUNET_PQ_query_param_auto_from_type (master_sig),
-    GNUNET_PQ_query_param_end
-  };
-
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "insert_signkey",
-                                             iparams);
-}
 
 
 /**
@@ -9160,333 +8537,55 @@ postgres_select_auditor_denom_sig (
 }
 
 
-/**
- * Closure for #wire_fee_by_time_helper()
- */
-struct WireFeeLookupContext
-{
-
-  /**
-   * Set to the wire fees. Set to invalid if fees conflict over
-   * the given time period.
-   */
-  struct TALER_WireFeeSet *fees;
-
-  /**
-   * Plugin context.
-   */
-  struct PostgresClosure *pg;
-};
 
 
 /**
- * Helper function for #postgres_lookup_wire_fee_by_time().
- * Calls the callback with the wire fee structure.
+ * Function called to grab a work shard on an operation @a op. Runs in its
+ * own transaction.
  *
- * @param cls a `struct WireFeeLookupContext`
- * @param result db results
- * @param num_results number of results in @a result
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param job_name name of the operation to grab a word shard for
+ * @param delay minimum age of a shard to grab
+ * @param shard_size desired shard size
+ * @param[out] start_row inclusive start row of the shard (returned)
+ * @param[out] end_row exclusive end row of the shard (returned)
+ * @return transaction status code
  */
-static void
-wire_fee_by_time_helper (void *cls,
-                         PGresult *result,
-                         unsigned int num_results)
+static enum GNUNET_DB_QueryStatus
+postgres_begin_shard (void *cls,
+                      const char *job_name,
+                      struct GNUNET_TIME_Relative delay,
+                      uint64_t shard_size,
+                      uint64_t *start_row,
+                      uint64_t *end_row)
 {
-  struct WireFeeLookupContext *wlc = cls;
-  struct PostgresClosure *pg = wlc->pg;
+  struct PostgresClosure *pg = cls;
 
-  for (unsigned int i = 0; i<num_results; i++)
+  for (unsigned int retries = 0; retries<10; retries++)
   {
-    struct TALER_WireFeeSet fs;
-    struct GNUNET_PQ_ResultSpec rs[] = {
-      TALER_PQ_RESULT_SPEC_AMOUNT ("wire_fee",
-                                   &fs.wire),
-      TALER_PQ_RESULT_SPEC_AMOUNT ("closing_fee",
-                                   &fs.closing),
-      GNUNET_PQ_result_spec_end
-    };
-
     if (GNUNET_OK !=
-        GNUNET_PQ_extract_result (result,
-                                  rs,
-                                  i))
+        TEH_PG_start (pg,
+                        "begin_shard"))
     {
       GNUNET_break (0);
-      /* invalidate */
-      memset (wlc->fees,
-              0,
-              sizeof (struct TALER_WireFeeSet));
-      return;
-    }
-    if (0 == i)
-    {
-      *wlc->fees = fs;
-      continue;
-    }
-    if (0 !=
-        TALER_wire_fee_set_cmp (&fs,
-                                wlc->fees))
-    {
-      /* invalidate */
-      memset (wlc->fees,
-              0,
-              sizeof (struct TALER_WireFeeSet));
-      return;
+      return GNUNET_DB_STATUS_HARD_ERROR;
     }
-  }
-}
 
-
-/**
- * Lookup information about known wire fees.  Finds all applicable
- * fees in the given range. If they are identical, returns the
- * respective @a fees. If any of the fees
- * differ between @a start_time and @a end_time, the transaction
- * succeeds BUT returns an invalid amount for both fees.
- *
- * @param cls closure
- * @param wire_method the wire method to lookup fees for
- * @param start_time starting time of fee
- * @param end_time end time of fee
- * @param[out] fees wire fees for that time period; if
- *             different fees exists within this time
- *             period, an 'invalid' amount is returned.
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_wire_fee_by_time (
-  void *cls,
-  const char *wire_method,
-  struct GNUNET_TIME_Timestamp start_time,
-  struct GNUNET_TIME_Timestamp end_time,
-  struct TALER_WireFeeSet *fees)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (wire_method),
-    GNUNET_PQ_query_param_timestamp (&start_time),
-    GNUNET_PQ_query_param_timestamp (&end_time),
-    GNUNET_PQ_query_param_end
-  };
-  struct WireFeeLookupContext wlc = {
-    .fees = fees,
-    .pg = pg
-  };
-
-  return GNUNET_PQ_eval_prepared_multi_select (pg->conn,
-                                               "lookup_wire_fee_by_time",
-                                               params,
-                                               &wire_fee_by_time_helper,
-                                               &wlc);
-}
-
-
-/**
- * Closure for #global_fee_by_time_helper()
- */
-struct GlobalFeeLookupContext
-{
-
-  /**
-   * Set to the wire fees. Set to invalid if fees conflict over
-   * the given time period.
-   */
-  struct TALER_GlobalFeeSet *fees;
-
-  /**
-   * Set to timeout of unmerged purses
-   */
-  struct GNUNET_TIME_Relative *purse_timeout;
-
-  /**
-   * Set to history expiration for reserves.
-   */
-  struct GNUNET_TIME_Relative *history_expiration;
-
-  /**
-   * Set to number of free purses per account.
-   */
-  uint32_t *purse_account_limit;
-
-  /**
-   * Plugin context.
-   */
-  struct PostgresClosure *pg;
-};
-
-
-/**
- * Helper function for #postgres_lookup_global_fee_by_time().
- * Calls the callback with each denomination key.
- *
- * @param cls a `struct GlobalFeeLookupContext`
- * @param result db results
- * @param num_results number of results in @a result
- */
-static void
-global_fee_by_time_helper (void *cls,
-                           PGresult *result,
-                           unsigned int num_results)
-{
-  struct GlobalFeeLookupContext *wlc = cls;
-  struct PostgresClosure *pg = wlc->pg;
-
-  for (unsigned int i = 0; i<num_results; i++)
-  {
-    struct TALER_GlobalFeeSet fs;
-    struct GNUNET_TIME_Relative purse_timeout;
-    struct GNUNET_TIME_Relative history_expiration;
-    uint32_t purse_account_limit;
-    struct GNUNET_PQ_ResultSpec rs[] = {
-      TALER_PQ_RESULT_SPEC_AMOUNT ("history_fee",
-                                   &fs.history),
-      TALER_PQ_RESULT_SPEC_AMOUNT ("account_fee",
-                                   &fs.account),
-      TALER_PQ_RESULT_SPEC_AMOUNT ("purse_fee",
-                                   &fs.purse),
-      GNUNET_PQ_result_spec_relative_time ("purse_timeout",
-                                           &purse_timeout),
-      GNUNET_PQ_result_spec_relative_time ("history_expiration",
-                                           &history_expiration),
-      GNUNET_PQ_result_spec_uint32 ("purse_account_limit",
-                                    &purse_account_limit),
-      GNUNET_PQ_result_spec_end
-    };
-
-    if (GNUNET_OK !=
-        GNUNET_PQ_extract_result (result,
-                                  rs,
-                                  i))
-    {
-      GNUNET_break (0);
-      /* invalidate */
-      memset (wlc->fees,
-              0,
-              sizeof (struct TALER_GlobalFeeSet));
-      return;
-    }
-    if (0 == i)
-    {
-      *wlc->fees = fs;
-      *wlc->purse_timeout = purse_timeout;
-      *wlc->history_expiration = history_expiration;
-      *wlc->purse_account_limit = purse_account_limit;
-      continue;
-    }
-    if ( (0 !=
-          TALER_global_fee_set_cmp (&fs,
-                                    wlc->fees)) ||
-         (purse_account_limit != *wlc->purse_account_limit) ||
-         (GNUNET_TIME_relative_cmp (purse_timeout,
-                                    !=,
-                                    *wlc->purse_timeout)) ||
-         (GNUNET_TIME_relative_cmp (history_expiration,
-                                    !=,
-                                    *wlc->history_expiration)) )
-    {
-      /* invalidate */
-      memset (wlc->fees,
-              0,
-              sizeof (struct TALER_GlobalFeeSet));
-      return;
-    }
-  }
-}
-
-
-/**
- * Lookup information about known global fees.
- *
- * @param cls closure
- * @param start_time starting time of fee
- * @param end_time end time of fee
- * @param[out] fees set to wire fees for that time period; if
- *             different global fee exists within this time
- *             period, an 'invalid' amount is returned.
- * @param[out] purse_timeout set to when unmerged purses expire
- * @param[out] history_expiration set to when we expire reserve histories
- * @param[out] purse_account_limit set to number of free purses
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_global_fee_by_time (
-  void *cls,
-  struct GNUNET_TIME_Timestamp start_time,
-  struct GNUNET_TIME_Timestamp end_time,
-  struct TALER_GlobalFeeSet *fees,
-  struct GNUNET_TIME_Relative *purse_timeout,
-  struct GNUNET_TIME_Relative *history_expiration,
-  uint32_t *purse_account_limit)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_timestamp (&start_time),
-    GNUNET_PQ_query_param_timestamp (&end_time),
-    GNUNET_PQ_query_param_end
-  };
-  struct GlobalFeeLookupContext wlc = {
-    .fees = fees,
-    .purse_timeout = purse_timeout,
-    .history_expiration = history_expiration,
-    .purse_account_limit = purse_account_limit,
-    .pg = pg
-  };
-
-  return GNUNET_PQ_eval_prepared_multi_select (pg->conn,
-                                               "lookup_global_fee_by_time",
-                                               params,
-                                               &global_fee_by_time_helper,
-                                               &wlc);
-}
-
-
-/**
- * Function called to grab a work shard on an operation @a op. Runs in its
- * own transaction.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param job_name name of the operation to grab a word shard for
- * @param delay minimum age of a shard to grab
- * @param shard_size desired shard size
- * @param[out] start_row inclusive start row of the shard (returned)
- * @param[out] end_row exclusive end row of the shard (returned)
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_begin_shard (void *cls,
-                      const char *job_name,
-                      struct GNUNET_TIME_Relative delay,
-                      uint64_t shard_size,
-                      uint64_t *start_row,
-                      uint64_t *end_row)
-{
-  struct PostgresClosure *pg = cls;
-
-  for (unsigned int retries = 0; retries<10; retries++)
-  {
-    if (GNUNET_OK !=
-        postgres_start (pg,
-                        "begin_shard"))
-    {
-      GNUNET_break (0);
-      return GNUNET_DB_STATUS_HARD_ERROR;
-    }
-
-    {
-      struct GNUNET_TIME_Absolute past;
-      enum GNUNET_DB_QueryStatus qs;
-      struct GNUNET_PQ_QueryParam params[] = {
-        GNUNET_PQ_query_param_string (job_name),
-        GNUNET_PQ_query_param_absolute_time (&past),
-        GNUNET_PQ_query_param_end
-      };
-      struct GNUNET_PQ_ResultSpec rs[] = {
-        GNUNET_PQ_result_spec_uint64 ("start_row",
-                                      start_row),
-        GNUNET_PQ_result_spec_uint64 ("end_row",
-                                      end_row),
-        GNUNET_PQ_result_spec_end
-      };
+    {
+      struct GNUNET_TIME_Absolute past;
+      enum GNUNET_DB_QueryStatus qs;
+      struct GNUNET_PQ_QueryParam params[] = {
+        GNUNET_PQ_query_param_string (job_name),
+        GNUNET_PQ_query_param_absolute_time (&past),
+        GNUNET_PQ_query_param_end
+      };
+      struct GNUNET_PQ_ResultSpec rs[] = {
+        GNUNET_PQ_result_spec_uint64 ("start_row",
+                                      start_row),
+        GNUNET_PQ_result_spec_uint64 ("end_row",
+                                      end_row),
+        GNUNET_PQ_result_spec_end
+      };
 
       past = GNUNET_TIME_absolute_get ();
       qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
@@ -9497,10 +8596,10 @@ postgres_begin_shard (void *cls,
       {
       case GNUNET_DB_STATUS_HARD_ERROR:
         GNUNET_break (0);
-        postgres_rollback (pg);
+        TEH_PG_rollback (pg);
         return qs;
       case GNUNET_DB_STATUS_SOFT_ERROR:
-        postgres_rollback (pg);
+        TEH_PG_rollback (pg);
         continue;
       case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
         {
@@ -9522,16 +8621,16 @@ postgres_begin_shard (void *cls,
           {
           case GNUNET_DB_STATUS_HARD_ERROR:
             GNUNET_break (0);
-            postgres_rollback (pg);
+            TEH_PG_rollback (pg);
             return qs;
           case GNUNET_DB_STATUS_SOFT_ERROR:
-            postgres_rollback (pg);
+            TEH_PG_rollback (pg);
             continue;
           case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
             goto commit;
           case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
             GNUNET_break (0); /* logic error, should be impossible */
-            postgres_rollback (pg);
+            TEH_PG_rollback (pg);
             return GNUNET_DB_STATUS_HARD_ERROR;
           }
         }
@@ -9562,10 +8661,10 @@ postgres_begin_shard (void *cls,
       {
       case GNUNET_DB_STATUS_HARD_ERROR:
         GNUNET_break (0);
-        postgres_rollback (pg);
+        TEH_PG_rollback (pg);
         return qs;
       case GNUNET_DB_STATUS_SOFT_ERROR:
-        postgres_rollback (pg);
+        TEH_PG_rollback (pg);
         continue;
       case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
         break;
@@ -9600,10 +8699,10 @@ postgres_begin_shard (void *cls,
       {
       case GNUNET_DB_STATUS_HARD_ERROR:
         GNUNET_break (0);
-        postgres_rollback (pg);
+        TEH_PG_rollback (pg);
         return qs;
       case GNUNET_DB_STATUS_SOFT_ERROR:
-        postgres_rollback (pg);
+        TEH_PG_rollback (pg);
         continue;
       case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
         /* continued below */
@@ -9611,7 +8710,7 @@ postgres_begin_shard (void *cls,
       case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
         /* someone else got this shard already,
            try again */
-        postgres_rollback (pg);
+        TEH_PG_rollback (pg);
         continue;
       }
     } /* claim_next_shard */
@@ -9626,10 +8725,10 @@ commit:
       {
       case GNUNET_DB_STATUS_HARD_ERROR:
         GNUNET_break (0);
-        postgres_rollback (pg);
+        TEH_PG_rollback (pg);
         return qs;
       case GNUNET_DB_STATUS_SOFT_ERROR:
-        postgres_rollback (pg);
+        TEH_PG_rollback (pg);
         continue;
       case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
       case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
@@ -9704,270 +8803,64 @@ postgres_complete_shard (void *cls,
 }
 
 
+
 /**
- * Function called to grab a revolving work shard on an operation @a op. Runs
- * in its own transaction. Returns the oldest inactive shard.
+ * Function called to release a revolving shard
+ * back into the work pool.  Clears the
+ * "completed" flag.
  *
  * @param cls the @e cls of this struct with the plugin-specific state
- * @param job_name name of the operation to grab a revolving shard for
- * @param shard_size desired shard size
- * @param shard_limit exclusive end of the shard range
- * @param[out] start_row inclusive start row of the shard (returned)
- * @param[out] end_row inclusive end row of the shard (returned)
+ * @param job_name name of the operation to grab a word shard for
+ * @param start_row inclusive start row of the shard
+ * @param end_row exclusive end row of the shard
  * @return transaction status code
  */
-static enum GNUNET_DB_QueryStatus
-postgres_begin_revolving_shard (void *cls,
-                                const char *job_name,
-                                uint32_t shard_size,
-                                uint32_t shard_limit,
-                                uint32_t *start_row,
-                                uint32_t *end_row)
+enum GNUNET_DB_QueryStatus
+postgres_release_revolving_shard (void *cls,
+                                  const char *job_name,
+                                  uint32_t start_row,
+                                  uint32_t end_row)
 {
   struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (job_name),
+    GNUNET_PQ_query_param_uint32 (&start_row),
+    GNUNET_PQ_query_param_uint32 (&end_row),
+    GNUNET_PQ_query_param_end
+  };
 
-  GNUNET_assert (shard_limit <= 1U + (uint32_t) INT_MAX);
-  GNUNET_assert (shard_limit > 0);
-  GNUNET_assert (shard_size > 0);
-  for (unsigned int retries = 0; retries<3; retries++)
-  {
-    if (GNUNET_OK !=
-        postgres_start (pg,
-                        "begin_revolving_shard"))
-    {
-      GNUNET_break (0);
-      return GNUNET_DB_STATUS_HARD_ERROR;
-    }
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Releasing revolving shard %s %u-%u\n",
+              job_name,
+              (unsigned int) start_row,
+              (unsigned int) end_row);
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "release_revolving_shard",
+                                             params);
+}
 
-    /* First, find last 'end_row' */
-    {
-      enum GNUNET_DB_QueryStatus qs;
-      uint32_t last_end;
-      struct GNUNET_PQ_QueryParam params[] = {
-        GNUNET_PQ_query_param_string (job_name),
-        GNUNET_PQ_query_param_end
-      };
-      struct GNUNET_PQ_ResultSpec rs[] = {
-        GNUNET_PQ_result_spec_uint32 ("end_row",
-                                      &last_end),
-        GNUNET_PQ_result_spec_end
-      };
 
-      qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                     
"get_last_revolving_shard",
-                                                     params,
-                                                     rs);
-      switch (qs)
-      {
-      case GNUNET_DB_STATUS_HARD_ERROR:
-        GNUNET_break (0);
-        postgres_rollback (pg);
-        return qs;
-      case GNUNET_DB_STATUS_SOFT_ERROR:
-        postgres_rollback (pg);
-        continue;
-      case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
-        *start_row = 1U + last_end;
-        break;
-      case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
-        *start_row = 0; /* base-case: no shards yet */
-        break; /* continued below */
-      }
-    } /* get_last_shard */
+/**
+ * Function called to delete all revolving shards.
+ * To be used after a crash or when the shard size is
+ * changed.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @return transaction status code
+ */
+enum GNUNET_GenericReturnValue
+postgres_delete_shard_locks (void *cls)
+{
+  struct PostgresClosure *pg = cls;
+  struct GNUNET_PQ_ExecuteStatement es[] = {
+    GNUNET_PQ_make_execute ("DELETE FROM work_shards;"),
+    GNUNET_PQ_make_execute ("DELETE FROM revolving_work_shards;"),
+    GNUNET_PQ_EXECUTE_STATEMENT_END
+  };
 
-    if (*start_row < shard_limit)
-    {
-      /* Claim fresh shard */
-      enum GNUNET_DB_QueryStatus qs;
-      struct GNUNET_TIME_Absolute now;
-      struct GNUNET_PQ_QueryParam params[] = {
-        GNUNET_PQ_query_param_string (job_name),
-        GNUNET_PQ_query_param_absolute_time (&now),
-        GNUNET_PQ_query_param_uint32 (start_row),
-        GNUNET_PQ_query_param_uint32 (end_row),
-        GNUNET_PQ_query_param_end
-      };
-
-      *end_row = GNUNET_MIN (shard_limit,
-                             *start_row + shard_size - 1);
-      now = GNUNET_TIME_absolute_get ();
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  "Trying to claim shard %llu-%llu\n",
-                  (unsigned long long) *start_row,
-                  (unsigned long long) *end_row);
-      qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                               "create_revolving_shard",
-                                               params);
-      switch (qs)
-      {
-      case GNUNET_DB_STATUS_HARD_ERROR:
-        GNUNET_break (0);
-        postgres_rollback (pg);
-        return qs;
-      case GNUNET_DB_STATUS_SOFT_ERROR:
-        postgres_rollback (pg);
-        continue;
-      case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
-        /* continued below (with commit) */
-        break;
-      case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
-        /* someone else got this shard already,
-           try again */
-        postgres_rollback (pg);
-        continue;
-      }
-    } /* end create fresh reovlving shard */
-    else
-    {
-      /* claim oldest existing shard */
-      enum GNUNET_DB_QueryStatus qs;
-      struct GNUNET_PQ_QueryParam params[] = {
-        GNUNET_PQ_query_param_string (job_name),
-        GNUNET_PQ_query_param_end
-      };
-      struct GNUNET_PQ_ResultSpec rs[] = {
-        GNUNET_PQ_result_spec_uint32 ("start_row",
-                                      start_row),
-        GNUNET_PQ_result_spec_uint32 ("end_row",
-                                      end_row),
-        GNUNET_PQ_result_spec_end
-      };
-
-      qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                     
"get_open_revolving_shard",
-                                                     params,
-                                                     rs);
-      switch (qs)
-      {
-      case GNUNET_DB_STATUS_HARD_ERROR:
-        GNUNET_break (0);
-        postgres_rollback (pg);
-        return qs;
-      case GNUNET_DB_STATUS_SOFT_ERROR:
-        postgres_rollback (pg);
-        continue;
-      case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
-        /* no open shards available */
-        postgres_rollback (pg);
-        return qs;
-      case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
-        {
-          enum GNUNET_DB_QueryStatus qs;
-          struct GNUNET_TIME_Timestamp now;
-          struct GNUNET_PQ_QueryParam params[] = {
-            GNUNET_PQ_query_param_string (job_name),
-            GNUNET_PQ_query_param_timestamp (&now),
-            GNUNET_PQ_query_param_uint32 (start_row),
-            GNUNET_PQ_query_param_uint32 (end_row),
-            GNUNET_PQ_query_param_end
-          };
-
-          now = GNUNET_TIME_timestamp_get ();
-          qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                                   "reclaim_revolving_shard",
-                                                   params);
-          switch (qs)
-          {
-          case GNUNET_DB_STATUS_HARD_ERROR:
-            GNUNET_break (0);
-            postgres_rollback (pg);
-            return qs;
-          case GNUNET_DB_STATUS_SOFT_ERROR:
-            postgres_rollback (pg);
-            continue;
-          case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
-            break; /* continue with commit */
-          case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
-            GNUNET_break (0); /* logic error, should be impossible */
-            postgres_rollback (pg);
-            return GNUNET_DB_STATUS_HARD_ERROR;
-          }
-        }
-        break; /* continue with commit */
-      }
-    } /* end claim oldest existing shard */
-
-    /* commit */
-    {
-      enum GNUNET_DB_QueryStatus qs;
-
-      qs = TEH_PG_commit (pg);
-      switch (qs)
-      {
-      case GNUNET_DB_STATUS_HARD_ERROR:
-        GNUNET_break (0);
-        postgres_rollback (pg);
-        return qs;
-      case GNUNET_DB_STATUS_SOFT_ERROR:
-        postgres_rollback (pg);
-        continue;
-      case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
-      case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
-        return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
-      }
-    }
-  } /* retry 'for' loop */
-  return GNUNET_DB_STATUS_SOFT_ERROR;
-}
-
-
-/**
- * Function called to release a revolving shard
- * back into the work pool.  Clears the
- * "completed" flag.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param job_name name of the operation to grab a word shard for
- * @param start_row inclusive start row of the shard
- * @param end_row exclusive end row of the shard
- * @return transaction status code
- */
-enum GNUNET_DB_QueryStatus
-postgres_release_revolving_shard (void *cls,
-                                  const char *job_name,
-                                  uint32_t start_row,
-                                  uint32_t end_row)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (job_name),
-    GNUNET_PQ_query_param_uint32 (&start_row),
-    GNUNET_PQ_query_param_uint32 (&end_row),
-    GNUNET_PQ_query_param_end
-  };
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Releasing revolving shard %s %u-%u\n",
-              job_name,
-              (unsigned int) start_row,
-              (unsigned int) end_row);
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "release_revolving_shard",
-                                             params);
-}
-
-
-/**
- * Function called to delete all revolving shards.
- * To be used after a crash or when the shard size is
- * changed.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @return transaction status code
- */
-enum GNUNET_GenericReturnValue
-postgres_delete_shard_locks (void *cls)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_ExecuteStatement es[] = {
-    GNUNET_PQ_make_execute ("DELETE FROM work_shards;"),
-    GNUNET_PQ_make_execute ("DELETE FROM revolving_work_shards;"),
-    GNUNET_PQ_EXECUTE_STATEMENT_END
-  };
-
-  return GNUNET_PQ_exec_statements (pg->conn,
-                                    es);
-}
+  return GNUNET_PQ_exec_statements (pg->conn,
+                                    es);
+}
 
 
 /**
@@ -10002,40 +8895,6 @@ postgres_set_extension_manifest (void *cls,
 }
 
 
-/**
- * Function called to get the manifest of an extension
- * (age-restriction, policy_extension_...)
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param extension_name the name of the extension
- * @param[out] manifest JSON object of the manifest as string
- * @return transaction status code
- */
-enum GNUNET_DB_QueryStatus
-postgres_get_extension_manifest (void *cls,
-                                 const char *extension_name,
-                                 char **manifest)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (extension_name),
-    GNUNET_PQ_query_param_end
-  };
-  bool is_null;
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_allow_null (
-      GNUNET_PQ_result_spec_string ("manifest",
-                                    manifest),
-      &is_null),
-    GNUNET_PQ_result_spec_end
-  };
-
-  *manifest = NULL;
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   "get_extension_manifest",
-                                                   params,
-                                                   rs);
-}
 
 
 /**
@@ -10077,1454 +8936,162 @@ postgres_insert_partner (void *cls,
   return GNUNET_PQ_eval_prepared_non_select (pg->conn,
                                              "insert_partner",
                                              params);
-}
-
-
-/**
- * Function called to retrieve an encrypted contract.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param purse_pub key to lookup the contract by
- * @param[out] pub_ckey set to the ephemeral DH used to encrypt the contract
- * @param[out] econtract_sig set to the signature over the encrypted contract
- * @param[out] econtract_size set to the number of bytes in @a econtract
- * @param[out] econtract set to the encrypted contract on success, to be freed 
by the caller
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_select_contract (void *cls,
-                          const struct TALER_ContractDiffiePublicP *pub_ckey,
-                          struct TALER_PurseContractPublicKeyP *purse_pub,
-                          struct TALER_PurseContractSignatureP *econtract_sig,
-                          size_t *econtract_size,
-                          void **econtract)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (pub_ckey),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_auto_from_type ("purse_pub",
-                                          purse_pub),
-    GNUNET_PQ_result_spec_auto_from_type ("contract_sig",
-                                          econtract_sig),
-    GNUNET_PQ_result_spec_variable_size ("e_contract",
-                                         econtract,
-                                         econtract_size),
-    GNUNET_PQ_result_spec_end
-  };
-
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   "select_contract",
-                                                   params,
-                                                   rs);
-
-}
-
-
-/**
- * Function called to retrieve an encrypted contract.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param purse_pub key to lookup the contract by
- * @param[out] econtract set to the encrypted contract on success, to be freed 
by the caller
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_select_contract_by_purse (
-  void *cls,
-  const struct TALER_PurseContractPublicKeyP *purse_pub,
-  struct TALER_EncryptedContract *econtract)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (purse_pub),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_auto_from_type ("pub_ckey",
-                                          &econtract->contract_pub),
-    GNUNET_PQ_result_spec_auto_from_type ("contract_sig",
-                                          &econtract->econtract_sig),
-    GNUNET_PQ_result_spec_variable_size ("e_contract",
-                                         &econtract->econtract,
-                                         &econtract->econtract_size),
-    GNUNET_PQ_result_spec_end
-  };
-
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   "select_contract_by_purse",
-                                                   params,
-                                                   rs);
-
-}
-
-
-/**
- * Function called to persist an encrypted contract associated with a reserve.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param purse_pub the purse the contract is associated with (must exist)
- * @param econtract the encrypted contract
- * @param[out] in_conflict set to true if @a econtract
- *             conflicts with an existing contract;
- *             in this case, the return value will be
- *             #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT despite the failure
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_contract (
-  void *cls,
-  const struct TALER_PurseContractPublicKeyP *purse_pub,
-  const struct TALER_EncryptedContract *econtract,
-  bool *in_conflict)
-{
-  struct PostgresClosure *pg = cls;
-  enum GNUNET_DB_QueryStatus qs;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (purse_pub),
-    GNUNET_PQ_query_param_auto_from_type (&econtract->contract_pub),
-    GNUNET_PQ_query_param_fixed_size (econtract->econtract,
-                                      econtract->econtract_size),
-    GNUNET_PQ_query_param_auto_from_type (&econtract->econtract_sig),
-    GNUNET_PQ_query_param_end
-  };
-
-  *in_conflict = false;
-  qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                           "insert_contract",
-                                           params);
-  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs)
-    return qs;
-  {
-    struct TALER_EncryptedContract econtract2;
-
-    qs = postgres_select_contract_by_purse (pg,
-                                            purse_pub,
-                                            &econtract2);
-    if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
-    {
-      GNUNET_break (0);
-      return GNUNET_DB_STATUS_HARD_ERROR;
-    }
-    if ( (0 == GNUNET_memcmp (&econtract->contract_pub,
-                              &econtract2.contract_pub)) &&
-         (econtract2.econtract_size ==
-          econtract->econtract_size) &&
-         (0 == memcmp (econtract2.econtract,
-                       econtract->econtract,
-                       econtract->econtract_size)) )
-    {
-      GNUNET_free (econtract2.econtract);
-      return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
-    }
-    GNUNET_free (econtract2.econtract);
-    *in_conflict = true;
-    return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
-  }
-}
-
-
-
-
-/**
- * Function called to clean up one expired purse.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param start_time select purse expired after this time
- * @param end_time select purse expired before this time
- * @return transaction status code (#GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if no 
purse expired in the given time interval).
- */
-static enum GNUNET_DB_QueryStatus
-postgres_expire_purse (
-  void *cls,
-  struct GNUNET_TIME_Absolute start_time,
-  struct GNUNET_TIME_Absolute end_time)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_absolute_time (&start_time),
-    GNUNET_PQ_query_param_absolute_time (&end_time),
-    GNUNET_PQ_query_param_absolute_time (&now),
-    GNUNET_PQ_query_param_end
-  };
-  bool found = false;
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_bool ("found",
-                                &found),
-    GNUNET_PQ_result_spec_end
-  };
-  enum GNUNET_DB_QueryStatus qs;
-
-  qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                 "call_expire_purse",
-                                                 params,
-                                                 rs);
-  if (qs < 0)
-    return qs;
-  GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
-  return found
-         ? GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
-         : GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
-}
-
-
-/**
- * Function called to return meta data about a purse by the
- * merge capability key.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param merge_pub public key representing the merge capability
- * @param[out] purse_pub public key of the purse
- * @param[out] purse_expiration when would an unmerged purse expire
- * @param[out] h_contract_terms contract associated with the purse
- * @param[out] age_limit the age limit for deposits into the purse
- * @param[out] target_amount amount to be put into the purse
- * @param[out] balance amount put so far into the purse
- * @param[out] purse_sig signature of the purse over the initialization data
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_select_purse_by_merge_pub (
-  void *cls,
-  const struct TALER_PurseMergePublicKeyP *merge_pub,
-  struct TALER_PurseContractPublicKeyP *purse_pub,
-  struct GNUNET_TIME_Timestamp *purse_expiration,
-  struct TALER_PrivateContractHashP *h_contract_terms,
-  uint32_t *age_limit,
-  struct TALER_Amount *target_amount,
-  struct TALER_Amount *balance,
-  struct TALER_PurseContractSignatureP *purse_sig)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (merge_pub),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_auto_from_type ("purse_pub",
-                                          purse_pub),
-    GNUNET_PQ_result_spec_timestamp ("purse_expiration",
-                                     purse_expiration),
-    GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
-                                          h_contract_terms),
-    GNUNET_PQ_result_spec_uint32 ("age_limit",
-                                  age_limit),
-    TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
-                                 target_amount),
-    TALER_PQ_RESULT_SPEC_AMOUNT ("balance",
-                                 balance),
-    GNUNET_PQ_result_spec_auto_from_type ("purse_sig",
-                                          purse_sig),
-    GNUNET_PQ_result_spec_end
-  };
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   "select_purse_by_merge_pub",
-                                                   params,
-                                                   rs);
-}
-
-
-/**
- * Function called to execute a transaction crediting
- * a purse with @a amount from @a coin_pub. Reduces the
- * value of @a coin_pub and increase the balance of
- * the @a purse_pub purse. If the balance reaches the
- * target amount and the purse has been merged, triggers
- * the updates of the reserve/account balance.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param purse_pub purse to credit
- * @param coin_pub coin to deposit (debit)
- * @param amount fraction of the coin's value to deposit
- * @param coin_sig signature affirming the operation
- * @param amount_minus_fee amount to add to the purse
- * @param[out] balance_ok set to false if the coin's
- *        remaining balance is below @a amount;
- *             in this case, the return value will be
- *             #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT despite the failure
- * @param[out] conflict set to true if the deposit failed due to a conflict 
(coin already spent,
- *             or deposited into this purse with a different amount)
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_do_purse_deposit (
-  void *cls,
-  const struct TALER_PurseContractPublicKeyP *purse_pub,
-  const struct TALER_CoinSpendPublicKeyP *coin_pub,
-  const struct TALER_Amount *amount,
-  const struct TALER_CoinSpendSignatureP *coin_sig,
-  const struct TALER_Amount *amount_minus_fee,
-  bool *balance_ok,
-  bool *conflict)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
-  struct GNUNET_TIME_Timestamp reserve_expiration;
-  uint64_t partner_id = 0; /* FIXME #7271: WAD support... */
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_uint64 (&partner_id),
-    GNUNET_PQ_query_param_auto_from_type (purse_pub),
-    TALER_PQ_query_param_amount (amount),
-    GNUNET_PQ_query_param_auto_from_type (coin_pub),
-    GNUNET_PQ_query_param_auto_from_type (coin_sig),
-    TALER_PQ_query_param_amount (amount_minus_fee),
-    GNUNET_PQ_query_param_timestamp (&reserve_expiration),
-    GNUNET_PQ_query_param_timestamp (&now),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_bool ("balance_ok",
-                                balance_ok),
-    GNUNET_PQ_result_spec_bool ("conflict",
-                                conflict),
-    GNUNET_PQ_result_spec_end
-  };
-
-  reserve_expiration
-    = GNUNET_TIME_absolute_to_timestamp (
-        GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
-                                  pg->legal_reserve_expiration_time));
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   "call_purse_deposit",
-                                                   params,
-                                                   rs);
-}
-
-
-/**
- * Set the current @a balance in the purse
- * identified by @a purse_pub. Used by the auditor
- * to update the balance as calculated by the auditor.
- *
- * @param cls closure
- * @param purse_pub public key of a purse
- * @param balance new balance to store under the purse
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_set_purse_balance (
-  void *cls,
-  const struct TALER_PurseContractPublicKeyP *purse_pub,
-  const struct TALER_Amount *balance)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (purse_pub),
-    TALER_PQ_query_param_amount (balance),
-    GNUNET_PQ_query_param_end
-  };
-
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "set_purse_balance",
-                                             params);
-}
-
-
-/**
- * Function called to obtain a coin deposit data from
- * depositing the coin into a purse.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param purse_pub purse to credit
- * @param coin_pub coin to deposit (debit)
- * @param[out] amount set fraction of the coin's value that was deposited 
(with fee)
- * @param[out] h_denom_pub set to hash of denomination of the coin
- * @param[out] phac set to hash of age restriction on the coin
- * @param[out] coin_sig set to signature affirming the operation
- * @param[out] partner_url set to the URL of the partner exchange, or NULL for 
ourselves, must be freed by caller
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_get_purse_deposit (
-  void *cls,
-  const struct TALER_PurseContractPublicKeyP *purse_pub,
-  const struct TALER_CoinSpendPublicKeyP *coin_pub,
-  struct TALER_Amount *amount,
-  struct TALER_DenominationHashP *h_denom_pub,
-  struct TALER_AgeCommitmentHash *phac,
-  struct TALER_CoinSpendSignatureP *coin_sig,
-  char **partner_url)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (purse_pub),
-    GNUNET_PQ_query_param_auto_from_type (coin_pub),
-    GNUNET_PQ_query_param_end
-  };
-  bool is_null;
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
-                                          h_denom_pub),
-    GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",
-                                          phac),
-    GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
-                                          coin_sig),
-    TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
-                                 amount),
-    GNUNET_PQ_result_spec_allow_null (
-      GNUNET_PQ_result_spec_string ("partner_base_url",
-                                    partner_url),
-      &is_null),
-    GNUNET_PQ_result_spec_end
-  };
-
-  *partner_url = NULL;
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   
"select_purse_deposit_by_coin_pub",
-                                                   params,
-                                                   rs);
-}
-
-
-/**
- * Function called to approve merging a purse into a
- * reserve by the respective purse merge key.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param purse_pub purse to merge
- * @param merge_sig signature affirming the merge
- * @param merge_timestamp time of the merge
- * @param reserve_sig signature of the reserve affirming the merge
- * @param partner_url URL of the partner exchange, can be NULL if the reserves 
lives with us
- * @param reserve_pub public key of the reserve to credit
- * @param[out] no_partner set to true if @a partner_url is unknown
- * @param[out] no_balance set to true if the @a purse_pub is not paid up yet
- * @param[out] in_conflict set to true if @a purse_pub was merged into a 
different reserve already
-  * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_do_purse_merge (
-  void *cls,
-  const struct TALER_PurseContractPublicKeyP *purse_pub,
-  const struct TALER_PurseMergeSignatureP *merge_sig,
-  const struct GNUNET_TIME_Timestamp merge_timestamp,
-  const struct TALER_ReserveSignatureP *reserve_sig,
-  const char *partner_url,
-  const struct TALER_ReservePublicKeyP *reserve_pub,
-  bool *no_partner,
-  bool *no_balance,
-  bool *in_conflict)
-{
-  struct PostgresClosure *pg = cls;
-  struct TALER_PaytoHashP h_payto;
-  struct GNUNET_TIME_Timestamp expiration
-    = GNUNET_TIME_relative_to_timestamp (pg->legal_reserve_expiration_time);
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (purse_pub),
-    GNUNET_PQ_query_param_auto_from_type (merge_sig),
-    GNUNET_PQ_query_param_timestamp (&merge_timestamp),
-    GNUNET_PQ_query_param_auto_from_type (reserve_sig),
-    (NULL == partner_url)
-    ? GNUNET_PQ_query_param_null ()
-    : GNUNET_PQ_query_param_string (partner_url),
-    GNUNET_PQ_query_param_auto_from_type (reserve_pub),
-    GNUNET_PQ_query_param_auto_from_type (&h_payto),
-    GNUNET_PQ_query_param_timestamp (&expiration),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_bool ("no_partner",
-                                no_partner),
-    GNUNET_PQ_result_spec_bool ("no_balance",
-                                no_balance),
-    GNUNET_PQ_result_spec_bool ("conflict",
-                                in_conflict),
-    GNUNET_PQ_result_spec_end
-  };
-
-  {
-    char *payto_uri;
-
-    payto_uri = TALER_reserve_make_payto (pg->exchange_url,
-                                          reserve_pub);
-    TALER_payto_hash (payto_uri,
-                      &h_payto);
-    GNUNET_free (payto_uri);
-  }
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   "call_purse_merge",
-                                                   params,
-                                                   rs);
-}
-
-
-/**
- * Function called insert request to merge a purse into a reserve by the
- * respective purse merge key. The purse must not have been merged into a
- * different reserve.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param purse_pub purse to merge
- * @param merge_sig signature affirming the merge
- * @param merge_timestamp time of the merge
- * @param reserve_sig signature of the reserve affirming the merge
- * @param purse_fee amount to charge the reserve for the purse creation, NULL 
to use the quota
- * @param reserve_pub public key of the reserve to credit
- * @param[out] in_conflict set to true if @a purse_pub was merged into a 
different reserve already
- * @param[out] no_reserve set to true if @a reserve_pub is not a known reserve
- * @param[out] insufficient_funds set to true if @a reserve_pub has 
insufficient capacity to create another purse
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_do_reserve_purse (
-  void *cls,
-  const struct TALER_PurseContractPublicKeyP *purse_pub,
-  const struct TALER_PurseMergeSignatureP *merge_sig,
-  const struct GNUNET_TIME_Timestamp merge_timestamp,
-  const struct TALER_ReserveSignatureP *reserve_sig,
-  const struct TALER_Amount *purse_fee,
-  const struct TALER_ReservePublicKeyP *reserve_pub,
-  bool *in_conflict,
-  bool *no_reserve,
-  bool *insufficient_funds)
-{
-  struct PostgresClosure *pg = cls;
-  struct TALER_Amount zero_fee;
-  struct TALER_PaytoHashP h_payto;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (purse_pub),
-    GNUNET_PQ_query_param_auto_from_type (merge_sig),
-    GNUNET_PQ_query_param_timestamp (&merge_timestamp),
-    GNUNET_PQ_query_param_auto_from_type (reserve_sig),
-    GNUNET_PQ_query_param_bool (NULL == purse_fee),
-    TALER_PQ_query_param_amount (NULL == purse_fee
-                                 ? &zero_fee
-                                 : purse_fee),
-    GNUNET_PQ_query_param_auto_from_type (reserve_pub),
-    GNUNET_PQ_query_param_auto_from_type (&h_payto),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_bool ("insufficient_funds",
-                                insufficient_funds),
-    GNUNET_PQ_result_spec_bool ("conflict",
-                                in_conflict),
-    GNUNET_PQ_result_spec_bool ("no_reserve",
-                                no_reserve),
-    GNUNET_PQ_result_spec_end
-  };
-
-  {
-    char *payto_uri;
-
-    payto_uri = TALER_reserve_make_payto (pg->exchange_url,
-                                          reserve_pub);
-    TALER_payto_hash (payto_uri,
-                      &h_payto);
-    GNUNET_free (payto_uri);
-  }
-  GNUNET_assert (GNUNET_OK ==
-                 TALER_amount_set_zero (pg->currency,
-                                        &zero_fee));
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   "call_reserve_purse",
-                                                   params,
-                                                   rs);
-}
-
-
-/**
- * Function called to approve merging of a purse with
- * an account, made by the receiving account.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param purse_pub public key of the purse
- * @param[out] merge_sig set to the signature confirming the merge
- * @param[out] merge_timestamp set to the time of the merge
- * @param[out] partner_url set to the URL of the target exchange, or NULL if 
the target exchange is us. To be freed by the caller.
- * @param[out] reserve_pub set to the public key of the reserve/account being 
credited
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_select_purse_merge (
-  void *cls,
-  const struct TALER_PurseContractPublicKeyP *purse_pub,
-  struct TALER_PurseMergeSignatureP *merge_sig,
-  struct GNUNET_TIME_Timestamp *merge_timestamp,
-  char **partner_url,
-  struct TALER_ReservePublicKeyP *reserve_pub)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (purse_pub),
-    GNUNET_PQ_query_param_end
-  };
-  bool is_null;
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_auto_from_type ("merge_sig",
-                                          merge_sig),
-    GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
-                                          reserve_pub),
-    GNUNET_PQ_result_spec_timestamp ("merge_timestamp",
-                                     merge_timestamp),
-    GNUNET_PQ_result_spec_allow_null (
-      GNUNET_PQ_result_spec_string ("partner_base_url",
-                                    partner_url),
-      &is_null),
-    GNUNET_PQ_result_spec_end
-  };
-
-  *partner_url = NULL;
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   "select_purse_merge",
-                                                   params,
-                                                   rs);
-}
-
-
-/**
- * Function called to persist a signature that
- * prove that the client requested an
- * account history.  Debits the @a history_fee from
- * the reserve (if possible).
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param reserve_pub account that the history was requested for
- * @param reserve_sig signature affirming the request
- * @param request_timestamp when was the request made
- * @param history_fee how much should the @a reserve_pub be charged for the 
request
- * @param[out] balance_ok set to TRUE if the reserve balance
- *         was sufficient
- * @param[out] idempotent set to TRUE if the request is already in the DB
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_history_request (
-  void *cls,
-  const struct TALER_ReservePublicKeyP *reserve_pub,
-  const struct TALER_ReserveSignatureP *reserve_sig,
-  struct GNUNET_TIME_Timestamp request_timestamp,
-  const struct TALER_Amount *history_fee,
-  bool *balance_ok,
-  bool *idempotent)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (reserve_pub),
-    GNUNET_PQ_query_param_auto_from_type (reserve_sig),
-    GNUNET_PQ_query_param_timestamp (&request_timestamp),
-    TALER_PQ_query_param_amount (history_fee),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_bool ("balance_ok",
-                                balance_ok),
-    GNUNET_PQ_result_spec_bool ("idempotent",
-                                idempotent),
-    GNUNET_PQ_result_spec_end
-  };
-
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   "call_history_request",
-                                                   params,
-                                                   rs);
-}
-
-
-/**
- * Function called to persist a request to drain profits.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param wtid wire transfer ID to use
- * @param account_section account to drain
- * @param payto_uri account to wire funds to
- * @param request_timestamp when was the request made
- * @param amount amount to wire
- * @param master_sig signature affirming the operation
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_drain_profit (
-  void *cls,
-  const struct TALER_WireTransferIdentifierRawP *wtid,
-  const char *account_section,
-  const char *payto_uri,
-  struct GNUNET_TIME_Timestamp request_timestamp,
-  const struct TALER_Amount *amount,
-  const struct TALER_MasterSignatureP *master_sig)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (wtid),
-    GNUNET_PQ_query_param_string (account_section),
-    GNUNET_PQ_query_param_string (payto_uri),
-    GNUNET_PQ_query_param_timestamp (&request_timestamp),
-    TALER_PQ_query_param_amount (amount),
-    GNUNET_PQ_query_param_auto_from_type (master_sig),
-    GNUNET_PQ_query_param_end
-  };
-
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "drain_profit_insert",
-                                             params);
-}
-
-
-/**
- * Get profit drain operation ready to execute.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param[out] serial set to serial ID of the entry
- * @param[out] wtid set set to wire transfer ID to use
- * @param[out] account_section set to  account to drain
- * @param[out] payto_uri set to account to wire funds to
- * @param[out] request_timestamp set to time of the signature
- * @param[out] amount set to amount to wire
- * @param[out] master_sig set to signature affirming the operation
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_profit_drains_get_pending (
-  void *cls,
-  uint64_t *serial,
-  struct TALER_WireTransferIdentifierRawP *wtid,
-  char **account_section,
-  char **payto_uri,
-  struct GNUNET_TIME_Timestamp *request_timestamp,
-  struct TALER_Amount *amount,
-  struct TALER_MasterSignatureP *master_sig)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_uint64 ("profit_drain_serial_id",
-                                  serial),
-    GNUNET_PQ_result_spec_auto_from_type ("wtid",
-                                          wtid),
-    GNUNET_PQ_result_spec_string ("account_section",
-                                  account_section),
-    GNUNET_PQ_result_spec_string ("payto_uri",
-                                  payto_uri),
-    GNUNET_PQ_result_spec_timestamp ("trigger_date",
-                                     request_timestamp),
-    TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
-                                 amount),
-    GNUNET_PQ_result_spec_auto_from_type ("master_sig",
-                                          master_sig),
-    GNUNET_PQ_result_spec_end
-  };
-
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   "get_ready_profit_drain",
-                                                   params,
-                                                   rs);
-}
-
-
-/**
- * Function called to get information about a profit drain event.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param wtid wire transfer ID to look up drain event for
- * @param[out] serial set to serial ID of the entry
- * @param[out] account_section set to account to drain
- * @param[out] payto_uri set to account to wire funds to
- * @param[out] request_timestamp set to time of the signature
- * @param[out] amount set to amount to wire
- * @param[out] master_sig set to signature affirming the operation
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_get_drain_profit (
-  void *cls,
-  const struct TALER_WireTransferIdentifierRawP *wtid,
-  uint64_t *serial,
-  char **account_section,
-  char **payto_uri,
-  struct GNUNET_TIME_Timestamp *request_timestamp,
-  struct TALER_Amount *amount,
-  struct TALER_MasterSignatureP *master_sig)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (wtid),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_uint64 ("profit_drain_serial_id",
-                                  serial),
-    GNUNET_PQ_result_spec_string ("account_section",
-                                  account_section),
-    GNUNET_PQ_result_spec_string ("payto_uri",
-                                  payto_uri),
-    GNUNET_PQ_result_spec_timestamp ("trigger_date",
-                                     request_timestamp),
-    TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
-                                 amount),
-    GNUNET_PQ_result_spec_auto_from_type ("master_sig",
-                                          master_sig),
-    GNUNET_PQ_result_spec_end
-  };
-
-  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                   "get_profit_drain",
-                                                   params,
-                                                   rs);
-}
-
-
-/**
- * Set profit drain operation to finished.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param serial serial ID of the entry to mark finished
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_profit_drains_set_finished (
-  void *cls,
-  uint64_t serial)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_uint64 (&serial),
-    GNUNET_PQ_query_param_end
-  };
-
-  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
-                                             "drain_profit_set_finished",
-                                             params);
-}
-
-
-/**
- * Insert KYC requirement for @a h_payto account into table.
- *
- * @param cls closure
- * @param provider_section provider that must be checked
- * @param h_payto account that must be KYC'ed
- * @param[out] requirement_row set to legitimization requirement row for this 
check
- * @return database transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_kyc_requirement_for_account (
-  void *cls,
-  const char *provider_section,
-  const struct TALER_PaytoHashP *h_payto,
-  uint64_t *requirement_row)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (h_payto),
-    GNUNET_PQ_query_param_string (provider_section),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_uint64 ("legitimization_requirement_serial_id",
-                                  requirement_row),
-    GNUNET_PQ_result_spec_end
-  };
-
-  return GNUNET_PQ_eval_prepared_singleton_select (
-    pg->conn,
-    "insert_legitimization_requirement",
-    params,
-    rs);
-}
-
-
-/**
- * Begin KYC requirement process.
- *
- * @param cls closure
- * @param h_payto account that must be KYC'ed
- * @param provider_section provider that must be checked
- * @param provider_account_id provider account ID
- * @param provider_legitimization_id provider legitimization ID
- * @param[out] process_row row the process is stored under
- * @return database transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_insert_kyc_requirement_process (
-  void *cls,
-  const struct TALER_PaytoHashP *h_payto,
-  const char *provider_section,
-  const char *provider_account_id,
-  const char *provider_legitimization_id,
-  uint64_t *process_row)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (h_payto),
-    GNUNET_PQ_query_param_string (provider_section),
-    (NULL != provider_account_id)
-    ? GNUNET_PQ_query_param_string (provider_account_id)
-    : GNUNET_PQ_query_param_null (),
-    (NULL != provider_legitimization_id)
-    ? GNUNET_PQ_query_param_string (provider_legitimization_id)
-    : GNUNET_PQ_query_param_null (),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_uint64 ("legitimization_process_serial_id",
-                                  process_row),
-    GNUNET_PQ_result_spec_end
-  };
-
-  return GNUNET_PQ_eval_prepared_singleton_select (
-    pg->conn,
-    "insert_legitimization_process",
-    params,
-    rs);
-}
-
-
-/**
- * Update KYC requirement check with provider-linkage and/or
- * expiration data.
- *
- * @param cls closure
- * @param process_row row to select by
- * @param provider_section provider that must be checked (technically 
redundant)
- * @param h_payto account that must be KYC'ed (helps access by shard, 
otherwise also redundant)
- * @param provider_account_id provider account ID
- * @param provider_legitimization_id provider legitimization ID
- * @param expiration how long is this KYC check set to be valid (in the past 
if invalid)
- * @return database transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_update_kyc_process_by_row (
-  void *cls,
-  uint64_t process_row,
-  const char *provider_section,
-  const struct TALER_PaytoHashP *h_payto,
-  const char *provider_account_id,
-  const char *provider_legitimization_id,
-  struct GNUNET_TIME_Absolute expiration)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_uint64 (&process_row),
-    GNUNET_PQ_query_param_string (provider_section),
-    GNUNET_PQ_query_param_auto_from_type (h_payto),
-    (NULL != provider_account_id)
-    ? GNUNET_PQ_query_param_string (provider_account_id)
-    : GNUNET_PQ_query_param_null (),
-    (NULL != provider_legitimization_id)
-    ? GNUNET_PQ_query_param_string (provider_legitimization_id)
-    : GNUNET_PQ_query_param_null (),
-    GNUNET_PQ_query_param_absolute_time (&expiration),
-    GNUNET_PQ_query_param_end
-  };
-  enum GNUNET_DB_QueryStatus qs;
-
-  qs = GNUNET_PQ_eval_prepared_non_select (
-    pg->conn,
-    "update_legitimization_process",
-    params);
-  if (qs <= 0)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "Failed to update legitimization process: %d\n",
-                qs);
-    return qs;
-  }
-  if (GNUNET_TIME_absolute_is_future (expiration))
-  {
-    enum GNUNET_DB_QueryStatus qs2;
-    struct TALER_KycCompletedEventP rep = {
-      .header.size = htons (sizeof (rep)),
-      .header.type = htons (TALER_DBEVENT_EXCHANGE_KYC_COMPLETED),
-      .h_payto = *h_payto
-    };
-    uint32_t trigger_type = 1;
-    struct GNUNET_PQ_QueryParam params2[] = {
-      GNUNET_PQ_query_param_auto_from_type (h_payto),
-      GNUNET_PQ_query_param_uint32 (&trigger_type),
-      GNUNET_PQ_query_param_end
-    };
-
-    postgres_event_notify (pg,
-                           &rep.header,
-                           NULL,
-                           0);
-    qs2 = GNUNET_PQ_eval_prepared_non_select (
-      pg->conn,
-      "alert_kyc_status_change",
-      params2);
-    if (qs2 < 0)
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Failed to store KYC alert: %d\n",
-                  qs2);
-  }
-  return qs;
-}
-
-
-/**
- * Lookup KYC requirement.
- *
- * @param cls closure
- * @param requirement_row identifies requirement to look up
- * @param[out] requirements provider that must be checked
- * @param[out] h_payto account that must be KYC'ed
- * @return database transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_kyc_requirement_by_row (
-  void *cls,
-  uint64_t requirement_row,
-  char **requirements,
-  struct TALER_PaytoHashP *h_payto)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_uint64 (&requirement_row),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_string ("required_checks",
-                                  requirements),
-    GNUNET_PQ_result_spec_auto_from_type ("h_payto",
-                                          h_payto),
-    GNUNET_PQ_result_spec_end
-  };
-
-  return GNUNET_PQ_eval_prepared_singleton_select (
-    pg->conn,
-    "lookup_legitimization_requirement_by_row",
-    params,
-    rs);
-}
-
-
-/**
- * Lookup KYC provider meta data.
- *
- * @param cls closure
- * @param provider_section provider that must be checked
- * @param h_payto account that must be KYC'ed
- * @param[out] process_row row with the legitimization data
- * @param[out] expiration how long is this KYC check set to be valid (in the 
past if invalid)
- * @param[out] provider_account_id provider account ID
- * @param[out] provider_legitimization_id provider legitimization ID
- * @return database transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_lookup_kyc_process_by_account (
-  void *cls,
-  const char *provider_section,
-  const struct TALER_PaytoHashP *h_payto,
-  uint64_t *process_row,
-  struct GNUNET_TIME_Absolute *expiration,
-  char **provider_account_id,
-  char **provider_legitimization_id)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (h_payto),
-    GNUNET_PQ_query_param_string (provider_section),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_uint64 ("legitimization_process_serial_id",
-                                  process_row),
-    GNUNET_PQ_result_spec_absolute_time ("expiration_time",
-                                         expiration),
-    GNUNET_PQ_result_spec_allow_null (
-      GNUNET_PQ_result_spec_string ("provider_user_id",
-                                    provider_account_id),
-      NULL),
-    GNUNET_PQ_result_spec_allow_null (
-      GNUNET_PQ_result_spec_string ("provider_legitimization_id",
-                                    provider_legitimization_id),
-      NULL),
-    GNUNET_PQ_result_spec_end
-  };
-
-  *provider_account_id = NULL;
-  *provider_legitimization_id = NULL;
-  return GNUNET_PQ_eval_prepared_singleton_select (
-    pg->conn,
-    "lookup_process_by_account",
-    params,
-    rs);
-}
-
-
-/**
- * Lookup an
- * @a h_payto by @a provider_legitimization_id.
- *
- * @param cls closure
- * @param provider_section
- * @param provider_legitimization_id legi to look up
- * @param[out] h_payto where to write the result
- * @param[out] process_row where to write the row of the entry
- * @return database transaction status
- */
-static enum GNUNET_DB_QueryStatus
-postgres_kyc_provider_account_lookup (
-  void *cls,
-  const char *provider_section,
-  const char *provider_legitimization_id,
-  struct TALER_PaytoHashP *h_payto,
-  uint64_t *process_row)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_string (provider_section),
-    GNUNET_PQ_query_param_string (provider_legitimization_id),
-    GNUNET_PQ_query_param_end
-  };
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_auto_from_type ("h_payto",
-                                          h_payto),
-    GNUNET_PQ_result_spec_uint64 ("legitimization_process_serial_id",
-                                  process_row),
-    GNUNET_PQ_result_spec_end
-  };
-
-  return GNUNET_PQ_eval_prepared_singleton_select (
-    pg->conn,
-    "get_wire_target_by_legitimization_id",
-    params,
-    rs);
-}
-
-
-/**
- * Closure for #get_wire_fees_cb().
- */
-struct GetLegitimizationsContext
-{
-  /**
-   * Function to call per result.
-   */
-  TALER_EXCHANGEDB_SatisfiedProviderCallback cb;
-
-  /**
-   * Closure for @e cb.
-   */
-  void *cb_cls;
-
-  /**
-   * Plugin context.
-   */
-  struct PostgresClosure *pg;
-
-  /**
-   * Flag set to #GNUNET_OK as long as everything is fine.
-   */
-  enum GNUNET_GenericReturnValue status;
-
-};
-
-
-/**
- * Invoke the callback for each result.
- *
- * @param cls a `struct GetLegitimizationsContext *`
- * @param result SQL result
- * @param num_results number of rows in @a result
- */
-static void
-get_legitimizations_cb (void *cls,
-                        PGresult *result,
-                        unsigned int num_results)
-{
-  struct GetLegitimizationsContext *ctx = cls;
-
-  for (unsigned int i = 0; i < num_results; i++)
-  {
-    char *provider_section;
-    struct GNUNET_PQ_ResultSpec rs[] = {
-      GNUNET_PQ_result_spec_string ("provider_section",
-                                    &provider_section),
-      GNUNET_PQ_result_spec_end
-    };
-
-    if (GNUNET_OK !=
-        GNUNET_PQ_extract_result (result,
-                                  rs,
-                                  i))
-    {
-      GNUNET_break (0);
-      ctx->status = GNUNET_SYSERR;
-      return;
-    }
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "Found satisfied LEGI: %s\n",
-                provider_section);
-    ctx->cb (ctx->cb_cls,
-             provider_section);
-    GNUNET_PQ_cleanup_result (rs);
-  }
-}
-
-
-/**
- * Call us on KYC processes satisfied for the given
- * account.
- *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param h_payto account identifier
- * @param spc function to call for each satisfied KYC process
- * @param spc_cls closure for @a spc
- * @return transaction status code
- */
-static enum GNUNET_DB_QueryStatus
-postgres_select_satisfied_kyc_processes (
-  void *cls,
-  const struct TALER_PaytoHashP *h_payto,
-  TALER_EXCHANGEDB_SatisfiedProviderCallback spc,
-  void *spc_cls)
-{
-  struct PostgresClosure *pg = cls;
-  struct GNUNET_TIME_Absolute now
-    = GNUNET_TIME_absolute_get ();
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (h_payto),
-    GNUNET_PQ_query_param_absolute_time (&now),
-    GNUNET_PQ_query_param_end
-  };
-  struct GetLegitimizationsContext ctx = {
-    .cb = spc,
-    .cb_cls = spc_cls,
-    .pg = pg,
-    .status = GNUNET_OK
-  };
-  enum GNUNET_DB_QueryStatus qs;
-
-  qs = GNUNET_PQ_eval_prepared_multi_select (
-    pg->conn,
-    "get_satisfied_legitimizations",
-    params,
-    &get_legitimizations_cb,
-    &ctx);
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Satisfied LEGI check returned %d\n",
-              qs);
-  if (GNUNET_OK != ctx.status)
-    return GNUNET_DB_STATUS_HARD_ERROR;
-  return qs;
-}
-
-
-/**
- * Closure for #get_kyc_amounts_cb().
- */
-struct KycAmountCheckContext
-{
-  /**
-   * Function to call per result.
-   */
-  TALER_EXCHANGEDB_KycAmountCallback cb;
-
-  /**
-   * Closure for @e cb.
-   */
-  void *cb_cls;
-
-  /**
-   * Plugin context.
-   */
-  struct PostgresClosure *pg;
-
-  /**
-   * Flag set to #GNUNET_OK as long as everything is fine.
-   */
-  enum GNUNET_GenericReturnValue status;
+}
+
+
 
-};
 
 
-/**
- * Invoke the callback for each result.
- *
- * @param cls a `struct KycAmountCheckContext *`
- * @param result SQL result
- * @param num_results number of rows in @a result
- */
-static void
-get_kyc_amounts_cb (void *cls,
-                    PGresult *result,
-                    unsigned int num_results)
-{
-  struct KycAmountCheckContext *ctx = cls;
-  struct PostgresClosure *pg = ctx->pg;
 
-  for (unsigned int i = 0; i < num_results; i++)
-  {
-    struct GNUNET_TIME_Absolute date;
-    struct TALER_Amount amount;
-    struct GNUNET_PQ_ResultSpec rs[] = {
-      TALER_PQ_RESULT_SPEC_AMOUNT ("amount",
-                                   &amount),
-      GNUNET_PQ_result_spec_absolute_time ("date",
-                                           &date),
-      GNUNET_PQ_result_spec_end
-    };
-    enum GNUNET_GenericReturnValue ret;
 
-    if (GNUNET_OK !=
-        GNUNET_PQ_extract_result (result,
-                                  rs,
-                                  i))
-    {
-      GNUNET_break (0);
-      ctx->status = GNUNET_SYSERR;
-      return;
-    }
-    ret = ctx->cb (ctx->cb_cls,
-                   &amount,
-                   date);
-    GNUNET_PQ_cleanup_result (rs);
-    switch (ret)
-    {
-    case GNUNET_OK:
-      continue;
-    case GNUNET_NO:
-      break;
-    case GNUNET_SYSERR:
-      ctx->status = GNUNET_SYSERR;
-      break;
-    }
-    break;
-  }
-}
 
 
 /**
- * Call @a kac on withdrawn amounts after @a time_limit which are relevant
- * for a KYC trigger for a the (debited) account identified by @a h_payto.
+ * Function called to clean up one expired purse.
  *
  * @param cls the @e cls of this struct with the plugin-specific state
- * @param h_payto account identifier
- * @param time_limit oldest transaction that could be relevant
- * @param kac function to call for each applicable amount, in reverse 
chronological order (or until @a kac aborts by returning anything except 
#GNUNET_OK).
- * @param kac_cls closure for @a kac
- * @return transaction status code, @a kac aborting with #GNUNET_NO is not an 
error
+ * @param start_time select purse expired after this time
+ * @param end_time select purse expired before this time
+ * @return transaction status code (#GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if no 
purse expired in the given time interval).
  */
 static enum GNUNET_DB_QueryStatus
-postgres_select_withdraw_amounts_for_kyc_check (
+postgres_expire_purse (
   void *cls,
-  const struct TALER_PaytoHashP *h_payto,
-  struct GNUNET_TIME_Absolute time_limit,
-  TALER_EXCHANGEDB_KycAmountCallback kac,
-  void *kac_cls)
+  struct GNUNET_TIME_Absolute start_time,
+  struct GNUNET_TIME_Absolute end_time)
 {
   struct PostgresClosure *pg = cls;
+  struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (h_payto),
-    GNUNET_PQ_query_param_absolute_time (&time_limit),
+    GNUNET_PQ_query_param_absolute_time (&start_time),
+    GNUNET_PQ_query_param_absolute_time (&end_time),
+    GNUNET_PQ_query_param_absolute_time (&now),
     GNUNET_PQ_query_param_end
   };
-  struct KycAmountCheckContext ctx = {
-    .cb = kac,
-    .cb_cls = kac_cls,
-    .pg = pg,
-    .status = GNUNET_OK
+  bool found = false;
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_bool ("found",
+                                &found),
+    GNUNET_PQ_result_spec_end
   };
   enum GNUNET_DB_QueryStatus qs;
 
-  qs = GNUNET_PQ_eval_prepared_multi_select (
-    pg->conn,
-    "select_kyc_relevant_withdraw_events",
-    params,
-    &get_kyc_amounts_cb,
-    &ctx);
-  if (GNUNET_OK != ctx.status)
-    return GNUNET_DB_STATUS_HARD_ERROR;
-  return qs;
+  qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                 "call_expire_purse",
+                                                 params,
+                                                 rs);
+  if (qs < 0)
+    return qs;
+  GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
+  return found
+         ? GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
+         : GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
 }
 
 
 /**
- * Call @a kac on deposited amounts after @a time_limit which are relevant for 
a
- * KYC trigger for a the (credited) account identified by @a h_payto.
+ * Function called to return meta data about a purse by the
+ * merge capability key.
  *
  * @param cls the @e cls of this struct with the plugin-specific state
- * @param h_payto account identifier
- * @param time_limit oldest transaction that could be relevant
- * @param kac function to call for each applicable amount, in reverse 
chronological order (or until @a kac aborts by returning anything except 
#GNUNET_OK).
- * @param kac_cls closure for @a kac
- * @return transaction status code, @a kac aborting with #GNUNET_NO is not an 
error
+ * @param merge_pub public key representing the merge capability
+ * @param[out] purse_pub public key of the purse
+ * @param[out] purse_expiration when would an unmerged purse expire
+ * @param[out] h_contract_terms contract associated with the purse
+ * @param[out] age_limit the age limit for deposits into the purse
+ * @param[out] target_amount amount to be put into the purse
+ * @param[out] balance amount put so far into the purse
+ * @param[out] purse_sig signature of the purse over the initialization data
+ * @return transaction status code
  */
 static enum GNUNET_DB_QueryStatus
-postgres_select_aggregation_amounts_for_kyc_check (
+postgres_select_purse_by_merge_pub (
   void *cls,
-  const struct TALER_PaytoHashP *h_payto,
-  struct GNUNET_TIME_Absolute time_limit,
-  TALER_EXCHANGEDB_KycAmountCallback kac,
-  void *kac_cls)
+  const struct TALER_PurseMergePublicKeyP *merge_pub,
+  struct TALER_PurseContractPublicKeyP *purse_pub,
+  struct GNUNET_TIME_Timestamp *purse_expiration,
+  struct TALER_PrivateContractHashP *h_contract_terms,
+  uint32_t *age_limit,
+  struct TALER_Amount *target_amount,
+  struct TALER_Amount *balance,
+  struct TALER_PurseContractSignatureP *purse_sig)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (h_payto),
-    GNUNET_PQ_query_param_absolute_time (&time_limit),
+    GNUNET_PQ_query_param_auto_from_type (merge_pub),
     GNUNET_PQ_query_param_end
   };
-  struct KycAmountCheckContext ctx = {
-    .cb = kac,
-    .cb_cls = kac_cls,
-    .pg = pg,
-    .status = GNUNET_OK
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_auto_from_type ("purse_pub",
+                                          purse_pub),
+    GNUNET_PQ_result_spec_timestamp ("purse_expiration",
+                                     purse_expiration),
+    GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
+                                          h_contract_terms),
+    GNUNET_PQ_result_spec_uint32 ("age_limit",
+                                  age_limit),
+    TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
+                                 target_amount),
+    TALER_PQ_RESULT_SPEC_AMOUNT ("balance",
+                                 balance),
+    GNUNET_PQ_result_spec_auto_from_type ("purse_sig",
+                                          purse_sig),
+    GNUNET_PQ_result_spec_end
   };
-  enum GNUNET_DB_QueryStatus qs;
-
-  qs = GNUNET_PQ_eval_prepared_multi_select (
-    pg->conn,
-    "select_kyc_relevant_aggregation_events",
-    params,
-    &get_kyc_amounts_cb,
-    &ctx);
-  if (GNUNET_OK != ctx.status)
-    return GNUNET_DB_STATUS_HARD_ERROR;
-  return qs;
+  return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   "select_purse_by_merge_pub",
+                                                   params,
+                                                   rs);
 }
 
 
+
+
 /**
- * Call @a kac on merged reserve amounts after @a time_limit which are 
relevant for a
- * KYC trigger for a the wallet identified by @a h_payto.
+ * Set the current @a balance in the purse
+ * identified by @a purse_pub. Used by the auditor
+ * to update the balance as calculated by the auditor.
  *
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param h_payto account identifier
- * @param time_limit oldest transaction that could be relevant
- * @param kac function to call for each applicable amount, in reverse 
chronological order (or until @a kac aborts by returning anything except 
#GNUNET_OK).
- * @param kac_cls closure for @a kac
- * @return transaction status code, @a kac aborting with #GNUNET_NO is not an 
error
+ * @param cls closure
+ * @param purse_pub public key of a purse
+ * @param balance new balance to store under the purse
+ * @return transaction status
  */
 static enum GNUNET_DB_QueryStatus
-postgres_select_merge_amounts_for_kyc_check (
+postgres_set_purse_balance (
   void *cls,
-  const struct TALER_PaytoHashP *h_payto,
-  struct GNUNET_TIME_Absolute time_limit,
-  TALER_EXCHANGEDB_KycAmountCallback kac,
-  void *kac_cls)
+  const struct TALER_PurseContractPublicKeyP *purse_pub,
+  const struct TALER_Amount *balance)
 {
   struct PostgresClosure *pg = cls;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (h_payto),
-    GNUNET_PQ_query_param_absolute_time (&time_limit),
+    GNUNET_PQ_query_param_auto_from_type (purse_pub),
+    TALER_PQ_query_param_amount (balance),
     GNUNET_PQ_query_param_end
   };
-  struct KycAmountCheckContext ctx = {
-    .cb = kac,
-    .cb_cls = kac_cls,
-    .pg = pg,
-    .status = GNUNET_OK
-  };
-  enum GNUNET_DB_QueryStatus qs;
 
-  qs = GNUNET_PQ_eval_prepared_multi_select (
-    pg->conn,
-    "select_kyc_relevant_merge_events",
-    params,
-    &get_kyc_amounts_cb,
-    &ctx);
-  if (GNUNET_OK != ctx.status)
-    return GNUNET_DB_STATUS_HARD_ERROR;
-  return qs;
+  return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "set_purse_balance",
+                                             params);
 }
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 /**
  * Initialize Postgres database subsystem.
  *
@@ -11639,14 +9206,14 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
   plugin->create_tables = &postgres_create_tables;
 
   plugin->setup_foreign_servers = &postgres_setup_foreign_servers;
-  plugin->start = &postgres_start;
-  plugin->start_read_committed = &postgres_start_read_committed;
-  plugin->start_read_only = &postgres_start_read_only;
-  plugin->rollback = &postgres_rollback;
+ 
+ 
+
+ 
   plugin->event_listen = &postgres_event_listen;
   plugin->event_listen_cancel = &postgres_event_listen_cancel;
   plugin->event_notify = &postgres_event_notify;
-  plugin->insert_denomination_info = &postgres_insert_denomination_info;
+
   plugin->get_denomination_info = &postgres_get_denomination_info;
   plugin->iterate_denomination_info = &postgres_iterate_denomination_info;
   plugin->iterate_denominations = &postgres_iterate_denominations;
@@ -11662,7 +9229,7 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
   plugin->do_batch_withdraw = &postgres_do_batch_withdraw;
   plugin->get_policy_details = &postgres_get_policy_details;
   plugin->persist_policy_details = &postgres_persist_policy_details;
-  plugin->do_batch_withdraw_insert = &postgres_do_batch_withdraw_insert;
+
   plugin->do_deposit = &postgres_do_deposit;
   plugin->add_policy_fulfillment_proof = 
&postgres_add_policy_fulfillment_proof;
   plugin->do_melt = &postgres_do_melt;
@@ -11750,8 +9317,7 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
     = &postgres_lookup_auditor_status;
   plugin->insert_auditor
     = &postgres_insert_auditor;
-  plugin->update_auditor
-    = &postgres_update_auditor;
+
   plugin->lookup_wire_timestamp
     = &postgres_lookup_wire_timestamp;
   plugin->insert_wire
@@ -11772,14 +9338,11 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
     = &postgres_insert_auditor_denom_sig;
   plugin->select_auditor_denom_sig
     = &postgres_select_auditor_denom_sig;
-  plugin->lookup_wire_fee_by_time
-    = &postgres_lookup_wire_fee_by_time;
-  plugin->lookup_global_fee_by_time
-    = &postgres_lookup_global_fee_by_time;
+
+
   plugin->add_denomination_key
     = &postgres_add_denomination_key;
-  plugin->activate_signing_key
-    = &postgres_activate_signing_key;
+
   plugin->lookup_signing_key
     = &postgres_lookup_signing_key;
   plugin->begin_shard
@@ -11788,71 +9351,35 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
     = &postgres_abort_shard;
   plugin->complete_shard
     = &postgres_complete_shard;
-  plugin->begin_revolving_shard
-    = &postgres_begin_revolving_shard;
+
   plugin->release_revolving_shard
     = &postgres_release_revolving_shard;
   plugin->delete_shard_locks
     = &postgres_delete_shard_locks;
   plugin->set_extension_manifest
     = &postgres_set_extension_manifest;
-  plugin->get_extension_manifest
-    = &postgres_get_extension_manifest;
+
   plugin->insert_partner
     = &postgres_insert_partner;
-  plugin->insert_contract
-    = &postgres_insert_contract;
-  plugin->select_contract
-    = &postgres_select_contract;
-  plugin->select_contract_by_purse
-    = &postgres_select_contract_by_purse;
+
+
+
   plugin->expire_purse
     = &postgres_expire_purse;
   plugin->select_purse_by_merge_pub
     = &postgres_select_purse_by_merge_pub;
   
-  plugin->do_purse_deposit
-    = &postgres_do_purse_deposit;
+
   plugin->set_purse_balance
     = &postgres_set_purse_balance;
-  plugin->get_purse_deposit
-    = &postgres_get_purse_deposit;
-  plugin->do_purse_merge
-    = &postgres_do_purse_merge;
-  plugin->do_reserve_purse
-    = &postgres_do_reserve_purse;
-  plugin->select_purse_merge
-    = &postgres_select_purse_merge;
-  plugin->insert_history_request
-    = &postgres_insert_history_request;
-  plugin->insert_drain_profit
-    = &postgres_insert_drain_profit;
-  plugin->profit_drains_get_pending
-    = &postgres_profit_drains_get_pending;
-  plugin->get_drain_profit
-    = &postgres_get_drain_profit;
-  plugin->profit_drains_set_finished
-    = &postgres_profit_drains_set_finished;
-  plugin->insert_kyc_requirement_for_account
-    = &postgres_insert_kyc_requirement_for_account;
-  plugin->insert_kyc_requirement_process
-    = &postgres_insert_kyc_requirement_process;
-  plugin->update_kyc_process_by_row
-    = &postgres_update_kyc_process_by_row;
-  plugin->lookup_kyc_requirement_by_row
-    = &postgres_lookup_kyc_requirement_by_row;
-  plugin->lookup_kyc_process_by_account
-    = &postgres_lookup_kyc_process_by_account;
-  plugin->kyc_provider_account_lookup
-    = &postgres_kyc_provider_account_lookup;
-  plugin->select_satisfied_kyc_processes
-    = &postgres_select_satisfied_kyc_processes;
-  plugin->select_withdraw_amounts_for_kyc_check
-    = &postgres_select_withdraw_amounts_for_kyc_check;
-  plugin->select_aggregation_amounts_for_kyc_check
-    = &postgres_select_aggregation_amounts_for_kyc_check;
-  plugin->select_merge_amounts_for_kyc_check
-    = &postgres_select_merge_amounts_for_kyc_check;
+
+
+
+
+
+
+
+
   /* NEW style, sort alphabetically! */
   plugin->do_reserve_open
     = &TEH_PG_do_reserve_open;
@@ -11912,6 +9439,7 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
     = &TEH_PG_select_reserve_closed_above_serial_id;
   plugin->select_reserve_open_above_serial_id
     = &TEH_PG_select_reserve_open_above_serial_id;
+  /*need to sort*/
   plugin->insert_purse_request
     = &TEH_PG_insert_purse_request;
   plugin->iterate_active_signkeys
@@ -11926,7 +9454,82 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
     = &TEH_PG_insert_aggregation_tracking;
   plugin->setup_partitions
     = &TEH_PG_setup_partitions;
+  plugin->select_aggregation_amounts_for_kyc_check
+    = &TEH_PG_select_aggregation_amounts_for_kyc_check;
+
+  plugin->select_satisfied_kyc_processes
+    = &TEH_PG_select_satisfied_kyc_processes;
+  plugin->kyc_provider_account_lookup
+    = &TEH_PG_kyc_provider_account_lookup;
+  plugin->lookup_kyc_requirement_by_row
+    = &TEH_PG_lookup_kyc_requirement_by_row;
+  plugin->insert_kyc_requirement_for_account
+    = &TEH_PG_insert_kyc_requirement_for_account;  
+
+  
+  plugin->lookup_kyc_process_by_account
+    = &TEH_PG_lookup_kyc_process_by_account;
+  plugin->update_kyc_process_by_row
+    = &TEH_PG_update_kyc_process_by_row;
+  plugin->insert_kyc_requirement_process
+    = &TEH_PG_insert_kyc_requirement_process;
+  plugin->select_withdraw_amounts_for_kyc_check
+    = &TEH_PG_select_withdraw_amounts_for_kyc_check;
+  plugin->select_merge_amounts_for_kyc_check
+    = &TEH_PG_select_merge_amounts_for_kyc_check;
+  plugin->profit_drains_set_finished
+    = &TEH_PG_profit_drains_set_finished;
+  plugin->profit_drains_get_pending
+    = &TEH_PG_profit_drains_get_pending;
+  plugin->get_drain_profit
+    = &TEH_PG_get_drain_profit;
+  plugin->get_purse_deposit
+    = &TEH_PG_get_purse_deposit;
+  plugin->insert_contract
+    = &TEH_PG_insert_contract;
+  plugin->select_contract
+    = &TEH_PG_select_contract;
+  plugin->select_purse_merge
+    = &TEH_PG_select_purse_merge;
+  plugin->select_contract_by_purse
+    = &TEH_PG_select_contract_by_purse;
+  plugin->insert_drain_profit
+    = &TEH_PG_insert_drain_profit;
+  plugin->do_reserve_purse
+    = &TEH_PG_do_reserve_purse;
+  plugin->lookup_global_fee_by_time
+    = &TEH_PG_lookup_global_fee_by_time;
+  plugin->do_purse_deposit
+    = &TEH_PG_do_purse_deposit;
+  plugin->activate_signing_key
+    = &TEH_PG_activate_signing_key;
+  plugin->update_auditor
+    = &TEH_PG_update_auditor;
+  plugin->begin_revolving_shard
+    = &TEH_PG_begin_revolving_shard;
+  plugin->get_extension_manifest
+    = &TEH_PG_get_extension_manifest;
+  plugin->insert_history_request
+    = &TEH_PG_insert_history_request;
+  plugin->do_purse_merge
+    = &TEH_PG_do_purse_merge;
+  plugin->start_read_committed
+    = &TEH_PG_start_read_committed;
+  plugin->start_read_only
+    = &TEH_PG_start_read_only;
+  plugin->insert_denomination_info
+    = &TEH_PG_insert_denomination_info;
+  plugin->do_batch_withdraw_insert
+    = &TEH_PG_do_batch_withdraw_insert;
+  plugin->lookup_wire_fee_by_time
+    = &TEH_PG_lookup_wire_fee_by_time;
+  plugin->start
+    = &TEH_PG_start;
+  plugin->rollback
+    = &TEH_PG_rollback;
 
+
+  
   return plugin;
 }
 

-- 
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]