gnunet-svn
[Top][All Lists]
Advanced

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

[taler-exchange] 01/02: -exchange_api_batch_deposit.c compiles


From: gnunet
Subject: [taler-exchange] 01/02: -exchange_api_batch_deposit.c compiles
Date: Fri, 01 Jul 2022 07:22:41 +0200

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

grothoff pushed a commit to branch master
in repository exchange.

commit 085e40bc562343221bceb6fc4dc9aba8e32a27e3
Author: Christian Grothoff <grothoff@gnunet.org>
AuthorDate: Fri Jul 1 07:08:13 2022 +0200

    -exchange_api_batch_deposit.c compiles
---
 contrib/gana                                       |   2 +-
 doc/prebuilt                                       |   2 +-
 src/auditor/taler-helper-auditor-reserves.c        |   4 +-
 src/exchange/taler-exchange-httpd_common_deposit.c |   6 +-
 src/exchange/taler-exchange-httpd_keys.c           |   4 +-
 src/exchange/taler-exchange-httpd_purses_create.c  |   4 +-
 src/include/taler_exchange_service.h               | 138 +++++++
 src/lib/Makefile.am                                |   1 +
 ..._api_deposit.c => exchange_api_batch_deposit.c} | 421 +++++++++++----------
 src/lib/exchange_api_common.c                      |  62 +++
 src/lib/exchange_api_common.h                      |  20 +
 src/lib/exchange_api_deposit.c                     |  81 +---
 src/lib/exchange_api_handle.c                      |   2 +-
 src/lib/exchange_api_purse_create_with_deposit.c   |   4 +-
 src/lib/exchange_api_purse_create_with_merge.c     |   4 +-
 15 files changed, 461 insertions(+), 294 deletions(-)

diff --git a/contrib/gana b/contrib/gana
index ce57f1bb..75c838e7 160000
--- a/contrib/gana
+++ b/contrib/gana
@@ -1 +1 @@
-Subproject commit ce57f1bb32a657c0e479a13401339c9899b1c898
+Subproject commit 75c838e74c41bf9a6c02cdfe8109a444056bf26d
diff --git a/doc/prebuilt b/doc/prebuilt
index 1ed97b23..74d9c44e 160000
--- a/doc/prebuilt
+++ b/doc/prebuilt
@@ -1 +1 @@
-Subproject commit 1ed97b23f19c80fa84b21a5eb0c686d5491e8ec6
+Subproject commit 74d9c44ebc257a3d8b9c2c0a806508bd0cc5269a
diff --git a/src/auditor/taler-helper-auditor-reserves.c 
b/src/auditor/taler-helper-auditor-reserves.c
index 54d3db7c..c6c4d3ad 100644
--- a/src/auditor/taler-helper-auditor-reserves.c
+++ b/src/auditor/taler-helper-auditor-reserves.c
@@ -1283,8 +1283,8 @@ handle_purse_deposits (
   struct ReserveContext *rc = cls;
   const char *base_url
     = (NULL == deposit->exchange_base_url)
-    ? TALER_ARL_exchange_url
-    : deposit->exchange_base_url;
+      ? TALER_ARL_exchange_url
+      : deposit->exchange_base_url;
   enum GNUNET_DB_QueryStatus qs;
   struct TALER_Amount amount_minus_fee;
   struct TALER_Amount new_balance;
diff --git a/src/exchange/taler-exchange-httpd_common_deposit.c 
b/src/exchange/taler-exchange-httpd_common_deposit.c
index cfa15fcc..694dfa41 100644
--- a/src/exchange/taler-exchange-httpd_common_deposit.c
+++ b/src/exchange/taler-exchange-httpd_common_deposit.c
@@ -214,8 +214,8 @@ TEH_common_deposit_check_purse_deposit (
                                         MHD_HTTP_FORBIDDEN,
                                         
TALER_EC_EXCHANGE_PURSE_DEPOSIT_COIN_SIGNATURE_INVALID,
                                         TEH_base_url))
-      ? GNUNET_NO
-      : GNUNET_SYSERR;
+           ? GNUNET_NO
+           : GNUNET_SYSERR;
   }
 
   /* Check and verify the age restriction. */
@@ -301,7 +301,7 @@ if (0 >
                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
                                         TALER_EC_GENERIC_DB_COMMIT_FAILED,
                                         "make_coin_known"))
-             ? GNUNET_NO : GNUNET_SYSERR;
+           ? GNUNET_NO : GNUNET_SYSERR;
   }
   if (qs < 0)
     return (MHD_YES == mhd_ret) ? GNUNET_NO : GNUNET_SYSERR;
diff --git a/src/exchange/taler-exchange-httpd_keys.c 
b/src/exchange/taler-exchange-httpd_keys.c
index 65fe0f31..b1fa2cbc 100644
--- a/src/exchange/taler-exchange-httpd_keys.c
+++ b/src/exchange/taler-exchange-httpd_keys.c
@@ -2216,10 +2216,10 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
           switch (meta.cipher)
           {
           case TALER_DENOMINATION_RSA:
-            cipher = age_restricted ? "RSA+age_restricted": "RSA";
+            cipher = age_restricted ? "RSA+age_restricted" : "RSA";
             break;
           case TALER_DENOMINATION_CS:
-            cipher = age_restricted ? "CS+age_restricted": "CS";
+            cipher = age_restricted ? "CS+age_restricted" : "CS";
             break;
           default:
             GNUNET_assert (false);
diff --git a/src/exchange/taler-exchange-httpd_purses_create.c 
b/src/exchange/taler-exchange-httpd_purses_create.c
index b6eea05f..9cabdb1a 100644
--- a/src/exchange/taler-exchange-httpd_purses_create.c
+++ b/src/exchange/taler-exchange-httpd_purses_create.c
@@ -458,8 +458,8 @@ parse_coin (struct MHD_Connection *connection,
                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
                                         TALER_EC_GENERIC_FAILED_COMPUTE_AMOUNT,
                                         "total deposit contribution"))
-      ? GNUNET_NO
-      : GNUNET_SYSERR;
+           ? GNUNET_NO
+           : GNUNET_SYSERR;
   }
   return GNUNET_OK;
 }
diff --git a/src/include/taler_exchange_service.h 
b/src/include/taler_exchange_service.h
index bd2a5bca..6c3ad7a0 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -1047,6 +1047,144 @@ void
 TALER_EXCHANGE_deposit_cancel (struct TALER_EXCHANGE_DepositHandle *deposit);
 
 
+/**
+ * @brief A Batch Deposit Handle
+ */
+struct TALER_EXCHANGE_BatchDepositHandle;
+
+
+/**
+ * Structure with information about a batch deposit
+ * operation's result.
+ */
+struct TALER_EXCHANGE_BatchDepositResult
+{
+  /**
+   * HTTP response data
+   */
+  struct TALER_EXCHANGE_HttpResponse hr;
+
+  union
+  {
+
+    /**
+     * Information returned if the HTTP status is
+     * #MHD_HTTP_OK.
+     */
+    struct
+    {
+      /**
+       * Time when the exchange generated the batch deposit confirmation
+       */
+      struct GNUNET_TIME_Timestamp deposit_timestamp;
+
+      /**
+       * Array of signatures provided by the exchange
+       */
+      const struct TALER_ExchangeSignatureP *exchange_sigs;
+
+      /**
+       * exchange key used to sign @a exchange_sig.
+       */
+      const struct TALER_ExchangePublicKeyP *exchange_pub;
+
+      /**
+       * Base URL for looking up wire transfers, or
+       * NULL to use the default base URL.
+       */
+      const char *transaction_base_url;
+
+      /**
+       * Length of the @e exchange_sigs array.
+       */
+      unsigned int num_signatures;
+
+    } success;
+
+    /**
+     * Information returned if the HTTP status is
+     * #MHD_HTTP_CONFLICT.
+     */
+    struct
+    {
+      /* TODO: returning full details is not implemented */
+    } conflict;
+
+  } details;
+};
+
+
+/**
+ * Callbacks of this type are used to serve the result of submitting a
+ * deposit permission request to a exchange.
+ *
+ * @param cls closure
+ * @param dr deposit response details
+ */
+typedef void
+(*TALER_EXCHANGE_BatchDepositResultCallback) (
+  void *cls,
+  const struct TALER_EXCHANGE_BatchDepositResult *dr);
+
+
+/**
+ * Submit a batch of deposit permissions to the exchange and get the
+ * exchange's response.  This API is typically used by a merchant.  Note that
+ * while we return the response verbatim to the caller for further processing,
+ * we do already verify that the response is well-formed (i.e. that signatures
+ * included in the response are all valid).  If the exchange's reply is not
+ * well-formed, we return an HTTP status code of zero to @a cb.
+ *
+ * We also verify that the @a cdds.coin_sig are valid for this deposit
+ * request, and that the @a cdds.ub_sig are a valid signatures for @a
+ * coin_pub.  Also, the @a exchange must be ready to operate (i.e.  have
+ * finished processing the /keys reply).  If either check fails, we do
+ * NOT initiate the transaction with the exchange and instead return NULL.
+ *
+ * @param exchange the exchange handle; the exchange must be ready to operate
+ * @param dcd details about the contract the deposit is for
+ * @param num_cdds length of the @a cdds array
+ * @param cdds array with details about the coins to be deposited
+ * @param cb the callback to call when a reply for this request is available
+ * @param cb_cls closure for the above callback
+ * @param[out] ec if NULL is returned, set to the error code explaining why 
the operation failed
+ * @return a handle for this request; NULL if the inputs are invalid (i.e.
+ *         signatures fail to verify).  In this case, the callback is not 
called.
+ */
+struct TALER_EXCHANGE_BatchDepositHandle *
+TALER_EXCHANGE_batch_deposit (
+  struct TALER_EXCHANGE_Handle *exchange,
+  const struct TALER_EXCHANGE_DepositContractDetail *dcd,
+  unsigned int num_cdds,
+  const struct TALER_EXCHANGE_CoinDepositDetail *cdds,
+  TALER_EXCHANGE_BatchDepositResultCallback cb,
+  void *cb_cls,
+  enum TALER_ErrorCode *ec);
+
+
+/**
+ * Change the chance that our deposit confirmation will be given to the
+ * auditor to 100%.
+ *
+ * @param deposit the batch deposit permission request handle
+ */
+void
+TALER_EXCHANGE_batch_deposit_force_dc (struct
+                                       TALER_EXCHANGE_BatchDepositHandle *
+                                       deposit);
+
+
+/**
+ * Cancel a batch deposit permission request.  This function cannot be used
+ * on a request handle if a response is already served for it.
+ *
+ * @param deposit the deposit permission request handle
+ */
+void
+TALER_EXCHANGE_batch_deposit_cancel (struct
+                                     TALER_EXCHANGE_BatchDepositHandle 
*deposit);
+
+
 /* *********************  /coins/$COIN_PUB/refund *********************** */
 
 /**
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 844ca52f..76157c43 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -22,6 +22,7 @@ libtalerexchange_la_LDFLAGS = \
   -no-undefined
 libtalerexchange_la_SOURCES = \
   exchange_api_auditor_add_denomination.c \
+  exchange_api_batch_deposit.c \
   exchange_api_batch_withdraw.c \
   exchange_api_batch_withdraw2.c \
   exchange_api_curl_defaults.c exchange_api_curl_defaults.h \
diff --git a/src/lib/exchange_api_deposit.c 
b/src/lib/exchange_api_batch_deposit.c
similarity index 61%
copy from src/lib/exchange_api_deposit.c
copy to src/lib/exchange_api_batch_deposit.c
index 7e824617..be77f682 100644
--- a/src/lib/exchange_api_deposit.c
+++ b/src/lib/exchange_api_batch_deposit.c
@@ -1,6 +1,6 @@
 /*
    This file is part of TALER
-   Copyright (C) 2014-2021 Taler Systems SA
+   Copyright (C) 2014-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
@@ -15,8 +15,8 @@
    <http://www.gnu.org/licenses/>
  */
 /**
- * @file lib/exchange_api_deposit.c
- * @brief Implementation of the /deposit request of the exchange's HTTP API
+ * @file lib/exchange_api_batch_deposit.c
+ * @brief Implementation of the /batch-deposit request of the exchange's HTTP 
API
  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
  * @author Christian Grothoff
  */
@@ -47,7 +47,7 @@
 /**
  * @brief A Deposit Handle
  */
-struct TALER_EXCHANGE_DepositHandle
+struct TALER_EXCHANGE_BatchDepositHandle
 {
 
   /**
@@ -74,7 +74,7 @@ struct TALER_EXCHANGE_DepositHandle
   /**
    * Function to call with the result.
    */
-  TALER_EXCHANGE_DepositResultCallback cb;
+  TALER_EXCHANGE_BatchDepositResultCallback cb;
 
   /**
    * Closure for @a cb.
@@ -87,9 +87,9 @@ struct TALER_EXCHANGE_DepositHandle
   struct TALER_EXCHANGE_DepositContractDetail dcd;
 
   /**
-   * Details about the coin.
+   * Array with details about the coins.
    */
-  struct TALER_EXCHANGE_CoinDepositDetail cdd;
+  struct TALER_EXCHANGE_CoinDepositDetail *cdds;
 
   /**
    * Hash of the merchant's wire details.
@@ -108,9 +108,9 @@ struct TALER_EXCHANGE_DepositHandle
   struct GNUNET_TIME_Timestamp exchange_timestamp;
 
   /**
-   * Exchange signature, set for #auditor_cb.
+   * Exchange signatures, set for #auditor_cb.
    */
-  struct TALER_ExchangeSignatureP exchange_sig;
+  struct TALER_ExchangeSignatureP *exchange_sigs;
 
   /**
    * Exchange signing public key, set for #auditor_cb.
@@ -123,6 +123,11 @@ struct TALER_EXCHANGE_DepositHandle
    */
   unsigned int auditor_chance;
 
+  /**
+   * Length of the @e cdds array.
+   */
+  unsigned int num_cdds;
+
 };
 
 
@@ -140,12 +145,13 @@ auditor_cb (void *cls,
             struct TALER_AUDITOR_Handle *ah,
             const struct TALER_AuditorPublicKeyP *auditor_pub)
 {
-  struct TALER_EXCHANGE_DepositHandle *dh = cls;
+  struct TALER_EXCHANGE_BatchDepositHandle *dh = cls;
   const struct TALER_EXCHANGE_Keys *key_state;
   const struct TALER_EXCHANGE_SigningPublicKey *spk;
   struct TEAH_AuditorInteractionEntry *aie;
   struct TALER_Amount amount_without_fee;
   const struct TALER_EXCHANGE_DenomPublicKey *dki;
+  unsigned int coin;
 
   if (0 !=
       GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
@@ -155,12 +161,14 @@ auditor_cb (void *cls,
                 "Not providing deposit confirmation to auditor\n");
     return NULL;
   }
+  coin = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+                                   dh->num_cdds);
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Will provide deposit confirmation to auditor `%s'\n",
               TALER_B2S (auditor_pub));
   key_state = TALER_EXCHANGE_get_keys (dh->exchange);
   dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state,
-                                                     &dh->cdd.h_denom_pub);
+                                                     
&dh->cdds[coin].h_denom_pub);
   GNUNET_assert (NULL != dki);
   spk = TALER_EXCHANGE_get_signing_key_info (key_state,
                                              &dh->exchange_pub);
@@ -171,7 +179,7 @@ auditor_cb (void *cls,
   }
   GNUNET_assert (0 <=
                  TALER_amount_subtract (&amount_without_fee,
-                                        &dh->cdd.amount,
+                                        &dh->cdds[coin].amount,
                                         &dki->fees.deposit));
   aie = GNUNET_new (struct TEAH_AuditorInteractionEntry);
   aie->dch = TALER_AUDITOR_deposit_confirmation (
@@ -183,10 +191,10 @@ auditor_cb (void *cls,
     dh->dcd.wire_deadline,
     dh->dcd.refund_deadline,
     &amount_without_fee,
-    &dh->cdd.coin_pub,
+    &dh->cdds[coin].coin_pub,
     &dh->dcd.merchant_pub,
     &dh->exchange_pub,
-    &dh->exchange_sig,
+    &dh->exchange_sigs[coin],
     &key_state->master_pub,
     spk->valid_from,
     spk->valid_until,
@@ -202,7 +210,7 @@ auditor_cb (void *cls,
  * Function called when we're done processing the
  * HTTP /deposit request.
  *
- * @param cls the `struct TALER_EXCHANGE_DepositHandle`
+ * @param cls the `struct TALER_EXCHANGE_BatchDepositHandle`
  * @param response_code HTTP response code, 0 on error
  * @param response parsed JSON result, NULL on error
  */
@@ -211,9 +219,9 @@ handle_deposit_finished (void *cls,
                          long response_code,
                          const void *response)
 {
-  struct TALER_EXCHANGE_DepositHandle *dh = cls;
+  struct TALER_EXCHANGE_BatchDepositHandle *dh = cls;
   const json_t *j = response;
-  struct TALER_EXCHANGE_DepositResult dr = {
+  struct TALER_EXCHANGE_BatchDepositResult dr = {
     .hr.reply = j,
     .hr.http_status = (unsigned int) response_code
   };
@@ -229,9 +237,12 @@ handle_deposit_finished (void *cls,
   case MHD_HTTP_OK:
     {
       const struct TALER_EXCHANGE_Keys *key_state;
+      json_t *sigs;
+      json_t *sig;
+      unsigned int idx;
       struct GNUNET_JSON_Specification spec[] = {
-        GNUNET_JSON_spec_fixed_auto ("exchange_sig",
-                                     &dh->exchange_sig),
+        GNUNET_JSON_spec_json ("exchange_sigs",
+                               &sigs),
         GNUNET_JSON_spec_fixed_auto ("exchange_pub",
                                      &dh->exchange_pub),
         GNUNET_JSON_spec_mark_optional (
@@ -242,8 +253,6 @@ handle_deposit_finished (void *cls,
                                     &dh->exchange_timestamp),
         GNUNET_JSON_spec_end ()
       };
-      struct TALER_Amount amount_without_fee;
-      const struct TALER_EXCHANGE_DenomPublicKey *dki;
 
       if (GNUNET_OK !=
           GNUNET_JSON_parse (j,
@@ -255,51 +264,83 @@ handle_deposit_finished (void *cls,
         dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
         break;
       }
-      key_state = TALER_EXCHANGE_get_keys (dh->exchange);
-      dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state,
-                                                         &dh->cdd.h_denom_pub);
-      GNUNET_assert (NULL != dki);
-      if (GNUNET_OK !=
-          TALER_EXCHANGE_test_signing_key (key_state,
-                                           &dh->exchange_pub))
+      if (json_array_size (sigs) != dh->num_cdds)
       {
         GNUNET_break_op (0);
         dr.hr.http_status = 0;
-        dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE;
+        dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
         break;
       }
-      GNUNET_assert (0 <=
-                     TALER_amount_subtract (&amount_without_fee,
-                                            &dh->cdd.amount,
-                                            &dki->fees.deposit));
-
+      dh->exchange_sigs = GNUNET_new_array (dh->num_cdds,
+                                            struct TALER_ExchangeSignatureP);
+      key_state = TALER_EXCHANGE_get_keys (dh->exchange);
       if (GNUNET_OK !=
-          TALER_exchange_online_deposit_confirmation_verify (
-            &dh->dcd.h_contract_terms,
-            &dh->h_wire,
-            &dh->h_extensions,
-            dh->exchange_timestamp,
-            dh->dcd.wire_deadline,
-            dh->dcd.refund_deadline,
-            &amount_without_fee,
-            &dh->cdd.coin_pub,
-            &dh->dcd.merchant_pub,
-            &dh->exchange_pub,
-            &dh->exchange_sig))
+          TALER_EXCHANGE_test_signing_key (key_state,
+                                           &dh->exchange_pub))
       {
         GNUNET_break_op (0);
         dr.hr.http_status = 0;
         dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE;
         break;
       }
-
+      json_array_foreach (sigs, idx, sig)
+      {
+        struct GNUNET_JSON_Specification ispec[] = {
+          GNUNET_JSON_spec_fixed_auto ("exchange_sig",
+                                       &dh->exchange_sigs[idx]),
+          GNUNET_JSON_spec_end ()
+        };
+        struct TALER_Amount amount_without_fee;
+        const struct TALER_EXCHANGE_DenomPublicKey *dki;
+
+        if (GNUNET_OK !=
+            GNUNET_JSON_parse (sig,
+                               ispec,
+                               NULL, NULL))
+        {
+          GNUNET_break_op (0);
+          dr.hr.http_status = 0;
+          dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+          GNUNET_JSON_parse_free (spec);
+          break;
+        }
+        dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state,
+                                                           &dh->cdds[idx].
+                                                           h_denom_pub);
+        GNUNET_assert (NULL != dki);
+        GNUNET_assert (0 <=
+                       TALER_amount_subtract (&amount_without_fee,
+                                              &dh->cdds[idx].amount,
+                                              &dki->fees.deposit));
+
+        if (GNUNET_OK !=
+            TALER_exchange_online_deposit_confirmation_verify (
+              &dh->dcd.h_contract_terms,
+              &dh->h_wire,
+              &dh->h_extensions,
+              dh->exchange_timestamp,
+              dh->dcd.wire_deadline,
+              dh->dcd.refund_deadline,
+              &amount_without_fee,
+              &dh->cdds[idx].coin_pub,
+              &dh->dcd.merchant_pub,
+              &dh->exchange_pub,
+              &dh->exchange_sigs[idx]))
+        {
+          GNUNET_break_op (0);
+          dr.hr.http_status = 0;
+          dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE;
+          break;
+        }
+      }
       TEAH_get_auditors_for_dc (dh->exchange,
                                 &auditor_cb,
                                 dh);
     }
-    dr.details.success.exchange_sig = &dh->exchange_sig;
+    dr.details.success.exchange_sigs = dh->exchange_sigs;
     dr.details.success.exchange_pub = &dh->exchange_pub;
     dr.details.success.deposit_timestamp = dh->exchange_timestamp;
+    dr.details.success.num_signatures = dh->num_cdds;
     break;
   case MHD_HTTP_BAD_REQUEST:
     /* This should never happen, either us or the exchange is buggy
@@ -323,28 +364,62 @@ handle_deposit_finished (void *cls,
   case MHD_HTTP_CONFLICT:
     {
       const struct TALER_EXCHANGE_Keys *key_state;
+      struct TALER_CoinSpendPublicKeyP coin_pub;
+      struct GNUNET_JSON_Specification spec[] = {
+        GNUNET_JSON_spec_fixed_auto ("coin_pub",
+                                     &coin_pub),
+        GNUNET_JSON_spec_end ()
+      };
       const struct TALER_EXCHANGE_DenomPublicKey *dki;
+      bool found = false;
 
-      key_state = TALER_EXCHANGE_get_keys (dh->exchange);
-      dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state,
-                                                         &dh->cdd.h_denom_pub);
-      GNUNET_assert (NULL != dki);
-      dr.hr.ec = TALER_JSON_get_error_code (j);
-      dr.hr.hint = TALER_JSON_get_error_hint (j);
       if (GNUNET_OK !=
-          TALER_EXCHANGE_check_coin_conflict_ (
-            keys,
-            j,
-            dki,
-            &dh->cdd.coin_pub,
-            &dh->cdd.coin_sig,
-            &dh->cdd.amount))
+          GNUNET_JSON_parse (j,
+                             spec,
+                             NULL, NULL))
       {
         GNUNET_break_op (0);
         dr.hr.http_status = 0;
         dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
         break;
       }
+      for (unsigned int i = 0; i<dh->num_cdds; i++)
+      {
+        if (0 !=
+            GNUNET_memcmp (&coin_pub,
+                           &dh->cdds[i].coin_pub))
+          continue;
+        key_state = TALER_EXCHANGE_get_keys (dh->exchange);
+        dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state,
+                                                           &dh->cdds[i].
+                                                           h_denom_pub);
+        GNUNET_assert (NULL != dki);
+        if (GNUNET_OK !=
+            TALER_EXCHANGE_check_coin_conflict_ (
+              keys,
+              j,
+              dki,
+              &dh->cdds[i].coin_pub,
+              &dh->cdds[i].coin_sig,
+              &dh->cdds[i].amount))
+        {
+          GNUNET_break_op (0);
+          dr.hr.http_status = 0;
+          dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+          break;
+        }
+        found = true;
+        break;
+      }
+      if (! found)
+      {
+        GNUNET_break_op (0);
+        dr.hr.http_status = 0;
+        dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+        break;
+      }
+      dr.hr.ec = TALER_JSON_get_error_code (j);
+      dr.hr.hint = TALER_JSON_get_error_hint (j);
     }
     break;
   case MHD_HTTP_GONE:
@@ -374,98 +449,27 @@ handle_deposit_finished (void *cls,
   }
   dh->cb (dh->cb_cls,
           &dr);
-  TALER_EXCHANGE_deposit_cancel (dh);
-}
-
-
-/**
- * Verify signature information about the deposit.
- *
- * @param dcd contract details
- * @param ech hashed contract (passed to avoid recomputation)
- * @param h_wire hashed wire details (passed to avoid recomputation)
- * @param cdd coin-specific details
- * @param dki denomination of the coin
- * @return #GNUNET_OK if signatures are OK, #GNUNET_SYSERR if not
- */
-static enum GNUNET_GenericReturnValue
-verify_signatures (const struct TALER_EXCHANGE_DepositContractDetail *dcd,
-                   const struct TALER_ExtensionContractHashP *ech,
-                   const struct TALER_MerchantWireHashP *h_wire,
-                   const struct TALER_EXCHANGE_CoinDepositDetail *cdd,
-                   const struct TALER_EXCHANGE_DenomPublicKey *dki)
-{
-  if (GNUNET_OK !=
-      TALER_wallet_deposit_verify (&cdd->amount,
-                                   &dki->fees.deposit,
-                                   h_wire,
-                                   &dcd->h_contract_terms,
-                                   &cdd->h_age_commitment,
-                                   ech,
-                                   &cdd->h_denom_pub,
-                                   dcd->timestamp,
-                                   &dcd->merchant_pub,
-                                   dcd->refund_deadline,
-                                   &cdd->coin_pub,
-                                   &cdd->coin_sig))
-  {
-    GNUNET_break_op (0);
-    TALER_LOG_WARNING ("Invalid coin signature on /deposit request!\n");
-    TALER_LOG_DEBUG ("... amount_with_fee was %s\n",
-                     TALER_amount2s (&cdd->amount));
-    TALER_LOG_DEBUG ("... deposit_fee was %s\n",
-                     TALER_amount2s (&dki->fees.deposit));
-    return GNUNET_SYSERR;
-  }
-
-  /* check coin signature */
-  {
-    struct TALER_CoinPublicInfo coin_info = {
-      .coin_pub = cdd->coin_pub,
-      .denom_pub_hash = cdd->h_denom_pub,
-      .denom_sig = cdd->denom_sig,
-      .h_age_commitment = cdd->h_age_commitment,
-    };
-
-    if (GNUNET_YES !=
-        TALER_test_coin_valid (&coin_info,
-                               &dki->key))
-    {
-      GNUNET_break_op (0);
-      TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
-      return GNUNET_SYSERR;
-    }
-  }
-
-  /* Check coin does make a contribution */
-  if (0 < TALER_amount_cmp (&dki->fees.deposit,
-                            &cdd->amount))
-  {
-    GNUNET_break_op (0);
-    TALER_LOG_WARNING ("Deposit amount smaller than fee\n");
-    return GNUNET_SYSERR;
-  }
-  return GNUNET_OK;
+  TALER_EXCHANGE_batch_deposit_cancel (dh);
 }
 
 
-struct TALER_EXCHANGE_DepositHandle *
-TALER_EXCHANGE_deposit (
+struct TALER_EXCHANGE_BatchDepositHandle *
+TALER_EXCHANGE_batch_deposit (
   struct TALER_EXCHANGE_Handle *exchange,
   const struct TALER_EXCHANGE_DepositContractDetail *dcd,
-  const struct TALER_EXCHANGE_CoinDepositDetail *cdd,
-  TALER_EXCHANGE_DepositResultCallback cb,
+  unsigned int num_cdds,
+  const struct TALER_EXCHANGE_CoinDepositDetail *cdds,
+  TALER_EXCHANGE_BatchDepositResultCallback cb,
   void *cb_cls,
   enum TALER_ErrorCode *ec)
 {
   const struct TALER_EXCHANGE_Keys *key_state;
-  struct TALER_EXCHANGE_DepositHandle *dh;
+  struct TALER_EXCHANGE_BatchDepositHandle *dh;
   struct GNUNET_CURL_Context *ctx;
   json_t *deposit_obj;
+  json_t *deposits;
   CURL *eh;
-  const struct TALER_EXCHANGE_DenomPublicKey *dki;
   struct TALER_Amount amount_without_fee;
-  char arg_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2 + 32];
 
   GNUNET_assert (GNUNET_YES ==
                  TEAH_handle_is_ready (exchange));
@@ -477,47 +481,16 @@ TALER_EXCHANGE_deposit (
     *ec = TALER_EC_EXCHANGE_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE;
     return NULL;
   }
-  {
-    char pub_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2];
-    char *end;
-
-    end = GNUNET_STRINGS_data_to_string (
-      &cdd->coin_pub,
-      sizeof (struct TALER_CoinSpendPublicKeyP),
-      pub_str,
-      sizeof (pub_str));
-    *end = '\0';
-    GNUNET_snprintf (arg_str,
-                     sizeof (arg_str),
-                     "/coins/%s/deposit",
-                     pub_str);
-  }
-
   key_state = TALER_EXCHANGE_get_keys (exchange);
-  dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state,
-                                                     &cdd->h_denom_pub);
-  if (NULL == dki)
-  {
-    *ec = TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
-    GNUNET_break_op (0);
-    return NULL;
-  }
-
-  if (0 >
-      TALER_amount_subtract (&amount_without_fee,
-                             &cdd->amount,
-                             &dki->fees.deposit))
-  {
-    *ec = TALER_EC_EXCHANGE_DEPOSIT_FEE_ABOVE_AMOUNT;
-    GNUNET_break_op (0);
-    return NULL;
-  }
-  dh = GNUNET_new (struct TALER_EXCHANGE_DepositHandle);
+  dh = GNUNET_new (struct TALER_EXCHANGE_BatchDepositHandle);
   dh->auditor_chance = AUDITOR_CHANCE;
   dh->exchange = exchange;
   dh->cb = cb;
   dh->cb_cls = cb_cls;
-  dh->cdd = *cdd;
+  dh->cdds = GNUNET_memdup (cdds,
+                            num_cdds
+                            * sizeof (*cdds));
+  dh->num_cdds = num_cdds;
   dh->dcd = *dcd;
   if (NULL != dcd->extension_details)
     TALER_deposit_extension_hash (dcd->extension_details,
@@ -525,45 +498,85 @@ TALER_EXCHANGE_deposit (
   TALER_merchant_wire_signature_hash (dcd->merchant_payto_uri,
                                       &dcd->wire_salt,
                                       &dh->h_wire);
-  if (GNUNET_OK !=
-      verify_signatures (dcd,
-                         &dh->h_extensions,
-                         &dh->h_wire,
-                         cdd,
-                         dki))
+  deposits = json_array ();
+  GNUNET_assert (NULL != deposits);
+  for (unsigned int i = 0; i<num_cdds; i++)
   {
-    *ec = TALER_EC_EXCHANGE_DEPOSIT_COIN_SIGNATURE_INVALID;
-    GNUNET_break_op (0);
-    GNUNET_free (dh);
-    return NULL;
+    const struct TALER_EXCHANGE_CoinDepositDetail *cdd = &cdds[i];
+    const struct TALER_EXCHANGE_DenomPublicKey *dki;
+
+    dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state,
+                                                       &cdd->h_denom_pub);
+    if (NULL == dki)
+    {
+      *ec = TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
+      GNUNET_break_op (0);
+      return NULL;
+    }
+    if (0 >
+        TALER_amount_subtract (&amount_without_fee,
+                               &cdd->amount,
+                               &dki->fees.deposit))
+    {
+      *ec = TALER_EC_EXCHANGE_DEPOSIT_FEE_ABOVE_AMOUNT;
+      GNUNET_break_op (0);
+      GNUNET_free (dh->cdds);
+      GNUNET_free (dh);
+      return NULL;
+    }
+
+    if (GNUNET_OK !=
+        TALER_EXCHANGE_verify_deposit_signature_ (dcd,
+                                                  &dh->h_extensions,
+                                                  &dh->h_wire,
+                                                  cdd,
+                                                  dki))
+    {
+      *ec = TALER_EC_EXCHANGE_DEPOSIT_COIN_SIGNATURE_INVALID;
+      GNUNET_break_op (0);
+      GNUNET_free (dh->cdds);
+      GNUNET_free (dh);
+      return NULL;
+    }
+    GNUNET_assert (
+      0 ==
+      json_array_append_new (
+        deposits,
+        GNUNET_JSON_PACK (
+          TALER_JSON_pack_amount ("contribution",
+                                  &cdd->amount),
+          GNUNET_JSON_pack_allow_null (
+            GNUNET_JSON_pack_data_auto ("h_age_commitment",
+                                        &cdd->h_age_commitment)),
+          GNUNET_JSON_pack_data_auto ("denom_pub_hash",
+                                      &cdd->h_denom_pub),
+          TALER_JSON_pack_denom_sig ("ub_sig",
+                                     &cdd->denom_sig),
+          GNUNET_JSON_pack_data_auto ("coin_sig",
+                                      &cdd->coin_sig)
+          )));
   }
   dh->url = TEAH_path_to_url (exchange,
-                              arg_str);
+                              "/batch-deposit");
   if (NULL == dh->url)
   {
     GNUNET_break (0);
     *ec = TALER_EC_GENERIC_ALLOCATION_FAILURE;
     GNUNET_free (dh->url);
+    GNUNET_free (dh->cdds);
     GNUNET_free (dh);
     return NULL;
   }
 
   deposit_obj = GNUNET_JSON_PACK (
-    TALER_JSON_pack_amount ("contribution",
-                            &cdd->amount),
+    GNUNET_JSON_pack_array_steal ("coins",
+                                  deposits),
     GNUNET_JSON_pack_string ("merchant_payto_uri",
                              dcd->merchant_payto_uri),
     GNUNET_JSON_pack_data_auto ("wire_salt",
                                 &dcd->wire_salt),
     GNUNET_JSON_pack_data_auto ("h_contract_terms",
                                 &dcd->h_contract_terms),
-    GNUNET_JSON_pack_allow_null (
-      GNUNET_JSON_pack_data_auto ("h_age_commitment",
-                                  &cdd->h_age_commitment)),
-    GNUNET_JSON_pack_data_auto ("denom_pub_hash",
-                                &cdd->h_denom_pub),
-    TALER_JSON_pack_denom_sig ("ub_sig",
-                               &cdd->denom_sig),
     GNUNET_JSON_pack_timestamp ("timestamp",
                                 dcd->timestamp),
     GNUNET_JSON_pack_data_auto ("merchant_pub",
@@ -572,9 +585,7 @@ TALER_EXCHANGE_deposit (
       GNUNET_JSON_pack_timestamp ("refund_deadline",
                                   dcd->refund_deadline)),
     GNUNET_JSON_pack_timestamp ("wire_transfer_deadline",
-                                dcd->wire_deadline),
-    GNUNET_JSON_pack_data_auto ("coin_sig",
-                                &cdd->coin_sig));
+                                dcd->wire_deadline));
   GNUNET_assert (NULL != deposit_obj);
   eh = TALER_EXCHANGE_curl_easy_get_ (dh->url);
   if ( (NULL == eh) ||
@@ -588,6 +599,7 @@ TALER_EXCHANGE_deposit (
     if (NULL != eh)
       curl_easy_cleanup (eh);
     json_decref (deposit_obj);
+    GNUNET_free (dh->cdds);
     GNUNET_free (dh->url);
     GNUNET_free (dh);
     return NULL;
@@ -607,14 +619,17 @@ TALER_EXCHANGE_deposit (
 
 
 void
-TALER_EXCHANGE_deposit_force_dc (struct TALER_EXCHANGE_DepositHandle *deposit)
+TALER_EXCHANGE_batch_deposit_force_dc (struct
+                                       TALER_EXCHANGE_BatchDepositHandle *
+                                       deposit)
 {
   deposit->auditor_chance = 1;
 }
 
 
 void
-TALER_EXCHANGE_deposit_cancel (struct TALER_EXCHANGE_DepositHandle *deposit)
+TALER_EXCHANGE_batch_deposit_cancel (struct
+                                     TALER_EXCHANGE_BatchDepositHandle 
*deposit)
 {
   if (NULL != deposit->job)
   {
@@ -622,9 +637,11 @@ TALER_EXCHANGE_deposit_cancel (struct 
TALER_EXCHANGE_DepositHandle *deposit)
     deposit->job = NULL;
   }
   GNUNET_free (deposit->url);
+  GNUNET_free (deposit->cdds);
+  GNUNET_free (deposit->exchange_sigs);
   TALER_curl_easy_post_finished (&deposit->ctx);
   GNUNET_free (deposit);
 }
 
 
-/* end of exchange_api_deposit.c */
+/* end of exchange_api_batch_deposit.c */
diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c
index 26ddb3c0..739b215f 100644
--- a/src/lib/exchange_api_common.c
+++ b/src/lib/exchange_api_common.c
@@ -1946,4 +1946,66 @@ TALER_EXCHANGE_get_min_denomination_ (
 }
 
 
+enum GNUNET_GenericReturnValue
+TALER_EXCHANGE_verify_deposit_signature_ (
+  const struct TALER_EXCHANGE_DepositContractDetail *dcd,
+  const struct TALER_ExtensionContractHashP *ech,
+  const struct TALER_MerchantWireHashP *h_wire,
+  const struct TALER_EXCHANGE_CoinDepositDetail *cdd,
+  const struct TALER_EXCHANGE_DenomPublicKey *dki)
+{
+  if (GNUNET_OK !=
+      TALER_wallet_deposit_verify (&cdd->amount,
+                                   &dki->fees.deposit,
+                                   h_wire,
+                                   &dcd->h_contract_terms,
+                                   &cdd->h_age_commitment,
+                                   ech,
+                                   &cdd->h_denom_pub,
+                                   dcd->timestamp,
+                                   &dcd->merchant_pub,
+                                   dcd->refund_deadline,
+                                   &cdd->coin_pub,
+                                   &cdd->coin_sig))
+  {
+    GNUNET_break_op (0);
+    TALER_LOG_WARNING ("Invalid coin signature on /deposit request!\n");
+    TALER_LOG_DEBUG ("... amount_with_fee was %s\n",
+                     TALER_amount2s (&cdd->amount));
+    TALER_LOG_DEBUG ("... deposit_fee was %s\n",
+                     TALER_amount2s (&dki->fees.deposit));
+    return GNUNET_SYSERR;
+  }
+
+  /* check coin signature */
+  {
+    struct TALER_CoinPublicInfo coin_info = {
+      .coin_pub = cdd->coin_pub,
+      .denom_pub_hash = cdd->h_denom_pub,
+      .denom_sig = cdd->denom_sig,
+      .h_age_commitment = cdd->h_age_commitment,
+    };
+
+    if (GNUNET_YES !=
+        TALER_test_coin_valid (&coin_info,
+                               &dki->key))
+    {
+      GNUNET_break_op (0);
+      TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
+      return GNUNET_SYSERR;
+    }
+  }
+
+  /* Check coin does make a contribution */
+  if (0 < TALER_amount_cmp (&dki->fees.deposit,
+                            &cdd->amount))
+  {
+    GNUNET_break_op (0);
+    TALER_LOG_WARNING ("Deposit amount smaller than fee\n");
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
 /* end of exchange_api_common.c */
diff --git a/src/lib/exchange_api_common.h b/src/lib/exchange_api_common.h
index f4737ca9..a75ed3ed 100644
--- a/src/lib/exchange_api_common.h
+++ b/src/lib/exchange_api_common.h
@@ -198,4 +198,24 @@ TALER_EXCHANGE_get_min_denomination_ (
   const struct TALER_EXCHANGE_Keys *keys,
   struct TALER_Amount *min);
 
+
+/**
+ * Verify signature information about the deposit.
+ *
+ * @param dcd contract details
+ * @param ech hashed contract (passed to avoid recomputation)
+ * @param h_wire hashed wire details (passed to avoid recomputation)
+ * @param cdd coin-specific details
+ * @param dki denomination of the coin
+ * @return #GNUNET_OK if signatures are OK, #GNUNET_SYSERR if not
+ */
+enum GNUNET_GenericReturnValue
+TALER_EXCHANGE_verify_deposit_signature_ (
+  const struct TALER_EXCHANGE_DepositContractDetail *dcd,
+  const struct TALER_ExtensionContractHashP *ech,
+  const struct TALER_MerchantWireHashP *h_wire,
+  const struct TALER_EXCHANGE_CoinDepositDetail *cdd,
+  const struct TALER_EXCHANGE_DenomPublicKey *dki);
+
+
 #endif
diff --git a/src/lib/exchange_api_deposit.c b/src/lib/exchange_api_deposit.c
index 7e824617..32964341 100644
--- a/src/lib/exchange_api_deposit.c
+++ b/src/lib/exchange_api_deposit.c
@@ -378,77 +378,6 @@ handle_deposit_finished (void *cls,
 }
 
 
-/**
- * Verify signature information about the deposit.
- *
- * @param dcd contract details
- * @param ech hashed contract (passed to avoid recomputation)
- * @param h_wire hashed wire details (passed to avoid recomputation)
- * @param cdd coin-specific details
- * @param dki denomination of the coin
- * @return #GNUNET_OK if signatures are OK, #GNUNET_SYSERR if not
- */
-static enum GNUNET_GenericReturnValue
-verify_signatures (const struct TALER_EXCHANGE_DepositContractDetail *dcd,
-                   const struct TALER_ExtensionContractHashP *ech,
-                   const struct TALER_MerchantWireHashP *h_wire,
-                   const struct TALER_EXCHANGE_CoinDepositDetail *cdd,
-                   const struct TALER_EXCHANGE_DenomPublicKey *dki)
-{
-  if (GNUNET_OK !=
-      TALER_wallet_deposit_verify (&cdd->amount,
-                                   &dki->fees.deposit,
-                                   h_wire,
-                                   &dcd->h_contract_terms,
-                                   &cdd->h_age_commitment,
-                                   ech,
-                                   &cdd->h_denom_pub,
-                                   dcd->timestamp,
-                                   &dcd->merchant_pub,
-                                   dcd->refund_deadline,
-                                   &cdd->coin_pub,
-                                   &cdd->coin_sig))
-  {
-    GNUNET_break_op (0);
-    TALER_LOG_WARNING ("Invalid coin signature on /deposit request!\n");
-    TALER_LOG_DEBUG ("... amount_with_fee was %s\n",
-                     TALER_amount2s (&cdd->amount));
-    TALER_LOG_DEBUG ("... deposit_fee was %s\n",
-                     TALER_amount2s (&dki->fees.deposit));
-    return GNUNET_SYSERR;
-  }
-
-  /* check coin signature */
-  {
-    struct TALER_CoinPublicInfo coin_info = {
-      .coin_pub = cdd->coin_pub,
-      .denom_pub_hash = cdd->h_denom_pub,
-      .denom_sig = cdd->denom_sig,
-      .h_age_commitment = cdd->h_age_commitment,
-    };
-
-    if (GNUNET_YES !=
-        TALER_test_coin_valid (&coin_info,
-                               &dki->key))
-    {
-      GNUNET_break_op (0);
-      TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
-      return GNUNET_SYSERR;
-    }
-  }
-
-  /* Check coin does make a contribution */
-  if (0 < TALER_amount_cmp (&dki->fees.deposit,
-                            &cdd->amount))
-  {
-    GNUNET_break_op (0);
-    TALER_LOG_WARNING ("Deposit amount smaller than fee\n");
-    return GNUNET_SYSERR;
-  }
-  return GNUNET_OK;
-}
-
-
 struct TALER_EXCHANGE_DepositHandle *
 TALER_EXCHANGE_deposit (
   struct TALER_EXCHANGE_Handle *exchange,
@@ -526,11 +455,11 @@ TALER_EXCHANGE_deposit (
                                       &dcd->wire_salt,
                                       &dh->h_wire);
   if (GNUNET_OK !=
-      verify_signatures (dcd,
-                         &dh->h_extensions,
-                         &dh->h_wire,
-                         cdd,
-                         dki))
+      TALER_EXCHANGE_verify_deposit_signature_ (dcd,
+                                                &dh->h_extensions,
+                                                &dh->h_wire,
+                                                cdd,
+                                                dki))
   {
     *ec = TALER_EC_EXCHANGE_DEPOSIT_COIN_SIGNATURE_INVALID;
     GNUNET_break_op (0);
diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c
index 3cdc8ad2..488a419b 100644
--- a/src/lib/exchange_api_handle.c
+++ b/src/lib/exchange_api_handle.c
@@ -992,7 +992,7 @@ decode_keys_json (const json_t *resp_obj,
                                                  check_sig,
                                                  denom_key_obj,
                                                  &key_data->master_pub,
-                                                 check_sig ? &hash_xor: NULL));
+                                                 check_sig ? &hash_xor : 
NULL));
 
           // Build the running xor of the SHA512-hash of the public keys
           {
diff --git a/src/lib/exchange_api_purse_create_with_deposit.c 
b/src/lib/exchange_api_purse_create_with_deposit.c
index 3a5b7df5..ce0221aa 100644
--- a/src/lib/exchange_api_purse_create_with_deposit.c
+++ b/src/lib/exchange_api_purse_create_with_deposit.c
@@ -680,8 +680,8 @@ TALER_EXCHANGE_purse_create_with_deposit (
     GNUNET_JSON_pack_allow_null (
       TALER_JSON_pack_econtract ("econtract",
                                  upload_contract
-                                  ? &pch->econtract
-                                  : NULL)),
+                                 ? &pch->econtract
+                                 : NULL)),
     GNUNET_JSON_pack_data_auto ("purse_sig",
                                 &pch->purse_sig),
     GNUNET_JSON_pack_data_auto ("merge_pub",
diff --git a/src/lib/exchange_api_purse_create_with_merge.c 
b/src/lib/exchange_api_purse_create_with_merge.c
index 2b4f1cd2..f3c72d4f 100644
--- a/src/lib/exchange_api_purse_create_with_merge.c
+++ b/src/lib/exchange_api_purse_create_with_merge.c
@@ -478,8 +478,8 @@ TALER_EXCHANGE_purse_create_with_merge (
     GNUNET_JSON_pack_allow_null (
       TALER_JSON_pack_econtract ("econtract",
                                  upload_contract
-                                  ? &pcm->econtract
-                                  : NULL)),
+                                 ? &pcm->econtract
+                                 : NULL)),
     GNUNET_JSON_pack_allow_null (
       pay_for_purse
       ? TALER_JSON_pack_amount ("purse_fee",

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