gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [taler-exchange] branch master updated: implementing #4929


From: gnunet
Subject: [GNUnet-SVN] [taler-exchange] branch master updated: implementing #4929
Date: Sat, 04 Mar 2017 16:49:36 +0100

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

grothoff pushed a commit to branch master
in repository exchange.

The following commit(s) were added to refs/heads/master by this push:
     new 6ab67a3  implementing #4929
6ab67a3 is described below

commit 6ab67a3a76ee5ce8f8dec910dae7da524f066d2a
Author: Christian Grothoff <address@hidden>
AuthorDate: Sat Mar 4 16:49:33 2017 +0100

    implementing #4929
---
 src/exchange-lib/exchange_api_track_transfer.c     |   6 +
 src/exchange-lib/test_exchange_api.c               |  46 +++-
 src/exchange/taler-exchange-aggregator.c           | 159 +++++++++++---
 src/exchange/taler-exchange-httpd_db.c             |  41 ++++
 src/exchange/taler-exchange-httpd_responses.c      |   7 +-
 src/exchange/taler-exchange-httpd_responses.h      |   2 +
 .../test-taler-exchange-aggregator-postgres.conf   |  14 ++
 src/exchange/test_taler_exchange_aggregator.c      |  42 ++--
 src/exchangedb/exchangedb.conf                     |   2 +-
 src/exchangedb/plugin_exchangedb_postgres.c        | 236 ++++++++++++++++++++-
 src/exchangedb/test_exchangedb.c                   |   4 +
 src/include/taler_error_codes.h                    |  15 +-
 src/include/taler_exchange_service.h               |   2 +
 src/include/taler_exchangedb_plugin.h              |  50 +++++
 src/include/taler_signatures.h                     |   5 +
 15 files changed, 573 insertions(+), 58 deletions(-)

diff --git a/src/exchange-lib/exchange_api_track_transfer.c 
b/src/exchange-lib/exchange_api_track_transfer.c
index 819a00a..dff39eb 100644
--- a/src/exchange-lib/exchange_api_track_transfer.c
+++ b/src/exchange-lib/exchange_api_track_transfer.c
@@ -87,12 +87,14 @@ check_track_transfer_response_ok (struct 
TALER_EXCHANGE_TrackTransferHandle *wdh
   struct GNUNET_HashCode h_wire;
   struct GNUNET_TIME_Absolute exec_time;
   struct TALER_Amount total_amount;
+  struct TALER_Amount wire_fee;
   struct TALER_MerchantPublicKeyP merchant_pub;
   unsigned int num_details;
   struct TALER_ExchangePublicKeyP exchange_pub;
   struct TALER_ExchangeSignatureP exchange_sig;
   struct GNUNET_JSON_Specification spec[] = {
     TALER_JSON_spec_amount ("total", &total_amount),
+    TALER_JSON_spec_amount ("wire_fee", &wire_fee),
     GNUNET_JSON_spec_fixed_auto ("merchant_pub", &merchant_pub),
     GNUNET_JSON_spec_fixed_auto ("H_wire", &h_wire),
     GNUNET_JSON_spec_absolute_time ("execution_time", &exec_time),
@@ -158,6 +160,8 @@ check_track_transfer_response_ok (struct 
TALER_EXCHANGE_TrackTransferHandle *wdh
     wdp.purpose.size = htonl (sizeof (struct TALER_WireDepositDataPS));
     TALER_amount_hton (&wdp.total,
                        &total_amount);
+    TALER_amount_hton (&wdp.wire_fee,
+                       &wire_fee);
     wdp.merchant_pub = merchant_pub;
     wdp.h_wire = h_wire;
     GNUNET_CRYPTO_hash_context_finish (hash_context,
@@ -186,6 +190,7 @@ check_track_transfer_response_ok (struct 
TALER_EXCHANGE_TrackTransferHandle *wdh
              &h_wire,
              exec_time,
              &total_amount,
+             &wire_fee,
              num_details,
              details);
   }
@@ -257,6 +262,7 @@ handle_track_transfer_finished (void *cls,
            NULL,
            GNUNET_TIME_UNIT_ZERO_ABS,
            NULL,
+           NULL,
            0, NULL);
   TALER_EXCHANGE_track_transfer_cancel (wdh);
 }
diff --git a/src/exchange-lib/test_exchange_api.c 
b/src/exchange-lib/test_exchange_api.c
index 2456d77..3e69c25 100644
--- a/src/exchange-lib/test_exchange_api.c
+++ b/src/exchange-lib/test_exchange_api.c
@@ -540,6 +540,12 @@ struct Command
        */
       const char *total_amount_expected;
 
+      /**
+       * What is the expected wire fee? Only used if
+       * @e expected_response_code was #MHD_HTTP_OK.
+       */
+      const char *wire_fee_expected;
+
 
       /* TODO: may want to add list of deposits we expected
          to see aggregated here in the future. */
@@ -1417,6 +1423,7 @@ wire_cb (void *cls,
  * @param execution_time time when the exchange claims to have performed the 
wire transfer
  * @param total_amount total amount of the wire transfer, or NULL if the 
exchange could
  *             not provide any @a wtid (set only if @a http_status is 
#MHD_HTTP_OK)
+ * @param wire_fee wire fee that was charged by the exchange
  * @param details_length length of the @a details array
  * @param details array with details about the combined transactions
  */
@@ -1429,6 +1436,7 @@ wire_deposits_cb (void *cls,
                   const struct GNUNET_HashCode *h_wire,
                   struct GNUNET_TIME_Absolute execution_time,
                   const struct TALER_Amount *total_amount,
+                  const struct TALER_Amount *wire_fee,
                   unsigned int details_length,
                   const struct TALER_TrackTransferDetails *details)
 {
@@ -1469,6 +1477,24 @@ wire_deposits_cb (void *cls,
       fail (is);
       return;
     }
+    if (GNUNET_OK !=
+        TALER_string_to_amount (cmd->details.wire_deposits.wire_fee_expected,
+                                &expected_amount))
+    {
+      GNUNET_break (0);
+      fail (is);
+      return;
+    }
+    if (0 != TALER_amount_cmp (wire_fee,
+                               &expected_amount))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Wire fee missmatch to command %s\n",
+                  cmd->label);
+      json_dumpf (json, stderr, 0);
+      fail (is);
+      return;
+    }
     ref = find_command (is,
                         cmd->details.wire_deposits.wtid_ref);
     GNUNET_assert (NULL != ref);
@@ -2923,28 +2949,28 @@ run (void *cls)
     { .oc = OC_CHECK_BANK_TRANSFER,
       .label = "check_bank_transfer-499c",
       .details.check_bank_transfer.exchange_base_url = "https://exchange.com/";,
-      .details.check_bank_transfer.amount = "EUR:4.99",
+      .details.check_bank_transfer.amount = "EUR:4.98",
       .details.check_bank_transfer.account_debit = 2,
       .details.check_bank_transfer.account_credit = 42
     },
     { .oc = OC_CHECK_BANK_TRANSFER,
       .label = "check_bank_transfer-99c1",
       .details.check_bank_transfer.exchange_base_url = "https://exchange.com/";,
-      .details.check_bank_transfer.amount = "EUR:0.99",
+      .details.check_bank_transfer.amount = "EUR:0.98",
       .details.check_bank_transfer.account_debit = 2,
       .details.check_bank_transfer.account_credit = 42
     },
     { .oc = OC_CHECK_BANK_TRANSFER,
       .label = "check_bank_transfer-99c2",
       .details.check_bank_transfer.exchange_base_url = "https://exchange.com/";,
-      .details.check_bank_transfer.amount = "EUR:0.99",
+      .details.check_bank_transfer.amount = "EUR:0.98",
       .details.check_bank_transfer.account_debit = 2,
       .details.check_bank_transfer.account_credit = 42
     },
     { .oc = OC_CHECK_BANK_TRANSFER,
       .label = "check_bank_transfer-9c",
       .details.check_bank_transfer.exchange_base_url = "https://exchange.com/";,
-      .details.check_bank_transfer.amount = "EUR:0.09",
+      .details.check_bank_transfer.amount = "EUR:0.08",
       .details.check_bank_transfer.account_debit = 2,
       .details.check_bank_transfer.account_credit = 43
     },
@@ -2959,16 +2985,18 @@ run (void *cls)
       .details.deposit_wtid.bank_transfer_ref = "check_bank_transfer-499c" },
 
     { .oc = OC_WIRE_DEPOSITS,
-      .label = "wire-deposits-sucess-bank",
+      .label = "wire-deposits-success-bank",
       .expected_response_code = MHD_HTTP_OK,
       .details.wire_deposits.wtid_ref = "check_bank_transfer-99c1",
-      .details.wire_deposits.total_amount_expected = "EUR:0.99" },
+      .details.wire_deposits.total_amount_expected = "EUR:0.98",
+      .details.wire_deposits.wire_fee_expected = "EUR:0.01"  },
 
     { .oc = OC_WIRE_DEPOSITS,
-      .label = "wire-deposits-sucess-wtid",
+      .label = "wire-deposits-success-wtid",
       .expected_response_code = MHD_HTTP_OK,
       .details.wire_deposits.wtid_ref = "deposit-wtid-ok",
-      .details.wire_deposits.total_amount_expected = "EUR:4.99" },
+      .details.wire_deposits.total_amount_expected = "EUR:4.98",
+      .details.wire_deposits.wire_fee_expected = "EUR:0.01"  },
 
     /* ************** End of tracking API testing************* */
 
@@ -3030,7 +3058,7 @@ run (void *cls)
     { .oc = OC_CHECK_BANK_TRANSFER,
       .label = "check_bank_transfer-pre-refund",
       .details.check_bank_transfer.exchange_base_url = "https://exchange.com/";,
-      .details.check_bank_transfer.amount = "EUR:4.98",
+      .details.check_bank_transfer.amount = "EUR:4.97",
       .details.check_bank_transfer.account_debit = 2,
       .details.check_bank_transfer.account_credit = 42
     },
diff --git a/src/exchange/taler-exchange-aggregator.c 
b/src/exchange/taler-exchange-aggregator.c
index 96ec762..cbf3fb5 100644
--- a/src/exchange/taler-exchange-aggregator.c
+++ b/src/exchange/taler-exchange-aggregator.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2016 GNUnet e.V.
+  Copyright (C) 2016, 2017 GNUnet e.V.
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Affero General Public License as published by the Free 
Software
@@ -53,6 +53,12 @@ struct WirePlugin
    * Name of the plugin.
    */
   char *type;
+
+  /**
+   * Wire transfer fee structure.
+   */
+  struct TALER_EXCHANGEDB_AggregateFees *af;
+
 };
 
 
@@ -103,6 +109,11 @@ struct AggregationUnit
   struct TALER_Amount total_amount;
 
   /**
+   * Wire fee we charge for @e wp at @e execution_time.
+   */
+  struct TALER_Amount wire_fee;
+
+  /**
    * Hash of @e wire.
    */
   struct GNUNET_HashCode h_wire;
@@ -260,6 +271,83 @@ extract_type (const json_t *wire)
 
 
 /**
+ * Advance the "af" pointer in @a wp to point to the
+ * currently valid record.
+ *
+ * @param wp wire transfer fee data structure to update
+ * @param now timestamp to update fees to
+ */
+static void
+advance_fees (struct WirePlugin *wp,
+              struct GNUNET_TIME_Absolute now)
+{
+  struct TALER_EXCHANGEDB_AggregateFees *af;
+
+  /* First, try to see if we have current fee information in memory */
+  af = wp->af;
+  while ( (NULL != af) &&
+          (af->end_date.abs_value_us < now.abs_value_us) )
+  {
+    struct TALER_EXCHANGEDB_AggregateFees *n = af->next;
+
+    GNUNET_free (af);
+    af = n;
+  }
+  wp->af = af;
+}
+
+
+/**
+ * Update wire transfer fee data structure in @a wp.
+ *
+ * @param wp wire transfer fee data structure to update
+ * @param now timestamp to update fees to
+ * @param session DB session to use
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR if we
+ *         lack current fee information (and need to exit)
+ */
+static int
+update_fees (struct WirePlugin *wp,
+             struct GNUNET_TIME_Absolute now,
+             struct TALER_EXCHANGEDB_Session *session)
+{
+  advance_fees (wp,
+                now);
+  if (NULL != wp->af)
+    return GNUNET_OK;
+  /* Let's try to load it from disk... */
+  wp->af = TALER_EXCHANGEDB_fees_read (cfg,
+                                       wp->type);
+  advance_fees (wp,
+                now);
+  for (struct TALER_EXCHANGEDB_AggregateFees *p = wp->af;
+       NULL != p;
+       p = p->next)
+  {
+    if (GNUNET_SYSERR ==
+        db_plugin->insert_wire_fee (db_plugin->cls,
+                                    session,
+                                    wp->type,
+                                    p->start_date,
+                                    p->end_date,
+                                    &p->wire_fee,
+                                    &p->master_sig))
+    {
+      TALER_EXCHANGEDB_fees_free (wp->af);
+      wp->af = NULL;
+      return GNUNET_SYSERR;
+    }
+  }
+  if (NULL != wp->af)
+    return GNUNET_OK;
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+              "Failed to find current wire transfer fees for `%s'\n",
+              wp->type);
+  return GNUNET_SYSERR;
+}
+
+
+/**
  * Find the wire plugin for the given wire address.
  *
  * @param type wire plugin type we need a plugin for
@@ -345,6 +433,7 @@ shutdown_task (void *cls)
                                  wp_tail,
                                  wp);
     TALER_WIRE_plugin_unload (wp->wire_plugin);
+    TALER_EXCHANGEDB_fees_free (wp->af);
     GNUNET_free (wp->type);
     GNUNET_free (wp);
   }
@@ -433,9 +522,8 @@ deposit_cb (void *cls,
     return GNUNET_SYSERR;
   }
   au->row_id = row_id;
+  GNUNET_assert (NULL == au->wire);
   au->wire = json_incref ((json_t *) wire);
-  au->execution_time = GNUNET_TIME_absolute_get ();
-  (void) GNUNET_TIME_round_abs (&au->execution_time);
   TALER_JSON_hash (au->wire,
                    &au->h_wire);
   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
@@ -444,6 +532,21 @@ deposit_cb (void *cls,
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Starting aggregation under H(WTID)=%s\n",
               TALER_B2S (&au->wtid));
+
+  au->wp = find_plugin (extract_type (au->wire));
+  if (NULL == au->wp)
+    return GNUNET_SYSERR;
+
+  /* make sure we have current fees */
+  au->execution_time = GNUNET_TIME_absolute_get ();
+  (void) GNUNET_TIME_round_abs (&au->execution_time);
+  if (GNUNET_OK !=
+      update_fees (au->wp,
+                   au->execution_time,
+                   au->session))
+    return GNUNET_SYSERR;
+  au->wire_fee = au->wp->af->wire_fee;
+
   if (GNUNET_OK !=
       db_plugin->insert_aggregation_tracking (db_plugin->cls,
                                               au->session,
@@ -585,7 +688,7 @@ run_aggregation (void *cls)
   unsigned int i;
   int ret;
   const struct GNUNET_SCHEDULER_TaskContext *tc;
-  struct WirePlugin *wp;
+  struct TALER_Amount final_amount;
 
   task = NULL;
   tc = GNUNET_SCHEDULER_get_task_context ();
@@ -650,18 +753,6 @@ run_aggregation (void *cls)
     return;
   }
 
-  wp = find_plugin (extract_type (au->wire));
-  if (NULL == wp)
-  {
-    json_decref (au->wire);
-    GNUNET_free (au);
-    au = NULL;
-    db_plugin->rollback (db_plugin->cls,
-                         session);
-    GNUNET_SCHEDULER_shutdown ();
-    return;
-  }
-
   /* Now try to find other deposits to aggregate */
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Found ready deposit for %s, aggregating\n",
@@ -689,13 +780,18 @@ run_aggregation (void *cls)
     return;
   }
 
-  /* Round to the unit supported by the wire transfer method */
-  GNUNET_assert (GNUNET_SYSERR !=
-                 wp->wire_plugin->amount_round (wp->wire_plugin->cls,
-                                                &au->total_amount));
-  /* Check if after rounding down, we still have an amount to transfer */
-  if ( (0 == au->total_amount.value) &&
-       (0 == au->total_amount.fraction) )
+  /* Subtract wire transfer fee and round to the unit supported by the
+     wire transfer method; Check if after rounding down, we still have
+     an amount to transfer, and if not mark as 'tiny'. */
+  if ( (GNUNET_OK !=
+        TALER_amount_subtract (&final_amount,
+                               &au->total_amount,
+                               &au->wire_fee)) ||
+       (GNUNET_SYSERR ==
+        au->wp->wire_plugin->amount_round (au->wp->wire_plugin->cls,
+                                           &final_amount)) ||
+       ( (0 == final_amount.value) &&
+         (0 == final_amount.fraction) ) )
   {
     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                 "Aggregate value too low for transfer\n");
@@ -755,21 +851,20 @@ run_aggregation (void *cls)
   {
     char *amount_s;
 
-    amount_s = TALER_amount_to_string (&au->total_amount);
+    amount_s = TALER_amount_to_string (&final_amount);
     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                 "Preparing wire transfer of %s to %s\n",
                 amount_s,
                 TALER_B2S (&au->merchant_pub));
     GNUNET_free (amount_s);
   }
-  au->wp = wp;
-  au->ph = wp->wire_plugin->prepare_wire_transfer (wp->wire_plugin->cls,
-                                                   au->wire,
-                                                   &au->total_amount,
-                                                   exchange_base_url,
-                                                   &au->wtid,
-                                                   &prepare_cb,
-                                                   au);
+  au->ph = au->wp->wire_plugin->prepare_wire_transfer 
(au->wp->wire_plugin->cls,
+                                                       au->wire,
+                                                       &final_amount,
+                                                       exchange_base_url,
+                                                       &au->wtid,
+                                                       &prepare_cb,
+                                                       au);
   if (NULL == au->ph)
   {
     GNUNET_break (0); /* why? how to best recover? */
diff --git a/src/exchange/taler-exchange-httpd_db.c 
b/src/exchange/taler-exchange-httpd_db.c
index b9d3451..9257cbe 100644
--- a/src/exchange/taler-exchange-httpd_db.c
+++ b/src/exchange/taler-exchange-httpd_db.c
@@ -1865,6 +1865,11 @@ struct WtidTransactionContext
   struct TALER_MerchantPublicKeyP merchant_pub;
 
   /**
+   * Which method was used to wire the funds?
+   */
+  char *wire_method;
+
+  /**
    * Hash of the wire details of the merchant (identical for all
    * deposits), only valid if @e is_valid is #GNUNET_YES.
    */
@@ -1918,6 +1923,7 @@ struct WtidTransactionContext
 static void
 handle_transaction_data (void *cls,
                          const struct TALER_MerchantPublicKeyP *merchant_pub,
+                         const char *wire_method,
                          const struct GNUNET_HashCode *h_wire,
                          struct GNUNET_TIME_Absolute exec_time,
                          const struct GNUNET_HashCode *h_proposal_data,
@@ -1936,6 +1942,7 @@ handle_transaction_data (void *cls,
     ctx->merchant_pub = *merchant_pub;
     ctx->h_wire = *h_wire;
     ctx->exec_time = exec_time;
+    ctx->wire_method = GNUNET_strdup (wire_method);
     ctx->is_valid = GNUNET_YES;
     if (GNUNET_OK !=
         TALER_amount_subtract (&ctx->total,
@@ -1952,6 +1959,8 @@ handle_transaction_data (void *cls,
     if ( (0 != memcmp (&ctx->merchant_pub,
                        merchant_pub,
                        sizeof (struct TALER_MerchantPublicKeyP))) ||
+         (0 != strcmp (wire_method,
+                       ctx->wire_method)) ||
          (0 != memcmp (&ctx->h_wire,
                        h_wire,
                        sizeof (struct GNUNET_HashCode))) )
@@ -2006,6 +2015,10 @@ TEH_DB_execute_track_transfer (struct MHD_Connection 
*connection,
   struct WtidTransactionContext ctx;
   struct TALER_EXCHANGEDB_Session *session;
   struct TEH_TrackTransferDetail *wdd;
+  struct GNUNET_TIME_Absolute wire_fee_start_date;
+  struct GNUNET_TIME_Absolute wire_fee_end_date;
+  struct TALER_Amount wire_fee;
+  struct TALER_MasterSignatureP wire_fee_master_sig;
 
   if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls)))
   {
@@ -2016,6 +2029,7 @@ TEH_DB_execute_track_transfer (struct MHD_Connection 
*connection,
   ctx.is_valid = GNUNET_NO;
   ctx.wdd_head = NULL;
   ctx.wdd_tail = NULL;
+  ctx.wire_method = NULL;
   ret = TEH_plugin->lookup_wire_transfer (TEH_plugin->cls,
                                           session,
                                           wtid,
@@ -2042,10 +2056,36 @@ TEH_DB_execute_track_transfer (struct MHD_Connection 
*connection,
                                           "wtid");
     goto cleanup;
   }
+  if (GNUNET_OK !=
+      TEH_plugin->get_wire_fee (TEH_plugin->cls,
+                                session,
+                                ctx.wire_method,
+                                ctx.exec_time,
+                                &wire_fee_start_date,
+                                &wire_fee_end_date,
+                                &wire_fee,
+                                &wire_fee_master_sig))
+  {
+    GNUNET_break (0);
+    ret = TEH_RESPONSE_reply_internal_db_error (connection,
+                                               
TALER_EC_TRACK_TRANSFER_WIRE_FEE_NOT_FOUND);
+    goto cleanup;
+  }
+  if (GNUNET_OK !=
+      TALER_amount_subtract (&ctx.total,
+                             &ctx.total,
+                             &wire_fee))
+  {
+    GNUNET_break (0);
+    ret = TEH_RESPONSE_reply_internal_db_error (connection,
+                                               
TALER_EC_TRACK_TRANSFER_WIRE_FEE_INCONSISTENT);
+    goto cleanup;
+  }
   ret = TEH_RESPONSE_reply_track_transfer_details (connection,
                                                    &ctx.total,
                                                    &ctx.merchant_pub,
                                                    &ctx.h_wire,
+                                                   &wire_fee,
                                                    ctx.exec_time,
                                                    ctx.wdd_head);
  cleanup:
@@ -2056,6 +2096,7 @@ TEH_DB_execute_track_transfer (struct MHD_Connection 
*connection,
                                  wdd);
     GNUNET_free (wdd);
   }
+  GNUNET_free_non_null (ctx.wire_method);
   return ret;
 }
 
diff --git a/src/exchange/taler-exchange-httpd_responses.c 
b/src/exchange/taler-exchange-httpd_responses.c
index bae6707..1caef34 100644
--- a/src/exchange/taler-exchange-httpd_responses.c
+++ b/src/exchange/taler-exchange-httpd_responses.c
@@ -1214,6 +1214,7 @@ TEH_RESPONSE_reply_track_transaction (struct 
MHD_Connection *connection,
  * @param total total amount that was transferred
  * @param merchant_pub public key of the merchant
  * @param h_wire destination account
+ * @param wire_fee wire fee that was charged
  * @param exec_time execution time of the wire transfer
  * @param wdd_head linked list with details about the combined deposits
  * @return MHD result code
@@ -1223,6 +1224,7 @@ TEH_RESPONSE_reply_track_transfer_details (struct 
MHD_Connection *connection,
                                            const struct TALER_Amount *total,
                                            const struct 
TALER_MerchantPublicKeyP *merchant_pub,
                                            const struct GNUNET_HashCode 
*h_wire,
+                                           const struct TALER_Amount *wire_fee,
                                            struct GNUNET_TIME_Absolute 
exec_time,
                                            const struct 
TEH_TrackTransferDetail *wdd_head)
 {
@@ -1261,6 +1263,8 @@ TEH_RESPONSE_reply_track_transfer_details (struct 
MHD_Connection *connection,
   wdp.purpose.size = htonl (sizeof (struct TALER_WireDepositDataPS));
   TALER_amount_hton (&wdp.total,
                      total);
+  TALER_amount_hton (&wdp.wire_fee,
+                     wire_fee);
   wdp.merchant_pub = *merchant_pub;
   wdp.h_wire = *h_wire;
   GNUNET_CRYPTO_hash_context_finish (hash_context,
@@ -1270,8 +1274,9 @@ TEH_RESPONSE_reply_track_transfer_details (struct 
MHD_Connection *connection,
                &sig);
   return TEH_RESPONSE_reply_json_pack (connection,
                                        MHD_HTTP_OK,
-                                       "{s:o, s:o, s:o, s:o, s:o, s:o, s:o}",
+                                       "{s:o, s:o, s:o, s:o, s:o, s:o, s:o, 
s:o}",
                                        "total", TALER_JSON_from_amount (total),
+                                       "wire_fee", TALER_JSON_from_amount 
(wire_fee),
                                        "merchant_pub", 
GNUNET_JSON_from_data_auto (merchant_pub),
                                        "H_wire", GNUNET_JSON_from_data_auto 
(h_wire),
                                        "execution_time", 
GNUNET_JSON_from_time_abs (exec_time),
diff --git a/src/exchange/taler-exchange-httpd_responses.h 
b/src/exchange/taler-exchange-httpd_responses.h
index 17abd7e..179ae00 100644
--- a/src/exchange/taler-exchange-httpd_responses.h
+++ b/src/exchange/taler-exchange-httpd_responses.h
@@ -399,6 +399,7 @@ struct TEH_TrackTransferDetail
  * @param total total amount that was transferred
  * @param merchant_pub public key of the merchant
  * @param h_wire destination account
+ * @param wire_fee wire fee that was charged
  * @param exec_time execution time of the wire transfer
  * @param wdd_head linked list with details about the combined deposits
  * @return MHD result code
@@ -408,6 +409,7 @@ TEH_RESPONSE_reply_track_transfer_details (struct 
MHD_Connection *connection,
                                            const struct TALER_Amount *total,
                                            const struct 
TALER_MerchantPublicKeyP *merchant_pub,
                                            const struct GNUNET_HashCode 
*h_wire,
+                                           const struct TALER_Amount *wire_fee,
                                            struct GNUNET_TIME_Absolute 
exec_time,
                                            const struct 
TEH_TrackTransferDetail *wdd_head);
 
diff --git a/src/exchange/test-taler-exchange-aggregator-postgres.conf 
b/src/exchange/test-taler-exchange-aggregator-postgres.conf
index 4aa74b0..e70a933 100644
--- a/src/exchange/test-taler-exchange-aggregator-postgres.conf
+++ b/src/exchange/test-taler-exchange-aggregator-postgres.conf
@@ -29,6 +29,20 @@ DB_CONN_STR = postgres:///talercheck
 # Enable 'test' for testing of the actual coin operations.
 ENABLE = YES
 
+# Fees for the forseeable future...
+# If you see this after 2017, update to match the next 10 years...
+WIRE-FEE-2017 = EUR:0.01
+WIRE-FEE-2018 = EUR:0.01
+WIRE-FEE-2019 = EUR:0.01
+WIRE-FEE-2020 = EUR:0.01
+WIRE-FEE-2021 = EUR:0.01
+WIRE-FEE-2022 = EUR:0.01
+WIRE-FEE-2023 = EUR:0.01
+WIRE-FEE-2024 = EUR:0.01
+WIRE-FEE-2025 = EUR:0.01
+WIRE-FEE-2026 = EUR:0.01
+
+
 [exchange-wire-outgoing-test]
 # What is the main website of the bank?
 BANK_URI = "http://localhost:8082/";
diff --git a/src/exchange/test_taler_exchange_aggregator.c 
b/src/exchange/test_taler_exchange_aggregator.c
index 6bd0d70..5a3974f 100644
--- a/src/exchange/test_taler_exchange_aggregator.c
+++ b/src/exchange/test_taler_exchange_aggregator.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  (C) 2016 Inria and GNUnet e.V.
+  (C) 2016, 2017 Inria and GNUnet e.V.
 
   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
@@ -621,7 +621,7 @@ run_test ()
       .details.expect_transaction.debit_account = 3,
       .details.expect_transaction.credit_account = 4,
       .details.expect_transaction.exchange_base_url = 
"https://exchange.taler.net/";,
-      .details.expect_transaction.amount = "EUR:0.9"
+      .details.expect_transaction.amount = "EUR:0.89"
     },
 
     {
@@ -668,7 +668,7 @@ run_test ()
       .details.expect_transaction.debit_account = 3,
       .details.expect_transaction.credit_account = 4,
       .details.expect_transaction.exchange_base_url = 
"https://exchange.taler.net/";,
-      .details.expect_transaction.amount = "EUR:1.8"
+      .details.expect_transaction.amount = "EUR:1.79"
     },
 
     {
@@ -714,7 +714,7 @@ run_test ()
       .details.expect_transaction.debit_account = 3,
       .details.expect_transaction.credit_account = 4,
       .details.expect_transaction.exchange_base_url = 
"https://exchange.taler.net/";,
-      .details.expect_transaction.amount = "EUR:0.9"
+      .details.expect_transaction.amount = "EUR:0.89"
     },
     {
       .opcode = OPCODE_EXPECT_TRANSACTION,
@@ -722,7 +722,7 @@ run_test ()
       .details.expect_transaction.debit_account = 3,
       .details.expect_transaction.credit_account = 4,
       .details.expect_transaction.exchange_base_url = 
"https://exchange.taler.net/";,
-      .details.expect_transaction.amount = "EUR:0.9"
+      .details.expect_transaction.amount = "EUR:0.89"
     },
     {
       .opcode = OPCODE_EXPECT_TRANSACTION,
@@ -730,7 +730,7 @@ run_test ()
       .details.expect_transaction.debit_account = 3,
       .details.expect_transaction.credit_account = 5,
       .details.expect_transaction.exchange_base_url = 
"https://exchange.taler.net/";,
-      .details.expect_transaction.amount = "EUR:0.9"
+      .details.expect_transaction.amount = "EUR:0.89"
     },
     {
       .opcode = OPCODE_EXPECT_TRANSACTIONS_EMPTY,
@@ -779,7 +779,7 @@ run_test ()
       .details.expect_transaction.debit_account = 3,
       .details.expect_transaction.credit_account = 4,
       .details.expect_transaction.exchange_base_url = 
"https://exchange.taler.net/";,
-      .details.expect_transaction.amount = "EUR:0.2"
+      .details.expect_transaction.amount = "EUR:0.19"
     },
 
     /* test picking all deposits at earliest deadline */
@@ -824,7 +824,7 @@ run_test ()
       .details.expect_transaction.debit_account = 3,
       .details.expect_transaction.credit_account = 4,
       .details.expect_transaction.exchange_base_url = 
"https://exchange.taler.net/";,
-      .details.expect_transaction.amount = "EUR:0.2"
+      .details.expect_transaction.amount = "EUR:0.19"
     },
 
     /* Test NEVER running 'tiny' unless they make up minimum unit */
@@ -894,7 +894,7 @@ run_test ()
       .details.deposit.merchant_name = "bob",
       .details.deposit.merchant_account = 4,
       .details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 0s */
-      .details.deposit.amount_with_fee = "EUR:0.102",
+      .details.deposit.amount_with_fee = "EUR:0.112",
       .details.deposit.deposit_fee = "EUR:0.1"
     },
     {
@@ -934,7 +934,7 @@ run_test ()
       .details.deposit.merchant_name = "bob",
       .details.deposit.merchant_account = 4,
       .details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 0s */
-      .details.deposit.amount_with_fee = "EUR:0.109",
+      .details.deposit.amount_with_fee = "EUR:0.119",
       .details.deposit.deposit_fee = "EUR:0.1"
     },
     {
@@ -969,7 +969,7 @@ run_test ()
       .details.expect_transaction.debit_account = 3,
       .details.expect_transaction.credit_account = 4,
       .details.expect_transaction.exchange_base_url = 
"https://exchange.taler.net/";,
-      .details.expect_transaction.amount = "EUR:0.02"
+      .details.expect_transaction.amount = "EUR:0.01"
     },
 
     /* Test that aggregation would happen fully if wire deadline is long */
@@ -1027,7 +1027,7 @@ run_test ()
       .details.expect_transaction.debit_account = 3,
       .details.expect_transaction.credit_account = 4,
       .details.expect_transaction.exchange_base_url = 
"https://exchange.taler.net/";,
-      .details.expect_transaction.amount = "EUR:0.04"
+      .details.expect_transaction.amount = "EUR:0.03"
     },
 
 
@@ -1087,7 +1087,7 @@ run_test ()
       .details.expect_transaction.debit_account = 3,
       .details.expect_transaction.credit_account = 4,
       .details.expect_transaction.exchange_base_url = 
"https://exchange.taler.net/";,
-      .details.expect_transaction.amount = "EUR:0.02"
+      .details.expect_transaction.amount = "EUR:0.01"
     },
 
     /* Everything tested, terminate with success */
@@ -1203,6 +1203,7 @@ main (int argc,
 {
   const char *plugin_name;
   char *testname;
+  struct GNUNET_OS_Process *proc;
   struct GNUNET_CONFIGURATION_Handle *cfg;
   struct GNUNET_SIGNAL_Context *shc_chld;
 
@@ -1225,6 +1226,21 @@ main (int argc,
   GNUNET_log_setup ("test_taler_exchange_aggregator",
                     "WARNING",
                     NULL);
+  proc = GNUNET_OS_start_process (GNUNET_NO,
+                                  GNUNET_OS_INHERIT_STD_ALL,
+                                  NULL, NULL, NULL,
+                                  "taler-exchange-keyup",
+                                  "taler-exchange-keyup",
+                                  "-c", config_filename,
+                                  NULL);
+  if (NULL == proc)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+               "Failed to run `taler-exchange-keyup`, is your PATH 
correct?\n");
+    return 77;
+  }
+  GNUNET_OS_process_wait (proc);
+  GNUNET_OS_process_destroy (proc);
   cfg = GNUNET_CONFIGURATION_create ();
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_parse (cfg,
diff --git a/src/exchangedb/exchangedb.conf b/src/exchangedb/exchangedb.conf
index 4640507..73e1603 100644
--- a/src/exchangedb/exchangedb.conf
+++ b/src/exchangedb/exchangedb.conf
@@ -11,4 +11,4 @@ AUDITOR_BASE_DIR = ${TALER_DATA_HOME}/auditors/
 # the merchant per wire transfer.  The directory is expected to
 # contain files "$METHOD.fee" with the cost structure, where
 # $METHOD corresponds to a wire transfer method.
-WIREFEE_BASE_DIR = ${TALER_DATA_HOME}/wirefees/
+WIREFEE_BASE_DIR = ${TALER_DATA_HOME}/exchange/wirefees/
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c 
b/src/exchangedb/plugin_exchangedb_postgres.c
index ebca07f..feb03f9 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -216,6 +216,8 @@ postgres_drop_tables (void *cls)
   SQLEXEC_ (conn,
             "DROP TABLE IF EXISTS aggregation_tracking;");
   SQLEXEC_ (conn,
+            "DROP TABLE IF EXISTS wire_fee;");
+  SQLEXEC_ (conn,
             "DROP TABLE IF EXISTS deposits;");
   SQLEXEC_ (conn,
             "DROP TABLE IF EXISTS refresh_out;");
@@ -472,6 +474,23 @@ postgres_create_tables (void *cls)
   SQLEXEC_INDEX("CREATE INDEX aggregation_tracking_wtid_index "
                 "ON aggregation_tracking(wtid_raw)");
 
+
+  /* Table for the wire fees. */
+  SQLEXEC("CREATE TABLE IF NOT EXISTS wire_fee "
+          "(wire_method VARCHAR NOT NULL"
+          ",start_date INT8 NOT NULL"
+          ",end_date INT8 NOT NULL"
+          ",wire_fee_val INT8 NOT NULL"
+          ",wire_fee_frac INT4 NOT NULL"
+          ",wire_fee_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
+          ",master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)"
+          ",PRIMARY KEY (wire_method, start_date)" /* this combo must be 
unique */
+          ")");
+  /* Index for lookup_transactions statement on wtid */
+  SQLEXEC_INDEX("CREATE INDEX aggregation_tracking_wtid_index "
+                "ON aggregation_tracking(wtid_raw)");
+
+
   /* This table contains the pre-commit data for
      wire transfers the exchange is about to execute. */
   SQLEXEC("CREATE TABLE IF NOT EXISTS prewire "
@@ -1193,6 +1212,7 @@ postgres_prepare (PGconn *db_conn)
   PREPARE ("lookup_transactions",
            "SELECT"
            " deposits.h_proposal_data"
+           ",deposits.wire"
            ",deposits.h_wire"
            ",deposits.coin_pub"
            ",deposits.merchant_pub"
@@ -1241,6 +1261,35 @@ postgres_prepare (PGconn *db_conn)
            "($1, $2, $3)",
            3, NULL);
 
+  /* Used in #postgres_get_wire_fee() */
+  PREPARE ("get_wire_fee",
+           "SELECT "
+           " start_date"
+           ",end_date"
+           ",wire_fee_val"
+           ",wire_fee_frac"
+           ",wire_fee_curr"
+           ",master_sig"
+           " FROM wire_fee"
+           " WHERE wire_method=$1"
+           " AND start_date <= $2"
+           " AND end_date > $2",
+           2, NULL);
+
+  /* Used in #postgres_insert_wire_fee */
+  PREPARE ("insert_wire_fee",
+           "INSERT INTO wire_fee "
+           "(wire_method"
+           ",start_date"
+           ",end_date"
+           ",wire_fee_val"
+           ",wire_fee_frac"
+           ",wire_fee_curr"
+           ",master_sig"
+           ") VALUES "
+           "($1, $2, $3, $4, $5, $6, $7)",
+           7, NULL);
+
 
   /* Used in #postgres_wire_prepare_data_insert() to store
      wire transfer information before actually committing it with the bank */
@@ -3980,15 +4029,19 @@ postgres_lookup_wire_transfer (void *cls,
     struct GNUNET_TIME_Absolute exec_time;
     struct TALER_Amount amount_with_fee;
     struct TALER_Amount deposit_fee;
+    json_t *wire;
+    json_t *t;
+    const char *wire_method;
     struct GNUNET_PQ_ResultSpec rs[] = {
       GNUNET_PQ_result_spec_auto_from_type ("h_proposal_data", 
&h_proposal_data),
+      TALER_PQ_result_spec_json ("wire", &wire),
       GNUNET_PQ_result_spec_auto_from_type ("h_wire", &h_wire),
       GNUNET_PQ_result_spec_auto_from_type ("coin_pub", &coin_pub),
       GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", &merchant_pub),
       GNUNET_PQ_result_spec_absolute_time ("execution_time", &exec_time),
       TALER_PQ_result_spec_amount ("amount_with_fee", &amount_with_fee),
       TALER_PQ_result_spec_amount ("fee_deposit", &deposit_fee),
-       GNUNET_PQ_result_spec_end
+      GNUNET_PQ_result_spec_end
     };
     if (GNUNET_OK !=
         GNUNET_PQ_extract_result (result,
@@ -3999,8 +4052,23 @@ postgres_lookup_wire_transfer (void *cls,
       PQclear (result);
       return GNUNET_SYSERR;
     }
+    t = json_object_get (wire, "type");
+    if (NULL == t)
+    {
+      GNUNET_break (0);
+      PQclear (result);
+      return GNUNET_SYSERR;
+    }
+    wire_method = json_string_value (t);
+    if (NULL == wire_method)
+    {
+      GNUNET_break (0);
+      PQclear (result);
+      return GNUNET_SYSERR;
+    }
     cb (cb_cls,
         &merchant_pub,
+        wire_method,
         &h_wire,
         exec_time,
         &h_proposal_data,
@@ -4211,6 +4279,170 @@ postgres_insert_aggregation_tracking (void *cls,
 
 
 /**
+ * Obtain wire fee from database.
+ *
+ * @param cls closure
+ * @param session database connection
+ * @param type type of wire transfer the fee applies for
+ * @param date for which date do we want the fee?
+ * @param[out] start_date when does the fee go into effect
+ * @param[out] end_date when does the fee end being valid
+ * @param[out] wire_fee how high is the wire transfer fee
+ * @param[out] master_sig signature over the above by the exchange master key
+ * @return #GNUNET_OK on success, #GNUNET_NO if no fee is known
+ *         #GNUNET_SYSERR on failure
+ */
+static int
+postgres_get_wire_fee (void *cls,
+                       struct TALER_EXCHANGEDB_Session *session,
+                       const char *type,
+                       struct GNUNET_TIME_Absolute date,
+                       struct GNUNET_TIME_Absolute *start_date,
+                       struct GNUNET_TIME_Absolute *end_date,
+                       struct TALER_Amount *wire_fee,
+                       struct TALER_MasterSignatureP *master_sig)
+{
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (type),
+    GNUNET_PQ_query_param_absolute_time (&date),
+    GNUNET_PQ_query_param_end
+  };
+  struct GNUNET_PQ_ResultSpec rs[] = {
+    GNUNET_PQ_result_spec_absolute_time ("start_date", start_date),
+    GNUNET_PQ_result_spec_absolute_time ("end_date", end_date),
+    TALER_PQ_result_spec_amount ("wire_fee", wire_fee),
+    GNUNET_PQ_result_spec_auto_from_type ("master_sig", master_sig),
+    GNUNET_PQ_result_spec_end
+  };
+  PGresult *result;
+  int nrows;
+
+  result = GNUNET_PQ_exec_prepared (session->conn,
+                                    "get_wire_fee",
+                                    params);
+  if (PGRES_TUPLES_OK !=
+      PQresultStatus (result))
+  {
+    BREAK_DB_ERR (result);
+    PQclear (result);
+    return GNUNET_SYSERR;
+  }
+  nrows = PQntuples (result);
+  if (0 == nrows)
+  {
+    /* no matches found */
+    PQclear (result);
+    return GNUNET_NO;
+  }
+  if (1 != nrows)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (GNUNET_OK !=
+      GNUNET_PQ_extract_result (result,
+                                rs,
+                                0))
+  {
+    PQclear (result);
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  PQclear (result);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Insert wire transfer fee into database.
+ *
+ * @param cls closure
+ * @param session database connection
+ * @param type type of wire transfer this fee applies for
+ * @param start_date when does the fee go into effect
+ * @param end_date when does the fee end being valid
+ * @param wire_fee how high is the wire transfer fee
+ * @param master_sig signature over the above by the exchange master key
+ * @return #GNUNET_OK on success, #GNUNET_NO if the record exists,
+ *         #GNUNET_SYSERR on failure
+ */
+static int
+postgres_insert_wire_fee (void *cls,
+                          struct TALER_EXCHANGEDB_Session *session,
+                          const char *type,
+                          struct GNUNET_TIME_Absolute start_date,
+                          struct GNUNET_TIME_Absolute end_date,
+                          const struct TALER_Amount *wire_fee,
+                          const struct TALER_MasterSignatureP *master_sig)
+{
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_string (type),
+    GNUNET_PQ_query_param_absolute_time (&start_date),
+    GNUNET_PQ_query_param_absolute_time (&end_date),
+    TALER_PQ_query_param_amount (wire_fee),
+    GNUNET_PQ_query_param_auto_from_type (master_sig),
+    GNUNET_PQ_query_param_end
+  };
+  PGresult *result;
+  struct TALER_Amount wf;
+  struct TALER_MasterSignatureP sig;
+  struct GNUNET_TIME_Absolute sd;
+  struct GNUNET_TIME_Absolute ed;
+
+  if (GNUNET_OK ==
+      postgres_get_wire_fee (cls,
+                             session,
+                             type,
+                             start_date,
+                             &sd,
+                             &ed,
+                             &wf,
+                             &sig))
+  {
+    if (0 != memcmp (&sig,
+                     master_sig,
+                     sizeof (sig)))
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
+    }
+    if (0 != TALER_amount_cmp (wire_fee,
+                               &wf))
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
+    }
+    if ( (sd.abs_value_us != start_date.abs_value_us) ||
+         (ed.abs_value_us != end_date.abs_value_us) )
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
+    }
+    /* equal record already exists */
+    return GNUNET_NO;
+  }
+
+  result = GNUNET_PQ_exec_prepared (session->conn,
+                                   "insert_wire_fee",
+                                   params);
+  if (PGRES_COMMAND_OK != PQresultStatus (result))
+  {
+    BREAK_DB_ERR (result);
+    PQclear (result);
+    return GNUNET_SYSERR;
+  }
+  if (0 != strcmp ("1", PQcmdTuples (result)))
+  {
+    GNUNET_break (0);
+    PQclear (result);
+    return GNUNET_SYSERR;
+  }
+  PQclear (result);
+  return GNUNET_OK;
+}
+
+
+/**
  * Function called to insert wire transfer commit data into the DB.
  *
  * @param cls closure
@@ -5090,6 +5322,8 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
   plugin->lookup_wire_transfer = &postgres_lookup_wire_transfer;
   plugin->wire_lookup_deposit_wtid = &postgres_wire_lookup_deposit_wtid;
   plugin->insert_aggregation_tracking = &postgres_insert_aggregation_tracking;
+  plugin->insert_wire_fee = &postgres_insert_wire_fee;
+  plugin->get_wire_fee = &postgres_get_wire_fee;
   plugin->wire_prepare_data_insert = &postgres_wire_prepare_data_insert;
   plugin->wire_prepare_data_mark_finished = 
&postgres_wire_prepare_data_mark_finished;
   plugin->wire_prepare_data_get = &postgres_wire_prepare_data_get;
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index c37a590..a29e045 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -783,6 +783,7 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
 static void
 cb_wt_never (void *cls,
              const struct TALER_MerchantPublicKeyP *merchant_pub,
+             const char *wire_method,
              const struct GNUNET_HashCode *h_wire,
              struct GNUNET_TIME_Absolute exec_time,
              const struct GNUNET_HashCode *h_proposal_data,
@@ -825,6 +826,7 @@ static struct TALER_WireTransferIdentifierRawP wtid_wt;
 static void
 cb_wt_check (void *cls,
              const struct TALER_MerchantPublicKeyP *merchant_pub,
+             const char *wire_method,
              const struct GNUNET_HashCode *h_wire,
              struct GNUNET_TIME_Absolute exec_time,
              const struct GNUNET_HashCode *h_proposal_data,
@@ -836,6 +838,8 @@ cb_wt_check (void *cls,
   GNUNET_assert (0 == memcmp (merchant_pub,
                               &merchant_pub_wt,
                               sizeof (struct TALER_MerchantPublicKeyP)));
+  GNUNET_assert (0 == strcmp (wire_method,
+                              "SEPA"));
   GNUNET_assert (0 == memcmp (h_wire,
                               &h_wire_wt,
                               sizeof (struct GNUNET_HashCode)));
diff --git a/src/include/taler_error_codes.h b/src/include/taler_error_codes.h
index 770a8ad..4b90281 100644
--- a/src/include/taler_error_codes.h
+++ b/src/include/taler_error_codes.h
@@ -779,6 +779,19 @@ enum TALER_ErrorCode
    */
   TALER_EC_TRACK_TRANSFER_WTID_NOT_FOUND = 1702,
 
+  /**
+   * The exchange did not find information about the wire transfer
+   * fees it charged. This response is
+   * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+   */
+  TALER_EC_TRACK_TRANSFER_WIRE_FEE_NOT_FOUND = 1703,
+
+  /**
+   * The exchange found a wire fee that was above the total transfer
+   * value (and thus could not have been charged). This response is
+   * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR.
+   */
+  TALER_EC_TRACK_TRANSFER_WIRE_FEE_INCONSISTENT = 1704,
 
   /**
    * The exchange found internally inconsistent fee data when
@@ -1145,7 +1158,7 @@ enum TALER_ErrorCode
 
   /**
    * The backend encountered an error while trying to store the
-   * h_proposal_data into the database. 
+   * h_proposal_data into the database.
    * The response is provided with HTTP status code 
MHD_HTTP_INTERNAL_SERVER_ERROR.
    */
   TALER_EC_PROPOSAL_STORE_DB_ERROR = 2501,
diff --git a/src/include/taler_exchange_service.h 
b/src/include/taler_exchange_service.h
index 05256dd..3ac4069 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -1130,6 +1130,7 @@ struct TALER_EXCHANGE_TrackTransferHandle;
  * @param execution_time time when the exchange claims to have performed the 
wire transfer
  * @param total_amount total amount of the wire transfer, or NULL if the 
exchange could
  *             not provide any @a wtid (set only if @a http_status is 
#MHD_HTTP_OK)
+ * @param wire_fee wire fee that was charged by the exchange
  * @param details_length length of the @a details array
  * @param details array with details about the combined transactions
  */
@@ -1142,6 +1143,7 @@ typedef void
                                         const struct GNUNET_HashCode *h_wire,
                                         struct GNUNET_TIME_Absolute 
execution_time,
                                         const struct TALER_Amount 
*total_amount,
+                                        const struct TALER_Amount *wire_fee,
                                         unsigned int details_length,
                                         const struct 
TALER_TrackTransferDetails *details);
 
diff --git a/src/include/taler_exchangedb_plugin.h 
b/src/include/taler_exchangedb_plugin.h
index fa0c48a..e7ba06f 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -762,6 +762,7 @@ typedef void
  *
  * @param cls closure
  * @param merchant_pub public key of the merchant (should be same for all 
callbacks with the same @e cls)
+ * @param wire_method which wire plugin was used for the transfer?
  * @param h_wire hash of wire transfer details of the merchant (should be same 
for all callbacks with the same @e cls)
  * @param exec_time execution time of the wire transfer (should be same for 
all callbacks with the same @e cls)
  * @param h_proposal_data which proposal was this payment about
@@ -772,6 +773,7 @@ typedef void
 typedef void
 (*TALER_EXCHANGEDB_WireTransferDataCallback)(void *cls,
                                              const struct 
TALER_MerchantPublicKeyP *merchant_pub,
+                                             const char *wire_method,
                                              const struct GNUNET_HashCode 
*h_wire,
                                              struct GNUNET_TIME_Absolute 
exec_time,
                                              const struct GNUNET_HashCode 
*h_proposal_data,
@@ -1521,6 +1523,54 @@ struct TALER_EXCHANGEDB_Plugin
 
 
   /**
+   * Insert wire transfer fee into database.
+   *
+   * @param cls closure
+   * @param session database connection
+   * @param wire_method which wire method is the fee about?
+   * @param start_date when does the fee go into effect
+   * @param end_date when does the fee end being valid
+   * @param wire_fee how high is the wire transfer fee
+   * @param master_sig signature over the above by the exchange master key
+   * @return #GNUNET_OK on success, #GNUNET_NO if the record exists,
+   *         #GNUNET_SYSERR on failure
+   */
+  int
+  (*insert_wire_fee)(void *cls,
+                     struct TALER_EXCHANGEDB_Session *session,
+                     const char *wire_method,
+                     struct GNUNET_TIME_Absolute start_date,
+                     struct GNUNET_TIME_Absolute end_date,
+                     const struct TALER_Amount *wire_fee,
+                     const struct TALER_MasterSignatureP *master_sig);
+
+
+  /**
+   * Obtain wire fee from database.
+   *
+   * @param cls closure
+   * @param session database connection
+   * @param type type of wire transfer the fee applies for
+   * @param date for which date do we want the fee?
+   * @param[out] start_date when does the fee go into effect
+   * @param[out] end_date when does the fee end being valid
+   * @param[out] wire_fee how high is the wire transfer fee
+   * @param[out] master_sig signature over the above by the exchange master key
+   * @return #GNUNET_OK on success, #GNUNET_NO if no fee is known
+   *         #GNUNET_SYSERR on failure
+   */
+  int
+  (*get_wire_fee) (void *cls,
+                   struct TALER_EXCHANGEDB_Session *session,
+                   const char *type,
+                   struct GNUNET_TIME_Absolute date,
+                   struct GNUNET_TIME_Absolute *start_date,
+                   struct GNUNET_TIME_Absolute *end_date,
+                   struct TALER_Amount *wire_fee,
+                   struct TALER_MasterSignatureP *master_sig);
+
+
+  /**
    * Function called to insert wire transfer commit data into the DB.
    *
    * @param cls closure
diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h
index 3596739..8659deb 100644
--- a/src/include/taler_signatures.h
+++ b/src/include/taler_signatures.h
@@ -1004,6 +1004,11 @@ struct TALER_WireDepositDataPS
   struct TALER_AmountNBO total;
 
   /**
+   * Wire fee that was charged.
+   */
+  struct TALER_AmountNBO wire_fee;
+
+  /**
    * Public key of the merchant (for all aggregated transactions).
    */
   struct TALER_MerchantPublicKeyP merchant_pub;

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



reply via email to

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