gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant] 66/277: implement order claiming


From: gnunet
Subject: [taler-merchant] 66/277: implement order claiming
Date: Sun, 05 Jul 2020 20:49:39 +0200

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

grothoff pushed a commit to branch master
in repository merchant.

commit 5da121e9b0ec83f20a1a404f7049f9ff19aca32b
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Mon Apr 27 16:32:59 2020 +0200

    implement order claiming
---
 src/backend/taler-merchant-httpd.c                 |    2 +-
 .../taler-merchant-httpd_private-post-transfers.c  | 1089 ++++++++++++++++++++
 .../taler-merchant-httpd_private-post-transfers.h  |   49 +
 src/include/taler_merchant_service.h               |  113 +-
 src/include/taler_merchant_testing_lib.h           |   24 +-
 src/lib/Makefile.am                                |    3 +-
 ...al_lookup.c => merchant_api_post_order_claim.c} |  194 ++--
 src/lib/merchant_api_post_products.c               |   17 +-
 src/testing/Makefile.am                            |    2 +-
 src/testing/test_merchant_api.c                    |   10 +-
 ...osal_lookup.c => testing_api_cmd_claim_order.c} |  140 +--
 src/testing/testing_api_cmd_post_orders.c          |   41 +-
 12 files changed, 1403 insertions(+), 281 deletions(-)

diff --git a/src/backend/taler-merchant-httpd.c 
b/src/backend/taler-merchant-httpd.c
index f11d18c..7d255b9 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -908,7 +908,7 @@ url_handler (void *cls,
          (GNUNET_YES != GNUNET_CURL_is_valid_scope_id (correlation_id)) )
     {
       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  "illegal incoming correlation ID\n");
+                  "Illegal incoming correlation ID\n");
       correlation_id = NULL;
     }
     if (NULL != correlation_id)
diff --git a/src/backend/taler-merchant-httpd_private-post-transfers.c 
b/src/backend/taler-merchant-httpd_private-post-transfers.c
new file mode 100644
index 0000000..7f55c91
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-post-transfers.c
@@ -0,0 +1,1089 @@
+/*
+  This file is part of TALER
+  (C) 2014-2020 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU Affero General Public License as published by the Free 
Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file backend/taler-merchant-httpd_track-transfer.c
+ * @brief implement API for tracking transfers and wire transfers
+ * @author Marcello Stanisci
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <jansson.h>
+#include <taler/taler_signatures.h>
+#include <taler/taler_json_lib.h>
+#include "taler-merchant-httpd.h"
+#include "taler-merchant-httpd_mhd.h"
+#include "taler-merchant-httpd_auditors.h"
+#include "taler-merchant-httpd_exchanges.h"
+#include "taler-merchant-httpd_track-transfer.h"
+
+
+/**
+ * How long to wait before giving up processing with the exchange?
+ */
+#define TRACK_TIMEOUT (GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, \
+                                                      30))
+
+/**
+ * How often do we retry the simple INSERT database transaction?
+ */
+#define MAX_RETRIES 3
+
+/**
+ * Context used for handing /track/transfer requests.
+ */
+struct TrackTransferContext
+{
+
+  /**
+   * This MUST be first!
+   */
+  struct TM_HandlerContext hc;
+
+  /**
+   * Handle to the exchange.
+   */
+  struct TALER_EXCHANGE_Handle *eh;
+
+  /**
+   * Handle for the /wire/transfers request.
+   */
+  struct TALER_EXCHANGE_TransfersGetHandle *wdh;
+
+  /**
+   * For which merchant instance is this tracking request?
+   */
+  struct MerchantInstance *mi;
+
+  /**
+   * HTTP connection we are handling.
+   */
+  struct MHD_Connection *connection;
+
+  /**
+   * Response to return upon resume.
+   */
+  struct MHD_Response *response;
+
+  /**
+   * Handle for operation to lookup /keys (and auditors) from
+   * the exchange used for this transaction; NULL if no operation is
+   * pending.
+   */
+  struct TMH_EXCHANGES_FindOperation *fo;
+
+  /**
+   * Task run on timeout.
+   */
+  struct GNUNET_SCHEDULER_Task *timeout_task;
+
+  /**
+   * URL of the exchange.
+   */
+  char *url;
+
+  /**
+   * Wire method used for the transfer.
+   */
+  char *wire_method;
+
+  /**
+   * Pointer to the detail that we are currently
+   * checking in #check_transfer().
+   */
+  const struct TALER_TrackTransferDetails *current_detail;
+
+  /**
+   * Argument for the /wire/transfers request.
+   */
+  struct TALER_WireTransferIdentifierRawP wtid;
+
+  /**
+   * Full original response we are currently processing.
+   */
+  const json_t *original_response;
+
+  /**
+   * Modified response to return to the frontend.
+   */
+  json_t *deposits_response;
+
+  /**
+   * Which transaction detail are we currently looking at?
+   */
+  unsigned int current_offset;
+
+  /**
+   * Response code to return.
+   */
+  unsigned int response_code;
+
+  /**
+   * #GNUNET_NO if we did not find a matching coin.
+   * #GNUNET_SYSERR if we found a matching coin, but the amounts do not match.
+   * #GNUNET_OK if we did find a matching coin.
+   */
+  int check_transfer_result;
+};
+
+
+/**
+ * Represents an entry in the table used to sum up
+ * individual deposits for each h_contract_terms.
+ */
+struct Entry
+{
+
+  /**
+   * Sum accumulator for deposited value.
+   */
+  struct TALER_Amount deposit_value;
+
+  /**
+   * Sum accumulator for deposit fee.
+   */
+  struct TALER_Amount deposit_fee;
+
+};
+
+
+/**
+ * Free the @a rctx.
+ *
+ * @param rctx data to free
+ */
+static void
+free_transfer_track_context (struct TrackTransferContext *rctx)
+{
+  if (NULL != rctx->fo)
+  {
+    TMH_EXCHANGES_find_exchange_cancel (rctx->fo);
+    rctx->fo = NULL;
+  }
+  if (NULL != rctx->timeout_task)
+  {
+    GNUNET_SCHEDULER_cancel (rctx->timeout_task);
+    rctx->timeout_task = NULL;
+  }
+  if (NULL != rctx->wdh)
+  {
+    TALER_EXCHANGE_transfers_get_cancel (rctx->wdh);
+    rctx->wdh = NULL;
+  }
+  if (NULL != rctx->url)
+  {
+    GNUNET_free (rctx->url);
+    rctx->url = NULL;
+  }
+  if (NULL != rctx->wire_method)
+  {
+    GNUNET_free (rctx->wire_method);
+    rctx->wire_method = NULL;
+  }
+  GNUNET_free (rctx);
+}
+
+
+/**
+ * Callback that frees all the elements in the hashmap
+ *
+ * @param cls closure, NULL
+ * @param key current key
+ * @param value a `struct Entry`
+ * @return #GNUNET_YES if the iteration should continue,
+ *         #GNUNET_NO otherwise.
+ */
+static int
+hashmap_free (void *cls,
+              const struct GNUNET_HashCode *key,
+              void *value)
+{
+  struct TALER_Entry *entry = value;
+
+  (void) cls;
+  (void) key;
+  GNUNET_free (entry);
+  return GNUNET_YES;
+}
+
+
+/**
+ * Builds JSON response containing the summed-up amounts
+ * from individual deposits.
+ *
+ * @param cls closure
+ * @param key map's current key
+ * @param map's current value
+ * @return #GNUNET_YES if iteration is to be continued,
+ *         #GNUNET_NO otherwise.
+ */
+static int
+build_deposits_response (void *cls,
+                         const struct GNUNET_HashCode *key,
+                         void *value)
+{
+  struct TrackTransferContext *rctx = cls;
+  struct Entry *entry = value;
+  json_t *element;
+  json_t *contract_terms;
+  json_t *order_id;
+
+  db->preflight (db->cls);
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+      db->find_contract_terms_from_hash (db->cls,
+                                         &contract_terms,
+                                         key,
+                                         &rctx->mi->pubkey))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_NO;
+  }
+
+  order_id = json_object_get (contract_terms,
+                              "order_id");
+  if (NULL == order_id)
+  {
+    GNUNET_break_op (0);
+    json_decref (contract_terms);
+    return GNUNET_NO;
+  }
+  element = json_pack ("{s:O, s:o, s:o}",
+                       "order_id", order_id,
+                       "deposit_value", TALER_JSON_from_amount (
+                         &entry->deposit_value),
+                       "deposit_fee", TALER_JSON_from_amount (
+                         &entry->deposit_fee));
+  json_decref (contract_terms);
+  if (NULL == element)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_NO;
+  }
+  GNUNET_break (0 ==
+                json_array_append_new (rctx->deposits_response,
+                                       element));
+  return GNUNET_YES;
+}
+
+
+/**
+ * Transform /track/transfer result as gotten from the exchange
+ * and transforms it in a format liked by the backoffice Web interface.
+ *
+ * @param result response from exchange's /track/transfer
+ * @result pointer to new JSON, or NULL upon errors.
+ */
+static json_t *
+transform_response (const json_t *result,
+                    struct TrackTransferContext *rctx)
+{
+  json_t *deposits;
+  json_t *value;
+  json_t *result_mod = NULL;
+  size_t index;
+  const char *key;
+  struct GNUNET_HashCode h_key;
+  struct GNUNET_CONTAINER_MultiHashMap *map;
+  struct TALER_Amount iter_value;
+  struct TALER_Amount iter_fee;
+  struct Entry *current_entry;
+  struct GNUNET_JSON_Specification spec[] = {
+    TALER_JSON_spec_amount ("deposit_value", &iter_value),
+    TALER_JSON_spec_amount ("deposit_fee", &iter_fee),
+    GNUNET_JSON_spec_string ("h_contract_terms", &key),
+    GNUNET_JSON_spec_end ()
+  };
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Transforming /track/transfer response.\n");
+  map = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
+  deposits = json_object_get (result,
+                              "deposits");
+
+  json_array_foreach (deposits, index, value)
+  {
+    if (GNUNET_OK !=
+        GNUNET_JSON_parse (value,
+                           spec,
+                           NULL,
+                           NULL))
+    {
+      GNUNET_break_op (0);
+      return NULL;
+    }
+    GNUNET_CRYPTO_hash_from_string (key,
+                                    &h_key);
+
+    if (NULL != (current_entry =
+                   GNUNET_CONTAINER_multihashmap_get (map,
+                                                      &h_key)))
+    {
+      /* The map already knows this h_contract_terms*/
+      if ( (0 >
+            TALER_amount_add (&current_entry->deposit_value,
+                              &current_entry->deposit_value,
+                              &iter_value)) ||
+           (0 >
+            TALER_amount_add (&current_entry->deposit_fee,
+                              &current_entry->deposit_fee,
+                              &iter_fee)) )
+      {
+        GNUNET_JSON_parse_free (spec);
+        goto cleanup;
+      }
+    }
+    else
+    {
+      /* First time in the map for this h_contract_terms*/
+      current_entry = GNUNET_new (struct Entry);
+      current_entry->deposit_value = iter_value;
+      current_entry->deposit_fee = iter_fee;
+
+      if (GNUNET_SYSERR ==
+          GNUNET_CONTAINER_multihashmap_put (map,
+                                             &h_key,
+                                             current_entry,
+                                             
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+      {
+        GNUNET_JSON_parse_free (spec);
+        goto cleanup;
+      }
+    }
+    GNUNET_JSON_parse_free (spec);
+  }
+  rctx->deposits_response = json_array ();
+
+  if (GNUNET_SYSERR ==
+      GNUNET_CONTAINER_multihashmap_iterate (map,
+                                             &build_deposits_response,
+                                             rctx))
+    goto cleanup;
+
+  result_mod = json_copy ((struct json_t *) result);
+  json_object_del (result_mod,
+                   "deposits");
+  json_object_set_new (result_mod,
+                       "deposits_sums",
+                       rctx->deposits_response);
+  rctx->deposits_response = NULL;
+cleanup:
+  GNUNET_CONTAINER_multihashmap_iterate (map,
+                                         &hashmap_free,
+                                         NULL);
+  GNUNET_CONTAINER_multihashmap_destroy (map);
+  return result_mod;
+}
+
+
+/**
+ * Resume the given /track/transfer operation and send the given response.
+ * Stores the response in the @a rctx and signals MHD to resume
+ * the connection.  Also ensures MHD runs immediately.
+ *
+ * @param rctx transfer tracking context
+ * @param response_code response code to use
+ * @param response response data to send back
+ */
+static void
+resume_track_transfer_with_response (struct TrackTransferContext *rctx,
+                                     unsigned int response_code,
+                                     struct MHD_Response *response)
+{
+  rctx->response_code = response_code;
+  rctx->response = response;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Resuming /track/transfer handling as exchange interaction is 
done (%u)\n",
+              response_code);
+  if (NULL != rctx->timeout_task)
+  {
+    GNUNET_SCHEDULER_cancel (rctx->timeout_task);
+    rctx->timeout_task = NULL;
+  }
+  MHD_resume_connection (rctx->connection);
+  TMH_trigger_daemon (); /* we resumed, kick MHD */
+}
+
+
+/**
+ * Custom cleanup routine for a `struct TrackTransferContext`.
+ *
+ * @param hc the `struct TrackTransferContext` to clean up.
+ */
+static void
+track_transfer_cleanup (struct TM_HandlerContext *hc)
+{
+  struct TrackTransferContext *rctx = (struct TrackTransferContext *) hc;
+
+  free_transfer_track_context (rctx);
+}
+
+
+/**
+ * This function checks that the information about the coin which
+ * was paid back by _this_ wire transfer matches what _we_ (the merchant)
+ * knew about this coin.
+ *
+ * @param cls closure with our `struct TrackTransferContext *`
+ * @param transaction_id of the contract
+ * @param coin_pub public key of the coin
+ * @param exchange_url URL of the exchange that issued @a coin_pub
+ * @param amount_with_fee amount the exchange will transfer for this coin
+ * @param deposit_fee fee the exchange will charge for this coin
+ * @param refund_fee fee the exchange will charge for refunding this coin
+ * @param exchange_proof proof from exchange that coin was accepted
+ */
+static void
+check_transfer (void *cls,
+                const struct GNUNET_HashCode *h_contract_terms,
+                const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                const char *exchange_url,
+                const struct TALER_Amount *amount_with_fee,
+                const struct TALER_Amount *deposit_fee,
+                const struct TALER_Amount *refund_fee,
+                const struct TALER_Amount *wire_fee,
+                const json_t *exchange_proof)
+{
+  struct TrackTransferContext *rctx = cls;
+  const struct TALER_TrackTransferDetails *ttd = rctx->current_detail;
+
+  if (GNUNET_SYSERR == rctx->check_transfer_result)
+    return; /* already had a serious issue; odd that we're called more than 
once as well... */
+  if ( (0 != TALER_amount_cmp (amount_with_fee,
+                               &ttd->coin_value)) ||
+       (0 != TALER_amount_cmp (deposit_fee,
+                               &ttd->coin_fee)) )
+  {
+    /* Disagreement between the exchange and us about how much this
+       coin is worth! */
+    GNUNET_break_op (0);
+    rctx->check_transfer_result = GNUNET_SYSERR;
+    /* Build the `TrackTransferConflictDetails` */
+    rctx->response
+      = TALER_MHD_make_json_pack (
+          "{s:I, s:s, s:o, s:I, s:o, s:o, s:s, s:o, s:o}",
+          "code", (json_int_t) TALER_EC_TRACK_TRANSFER_CONFLICTING_REPORTS,
+          "hint", "disagreement about deposit valuation",
+          "exchange_deposit_proof", exchange_proof,
+          "conflict_offset", (json_int_t) rctx->current_offset,
+          "exchange_transfer_proof", rctx->original_response,
+          "coin_pub", GNUNET_JSON_from_data_auto (coin_pub),
+          "h_contract_terms", GNUNET_JSON_from_data_auto (
+            &ttd->h_contract_terms),
+          "amount_with_fee", TALER_JSON_from_amount (amount_with_fee),
+          "deposit_fee", TALER_JSON_from_amount (deposit_fee));
+    return;
+  }
+  rctx->check_transfer_result = GNUNET_OK;
+}
+
+
+/**
+ * Check that the given @a wire_fee is what the
+ * @a exchange_pub should charge at the @a execution_time.
+ * If the fee is correct (according to our database),
+ * return #GNUNET_OK.  If we do not have the fee structure
+ * in our DB, we just accept it and return #GNUNET_NO;
+ * if we have proof that the fee is bogus, we respond with
+ * the proof to the client and return #GNUNET_SYSERR.
+ *
+ * @param rctx context of the transfer to respond to
+ * @param json response from the exchange
+ * @param execution_time time of the wire transfer
+ * @param wire_fee fee claimed by the exchange
+ * @return #GNUNET_SYSERR if we returned hard proof of
+ *   missbehavior from the exchange to the client
+ */
+static int
+check_wire_fee (struct TrackTransferContext *rctx,
+                const json_t *json,
+                struct GNUNET_TIME_Absolute execution_time,
+                const struct TALER_Amount *wire_fee)
+{
+  const struct TALER_MasterPublicKeyP *master_pub;
+  struct GNUNET_HashCode h_wire_method;
+  struct TALER_Amount expected_fee;
+  struct TALER_Amount closing_fee;
+  struct TALER_MasterSignatureP master_sig;
+  struct GNUNET_TIME_Absolute start_date;
+  struct GNUNET_TIME_Absolute end_date;
+  enum GNUNET_DB_QueryStatus qs;
+  const struct TALER_EXCHANGE_Keys *keys;
+
+  keys = TALER_EXCHANGE_get_keys (rctx->eh);
+  if (NULL == keys)
+  {
+    GNUNET_break (0);
+    return GNUNET_NO;
+  }
+  master_pub = &keys->master_pub;
+  GNUNET_CRYPTO_hash (rctx->wire_method,
+                      strlen (rctx->wire_method) + 1,
+                      &h_wire_method);
+  db->preflight (db->cls);
+  qs = db->lookup_wire_fee (db->cls,
+                            master_pub,
+                            &h_wire_method,
+                            execution_time,
+                            &expected_fee,
+                            &closing_fee,
+                            &start_date,
+                            &end_date,
+                            &master_sig);
+  if (0 >= qs)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Failed to find wire fee for `%s' and method `%s' at %s in DB, 
accepting blindly that the fee is %s\n",
+                TALER_B2S (master_pub),
+                rctx->wire_method,
+                GNUNET_STRINGS_absolute_time_to_string (execution_time),
+                TALER_amount2s (wire_fee));
+    return GNUNET_NO;
+  }
+  if (0 <= TALER_amount_cmp (&expected_fee,
+                             wire_fee))
+    return GNUNET_OK; /* expected_fee >= wire_fee */
+
+  /* Wire fee check failed, export proof to client */
+  resume_track_transfer_with_response (
+    rctx,
+    MHD_HTTP_FAILED_DEPENDENCY,
+    TALER_MHD_make_json_pack (
+      "{s:I, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:O}",
+      "code", (json_int_t) TALER_EC_TRACK_TRANSFER_JSON_BAD_WIRE_FEE,
+      "wire_fee", TALER_JSON_from_amount (wire_fee),
+      "execution_time", GNUNET_JSON_from_time_abs (execution_time),
+      "expected_wire_fee", TALER_JSON_from_amount (&expected_fee),
+      "expected_closing_fee", TALER_JSON_from_amount (&closing_fee),
+      "start_date", GNUNET_JSON_from_time_abs (start_date),
+      "end_date", GNUNET_JSON_from_time_abs (end_date),
+      "master_sig", GNUNET_JSON_from_data_auto (&master_sig),
+      "master_pub", GNUNET_JSON_from_data_auto (master_pub),
+      "json", json));
+  return GNUNET_SYSERR;
+}
+
+
+/**
+ * Function called with detailed wire transfer data, including all
+ * of the coin transactions that were combined into the wire transfer.
+ *
+ * @param cls closure
+ * @param hr HTTP response details
+ * @param exchange_pub public key of the exchange used to sign @a json
+ * @param h_wire hash of the wire transfer address the transfer went to, or 
NULL on error
+ * @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
+ */
+static void
+wire_transfer_cb (void *cls,
+                  const struct TALER_EXCHANGE_HttpResponse *hr,
+                  const struct TALER_ExchangePublicKeyP *exchange_pub,
+                  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)
+{
+  struct TrackTransferContext *rctx = cls;
+  json_t *jresponse;
+  enum GNUNET_DB_QueryStatus qs;
+
+  rctx->wdh = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Got response code %u from exchange for /track/transfer\n",
+              hr->http_status);
+  if (MHD_HTTP_OK != hr->http_status)
+  {
+    resume_track_transfer_with_response (
+      rctx,
+      MHD_HTTP_FAILED_DEPENDENCY,
+      TALER_MHD_make_json_pack (
+        "{s:I, s:I, s:I, s:O}",
+        "code", (json_int_t) TALER_EC_TRACK_TRANSFER_EXCHANGE_ERROR,
+        "exchange_code", (json_int_t) hr->ec,
+        "exchange_http_status", (json_int_t) hr->http_status,
+        "exchange_reply", hr->reply));
+    return;
+  }
+  for (unsigned int i = 0; i<MAX_RETRIES; i++)
+  {
+    db->preflight (db->cls);
+    qs = db->store_transfer_to_proof (db->cls,
+                                      rctx->url,
+                                      &rctx->wtid,
+                                      execution_time,
+                                      exchange_pub,
+                                      hr->reply);
+    if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
+      break;
+  }
+  if (0 > qs)
+  {
+    /* Special report if retries insufficient */
+    GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+    /* Always report on hard error as well to enable diagnostics */
+    GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
+    resume_track_transfer_with_response
+      (rctx,
+      MHD_HTTP_INTERNAL_SERVER_ERROR,
+      TALER_MHD_make_json_pack ("{s:I, s:s}",
+                                "code",
+                                (json_int_t)
+                                
TALER_EC_TRACK_TRANSFER_DB_STORE_TRANSFER_ERROR,
+                                "details",
+                                "failed to store response from exchange to 
local database"));
+    return;
+  }
+  rctx->original_response = hr->reply;
+
+  if (GNUNET_SYSERR ==
+      check_wire_fee (rctx,
+                      hr->reply,
+                      execution_time,
+                      wire_fee))
+    return;
+
+  /* Now we want to double-check that any (Taler coin) deposit
+   * which is accounted into _this_ wire transfer, does exist
+   * into _our_ database.  This is the rationale: if the
+   * exchange paid us for it, we must have received it _beforehands_!
+   *
+   * details_length is how many (Taler coin) deposits have been
+   * aggregated into _this_ wire transfer.
+   *///
+  for (unsigned int i = 0; i<details_length; i++)
+  {
+    rctx->current_offset = i;
+    rctx->current_detail = &details[i];
+    /* Set the coin as "never seen" before. */
+    rctx->check_transfer_result = GNUNET_NO;
+    db->preflight (db->cls);
+    qs = db->find_payments_by_hash_and_coin (db->cls,
+                                             &details[i].h_contract_terms,
+                                             &rctx->mi->pubkey,
+                                             &details[i].coin_pub,
+                                             &check_transfer,
+                                             rctx);
+    if (0 > qs)
+    {
+      /* single, read-only SQL statements should never cause
+         serialization problems */
+      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+      /* Always report on hard error as well to enable diagnostics */
+      GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
+      resume_track_transfer_with_response
+        (rctx,
+        MHD_HTTP_INTERNAL_SERVER_ERROR,
+        TALER_MHD_make_json_pack ("{s:I, s:s}",
+                                  "code",
+                                  (json_int_t)
+                                  
TALER_EC_TRACK_TRANSFER_DB_FETCH_DEPOSIT_ERROR,
+                                  "details",
+                                  "failed to obtain deposit data from local 
database"));
+      return;
+    }
+    if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+    {
+      /* The exchange says we made this deposit, but WE do not
+         recall making it (corrupted / unreliable database?)!
+         Well, let's say thanks and accept the money! */
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Failed to find payment data in DB\n");
+      rctx->check_transfer_result = GNUNET_OK;
+    }
+    if (GNUNET_NO == rctx->check_transfer_result)
+    {
+      /* Internal error: how can we have called #check_transfer()
+         but still have no result? */
+      GNUNET_break (0);
+      resume_track_transfer_with_response
+        (rctx,
+        MHD_HTTP_INTERNAL_SERVER_ERROR,
+        TALER_MHD_make_json_pack ("{s:I, s:s, s:I, s:s}",
+                                  "code",
+                                  (json_int_t)
+                                  
TALER_EC_TRACK_TRANSFER_DB_INTERNAL_LOGIC_ERROR,
+                                  "details", "internal logic error",
+                                  "line", (json_int_t) __LINE__,
+                                  "file", __FILE__));
+      return;
+    }
+    if (GNUNET_SYSERR == rctx->check_transfer_result)
+    {
+      /* #check_transfer() failed, report conflict! */
+      GNUNET_break_op (0);
+      GNUNET_assert (NULL != rctx->response);
+      resume_track_transfer_with_response
+        (rctx,
+        MHD_HTTP_FAILED_DEPENDENCY,
+        rctx->response);
+      rctx->response = NULL;
+      return;
+    }
+    /* Response is consistent with the /deposit we made,
+       remember it for future reference */
+    for (unsigned int r = 0; r<MAX_RETRIES; r++)
+    {
+      db->preflight (db->cls);
+      qs = db->store_coin_to_transfer (db->cls,
+                                       &details[i].h_contract_terms,
+                                       &details[i].coin_pub,
+                                       &rctx->wtid);
+      if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
+        break;
+    }
+    if (0 > qs)
+    {
+      /* Special report if retries insufficient */
+      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+      /* Always report on hard error as well to enable diagnostics */
+      GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
+      resume_track_transfer_with_response
+        (rctx,
+        MHD_HTTP_INTERNAL_SERVER_ERROR,
+        TALER_MHD_make_json_pack ("{s:I, s:s}",
+                                  "code",
+                                  (json_int_t)
+                                  TALER_EC_TRACK_TRANSFER_DB_STORE_COIN_ERROR,
+                                  "details",
+                                  "failed to store response from exchange to 
local database"));
+      return;
+    }
+  }
+  rctx->original_response = NULL;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "About to call tracks transformator.\n");
+
+  if (NULL == (jresponse =
+                 transform_response (hr->reply,
+                                     rctx)))
+  {
+    resume_track_transfer_with_response
+      (rctx,
+      MHD_HTTP_INTERNAL_SERVER_ERROR,
+      TALER_MHD_make_error (TALER_EC_TRACK_TRANSFER_JSON_RESPONSE_ERROR,
+                            "Fail to elaborate the response."));
+    return;
+  }
+
+  resume_track_transfer_with_response (rctx,
+                                       MHD_HTTP_OK,
+                                       TALER_MHD_make_json (jresponse));
+  json_decref (jresponse);
+}
+
+
+/**
+ * Function called with the result of our exchange lookup.
+ *
+ * @param cls the `struct TrackTransferContext`
+ * @param hr HTTP response details
+ * @param eh NULL if exchange was not found to be acceptable
+ * @param wire_fee NULL (we did not specify a wire method)
+ * @param exchange_trusted #GNUNET_YES if this exchange is trusted by config
+ */
+static void
+process_track_transfer_with_exchange (void *cls,
+                                      const struct
+                                      TALER_EXCHANGE_HttpResponse *hr,
+                                      struct TALER_EXCHANGE_Handle *eh,
+                                      const struct TALER_Amount *wire_fee,
+                                      int exchange_trusted)
+{
+  struct TrackTransferContext *rctx = cls;
+
+  rctx->fo = NULL;
+  if (MHD_HTTP_OK != hr->http_status)
+  {
+    /* The request failed somehow */
+    GNUNET_break_op (0);
+    resume_track_transfer_with_response (
+      rctx,
+      MHD_HTTP_FAILED_DEPENDENCY,
+      TALER_MHD_make_json_pack (
+        (NULL != hr->reply)
+        ? "{s:s, s:I, s:I, s:I, s:O}"
+        : "{s:s, s:I, s:I, s:I}",
+        "hint", "failed to obtain meta-data from exchange",
+        "code", (json_int_t) TALER_EC_TRACK_TRANSFER_EXCHANGE_KEYS_FAILURE,
+        "exchange_http_status", (json_int_t) hr->http_status,
+        "exchange_code", (json_int_t) hr->ec,
+        "exchange_reply", hr->reply));
+    return;
+  }
+  rctx->eh = eh;
+  rctx->wdh = TALER_EXCHANGE_transfers_get (eh,
+                                            &rctx->wtid,
+                                            &wire_transfer_cb,
+                                            rctx);
+  if (NULL == rctx->wdh)
+  {
+    GNUNET_break (0);
+    resume_track_transfer_with_response
+      (rctx,
+      MHD_HTTP_INTERNAL_SERVER_ERROR,
+      TALER_MHD_make_json_pack ("{s:I, s:s}",
+                                "code",
+                                (json_int_t)
+                                TALER_EC_TRACK_TRANSFER_REQUEST_ERROR,
+                                "error",
+                                "failed to run /transfers/ GET on exchange"));
+  }
+}
+
+
+/**
+ * Handle a timeout for the processing of the track transfer request.
+ *
+ * @param cls closure
+ */
+static void
+handle_track_transfer_timeout (void *cls)
+{
+  struct TrackTransferContext *rctx = cls;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Resuming /track/transfer with error after timeout\n");
+  rctx->timeout_task = NULL;
+
+  if (NULL != rctx->fo)
+  {
+    TMH_EXCHANGES_find_exchange_cancel (rctx->fo);
+    rctx->fo = NULL;
+  }
+  resume_track_transfer_with_response (rctx,
+                                       MHD_HTTP_SERVICE_UNAVAILABLE,
+                                       TALER_MHD_make_error (
+                                         
TALER_EC_TRACK_TRANSFER_EXCHANGE_TIMEOUT,
+                                         "exchange not reachable"));
+}
+
+
+/**
+ * Function called with information about a wire transfer identifier.
+ * Generate a response based on the given @a proof.
+ *
+ * @param cls closure
+ * @param proof proof from exchange about what the wire transfer was for.
+ *              should match the `TrackTransactionResponse` format
+ *              of the exchange
+ */
+static void
+proof_cb (void *cls,
+          const json_t *proof)
+{
+  struct TrackTransferContext *rctx = cls;
+  json_t *transformed_response;
+
+  if (NULL == (transformed_response =
+                 transform_response (proof,
+                                     rctx)))
+  {
+    rctx->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+    rctx->response
+      = TALER_MHD_make_error (TALER_EC_TRACK_TRANSFER_JSON_RESPONSE_ERROR,
+                              "Fail to elaborate response.");
+    return;
+  }
+
+  rctx->response_code = MHD_HTTP_OK;
+  rctx->response = TALER_MHD_make_json (transformed_response);
+  json_decref (transformed_response);
+}
+
+
+/**
+ * Manages a /track/transfer call, thus it calls the /track/wtid
+ * offered by the exchange in order to return the set of transfers
+ * (of coins) associated with a given wire transfer.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param mi merchant backend instance, never NULL
+ * @return MHD result code
+ */
+MHD_RESULT
+MH_handler_track_transfer (struct TMH_RequestHandler *rh,
+                           struct MHD_Connection *connection,
+                           void **connection_cls,
+                           const char *upload_data,
+                           size_t *upload_data_size,
+                           struct MerchantInstance *mi)
+{
+  struct TrackTransferContext *rctx;
+  const char *str;
+  const char *url;
+  const char *wire_method;
+  MHD_RESULT ret;
+  enum GNUNET_DB_QueryStatus qs;
+
+  if (NULL == *connection_cls)
+  {
+    rctx = GNUNET_new (struct TrackTransferContext);
+    rctx->hc.cc = &track_transfer_cleanup;
+    rctx->connection = connection;
+    *connection_cls = rctx;
+  }
+  else
+  {
+    /* not first call, recover state */
+    rctx = *connection_cls;
+  }
+
+  if (0 != rctx->response_code)
+  {
+    /* We are *done* processing the request, just queue the response (!) */
+    if (UINT_MAX == rctx->response_code)
+    {
+      GNUNET_break (0);
+      return MHD_NO; /* hard error */
+    }
+    ret = MHD_queue_response (connection,
+                              rctx->response_code,
+                              rctx->response);
+    if (NULL != rctx->response)
+    {
+      MHD_destroy_response (rctx->response);
+      rctx->response = NULL;
+    }
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Queueing response (%u) for /track/transfer (%s).\n",
+                (unsigned int) rctx->response_code,
+                ret ? "OK" : "FAILED");
+    return ret;
+  }
+  if ( (NULL != rctx->fo) ||
+       (NULL != rctx->eh) )
+  {
+    /* likely old MHD version */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Not sure why we are here, should be suspended\n");
+    return MHD_YES; /* still work in progress */
+  }
+
+  url = MHD_lookup_connection_value (connection,
+                                     MHD_GET_ARGUMENT_KIND,
+                                     "exchange");
+  if (NULL == url)
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       TALER_EC_PARAMETER_MISSING,
+                                       "exchange");
+  rctx->url = GNUNET_strdup (url);
+
+  /* FIXME: change again: we probably don't want the wire_method
+     but rather the _account_ (section) here! */
+  wire_method = MHD_lookup_connection_value (connection,
+                                             MHD_GET_ARGUMENT_KIND,
+                                             "wire_method");
+  if (NULL == wire_method)
+  {
+    if (1)
+    {
+      /* temporary work-around until demo is adjusted... */
+      GNUNET_break (0);
+      wire_method = "x-taler-bank";
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Client needs fixing, see API change for #4943!\n");
+    }
+    else
+      return TALER_MHD_reply_with_error (connection,
+                                         MHD_HTTP_BAD_REQUEST,
+                                         TALER_EC_PARAMETER_MISSING,
+                                         "wire_method");
+  }
+  rctx->wire_method = GNUNET_strdup (wire_method);
+  rctx->mi = mi;
+  str = MHD_lookup_connection_value (connection,
+                                     MHD_GET_ARGUMENT_KIND,
+                                     "wtid");
+  if (NULL == str)
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       TALER_EC_PARAMETER_MISSING,
+                                       "wtid");
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_string_to_data (str,
+                                     strlen (str),
+                                     &rctx->wtid,
+                                     sizeof (rctx->wtid)))
+  {
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       TALER_EC_PARAMETER_MALFORMED,
+                                       "wtid");
+  }
+
+  /* Check if reply is already in database! */
+  db->preflight (db->cls);
+  qs = db->find_proof_by_wtid (db->cls,
+                               rctx->url,
+                               &rctx->wtid,
+                               &proof_cb,
+                               rctx);
+  if (0 > qs)
+  {
+    /* Simple select queries should not cause serialization issues */
+    GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+    /* Always report on hard error as well to enable diagnostics */
+    GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                       
TALER_EC_TRACK_TRANSFER_DB_FETCH_DEPOSIT_ERROR,
+                                       "Fail to query database about proofs");
+  }
+  if (0 != rctx->response_code)
+  {
+    ret = MHD_queue_response (connection,
+                              rctx->response_code,
+                              rctx->response);
+    if (NULL != rctx->response)
+    {
+      MHD_destroy_response (rctx->response);
+      rctx->response = NULL;
+    }
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Queueing response (%u) for /track/transfer (%s).\n",
+                (unsigned int) rctx->response_code,
+                ret ? "OK" : "FAILED");
+    return ret;
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Suspending /track/transfer handling while working with the 
exchange\n");
+  MHD_suspend_connection (connection);
+  rctx->fo = TMH_EXCHANGES_find_exchange (url,
+                                          NULL,
+                                          GNUNET_NO,
+                                          
&process_track_transfer_with_exchange,
+                                          rctx);
+  rctx->timeout_task
+    = GNUNET_SCHEDULER_add_delayed (TRACK_TIMEOUT,
+                                    &handle_track_transfer_timeout,
+                                    rctx);
+  return MHD_YES;
+}
+
+
+/* end of taler-merchant-httpd_track-transfer.c */
diff --git a/src/backend/taler-merchant-httpd_private-post-transfers.h 
b/src/backend/taler-merchant-httpd_private-post-transfers.h
new file mode 100644
index 0000000..0463295
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-post-transfers.h
@@ -0,0 +1,49 @@
+/*
+  This file is part of TALER
+  (C) 2014-2020 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU General Public License as published by the Free Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file backend/taler-merchant-httpd_track-transfer.h
+ * @brief headers for /track/transfer handler
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#ifndef TALER_MERCHANT_HTTPD_TRACK_TRANSFER_H
+#define TALER_MERCHANT_HTTPD_TRACK_TRANSFER_H
+#include <microhttpd.h>
+#include "taler-merchant-httpd.h"
+
+/**
+ * Manages a /track/transfer call, thus it calls the /wire/transfer
+ * offered by the exchange in order to return the set of transfers
+ * (of coins) associated with a given wire transfer
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param mi merchant backend instance, never NULL
+ * @return MHD result code
+ */
+MHD_RESULT
+MH_handler_track_transfer (struct TMH_RequestHandler *rh,
+                           struct MHD_Connection *connection,
+                           void **connection_cls,
+                           const char *upload_data,
+                           size_t *upload_data_size,
+                           struct MerchantInstance *mi);
+
+
+#endif
diff --git a/src/include/taler_merchant_service.h 
b/src/include/taler_merchant_service.h
index bc5eae1..a4312c0 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -1363,6 +1363,62 @@ TALER_MERCHANT_order_delete_cancel (
   struct TALER_MERCHANT_OrderDeleteHandle *odh);
 
 
+/**
+ * Handle to a POST /orders/$ID/claim handle
+ */
+struct TALER_MERCHANT_OrderClaimHandle;
+
+
+/**
+ * Callback called to process a POST /orders/$ID/claim response.
+ *
+ * @param cls closure
+ * @param hr HTTP response details
+ * @param contract_terms the details of the contract
+ * @param sig merchant's signature over @a contract_terms (already verified)
+ * @param h_contract_terms hash over @a contract_terms (computed
+ *        client-side to verify @a sig)
+ */
+typedef void
+(*TALER_MERCHANT_OrderClaimCallback) (
+  void *cls,
+  const struct TALER_MERCHANT_HttpResponse *hr,
+  const json_t *contract_terms,
+  const struct TALER_MerchantSignatureP *sig,
+  const struct GNUNET_HashCode *h_contract_terms);
+
+
+/**
+ * Calls the POST /orders/$ID/claim API at the backend.  That is,
+ * retrieve the final contract terms including the client nonce.
+ * This is a PUBLIC API for wallets.
+ *
+ * @param ctx execution context
+ * @param backend_url base URL of the merchant backend
+ * @param order_id order id used to perform the lookup
+ * @param nonce nonce to use to claim the proposal
+ * @param cb callback which will work the response gotten from the backend
+ * @param cb_cls closure to pass to @a cb
+ * @return handle for this handle, NULL upon errors
+ */
+struct TALER_MERCHANT_OrderClaimHandle *
+TALER_MERCHANT_order_claim (struct GNUNET_CURL_Context *ctx,
+                            const char *backend_url,
+                            const char *order_id,
+                            const struct GNUNET_CRYPTO_EddsaPublicKey *nonce,
+                            TALER_MERCHANT_OrderClaimCallback cb,
+                            void *cb_cls);
+
+
+/**
+ * Cancel a POST /order/$ID/claim request.
+ *
+ * @param och handle to the request to be canceled
+ */
+void
+TALER_MERCHANT_order_claim_cancel (struct TALER_MERCHANT_OrderClaimHandle 
*och);
+
+
 /* *********************   OLD ************************** */
 
 
@@ -1520,63 +1576,6 @@ TALER_MERCHANT_refund_increase_cancel (
 /* *********************  /proposal *********************** */
 
 
-/**
- * Handle to a GET /proposal operation
- */
-struct TALER_MERCHANT_ProposalLookupOperation;
-
-
-/**
- * Callback called to work a GET /proposal response.
- *
- * @param cls closure
- * @param hr HTTP response details
- * @param contract_terms the details of the contract
- * @param sig merchant's signature over @a contract_terms
- * @param contract_hash hash over @a contract_terms
- */
-typedef void
-(*TALER_MERCHANT_ProposalLookupOperationCallback) (
-  void *cls,
-  const struct TALER_MERCHANT_HttpResponse *hr,
-  const json_t *contract_terms,
-  const struct TALER_MerchantSignatureP *sig,
-  const struct GNUNET_HashCode *contract_hash);
-
-
-/**
- * Calls the GET /proposal API at the backend.  That is,
- * retrieve a proposal data by providing its transaction id.
- *
- * @param ctx execution context
- * @param backend_url base URL of the merchant backend
- * @param order_id order id used to perform the lookup
- * @param nonce nonce to use, only used when requesting the proposal the first 
time,
- *              can be NULL to omit the nonce (after the first request)
- * @param plo_cb callback which will work the response gotten from the backend
- * @param plo_cb_cls closure to pass to @a history_cb
- * @return handle for this operation, NULL upon errors
- */
-struct TALER_MERCHANT_ProposalLookupOperation *
-TALER_MERCHANT_proposal_lookup (
-  struct GNUNET_CURL_Context *ctx,
-  const char *backend_url,
-  const char *order_id,
-  const struct GNUNET_CRYPTO_EddsaPublicKey *nonce,
-  TALER_MERCHANT_ProposalLookupOperationCallback plo_cb,
-  void *plo_cb_cls);
-
-
-/**
- * Cancel a GET /proposal request.
- *
- * @param plo handle to the request to be canceled
- */
-void
-TALER_MERCHANT_proposal_lookup_cancel (
-  struct TALER_MERCHANT_ProposalLookupOperation *plo);
-
-
 /* *********************  /pay *********************** */
 
 
diff --git a/src/include/taler_merchant_testing_lib.h 
b/src/include/taler_merchant_testing_lib.h
index 33d23e5..4e0b3fd 100644
--- a/src/include/taler_merchant_testing_lib.h
+++ b/src/include/taler_merchant_testing_lib.h
@@ -425,27 +425,27 @@ TALER_TESTING_cmd_merchant_post_orders (const char *label,
                                         const char *order);
 
 
-/* ******************** OLD ******************* */
-
-
 /**
- * Make a "proposal lookup" command.
+ * Make a "claim order" command.
  *
  * @param label command label.
  * @param merchant_url base URL of the merchant backend
  *        serving the proposal lookup request.
  * @param http_status expected HTTP response code.
- * @param proposal_reference reference to a "proposal" CMD.
- * @param order_id order id to lookup, can be NULL.
- *
+ * @param order_reference reference to a POST order CMD, can be NULL if @a 
order_id given
+ * @param order_id order id to lookup, can be NULL (then we use @a 
order_reference)
  * @return the command.
  */
 struct TALER_TESTING_Command
-TALER_TESTING_cmd_merchant_post_orders_lookup (const char *label,
-                                               const char *merchant_url,
-                                               unsigned int http_status,
-                                               const char *proposal_reference,
-                                               const char *order_id);
+TALER_TESTING_cmd_merchant_claim_order (const char *label,
+                                        const char *merchant_url,
+                                        unsigned int http_status,
+                                        const char *order_reference,
+                                        const char *order_id);
+
+
+/* ******************** OLD ******************* */
+
 
 /**
  * Make a "check payment" test command.
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 2911c75..6e6fd54 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -29,9 +29,10 @@ libtalermerchant_la_SOURCES = \
   merchant_api_post_instances.c \
   merchant_api_post_products.c \
   merchant_api_post_orders.c \
+  merchant_api_post_order_claim.c \
+ \
   merchant_api_check_payment.c \
   merchant_api_history.c \
-  merchant_api_proposal_lookup.c \
   merchant_api_pay.c \
   merchant_api_poll_payment.c \
   merchant_api_refund.c \
diff --git a/src/lib/merchant_api_proposal_lookup.c 
b/src/lib/merchant_api_post_order_claim.c
similarity index 51%
rename from src/lib/merchant_api_proposal_lookup.c
rename to src/lib/merchant_api_post_order_claim.c
index 0f2b0f3..31be123 100644
--- a/src/lib/merchant_api_proposal_lookup.c
+++ b/src/lib/merchant_api_post_order_claim.c
@@ -17,8 +17,8 @@
   see <http://www.gnu.org/licenses/>
 */
 /**
- * @file lib/merchant_api_proposal_lookup.c
- * @brief Implementation of the /proposal GET
+ * @file lib/merchant_api_post_order_claim.c
+ * @brief Implementation of POST /orders/$ID/claim
  * @author Christian Grothoff
  * @author Marcello Stanisci
  */
@@ -35,12 +35,12 @@
 
 
 /**
- * Structure representing a GET /proposal operation.
+ * Structure representing a POST /orders/$ID/claim operation.
  */
-struct TALER_MERCHANT_ProposalLookupOperation
+struct TALER_MERCHANT_OrderClaimHandle
 {
   /**
-   * Full URL, includes "/proposal".
+   * Full URL, includes "/orders/$ID/claim".
    */
   char *url;
 
@@ -52,7 +52,7 @@ struct TALER_MERCHANT_ProposalLookupOperation
   /**
    * Function to call with the result.
    */
-  TALER_MERCHANT_ProposalLookupOperationCallback cb;
+  TALER_MERCHANT_OrderClaimCallback cb;
 
   /**
    * Closure for @a cb.
@@ -65,31 +65,26 @@ struct TALER_MERCHANT_ProposalLookupOperation
   struct GNUNET_CURL_Context *ctx;
 
   /**
-   * Should we send the lookup operation with a nonce?
+   * Minor context that holds body and headers.
    */
-  int has_nonce;
-
-  /**
-   * Nonce, only initialized if has_nonce is GNUNET_YES.
-   */
-  struct GNUNET_CRYPTO_EddsaPublicKey nonce;
-
+  struct TALER_CURL_PostContext post_ctx;
 };
 
 
 /**
- * Function called when we're done processing the GET /proposal request.
+ * Function called when we're done processing the
+ * POST /orders/$ID/claim request.
  *
- * @param cls the `struct TALER_MERCHANT_ProposalLookupOperation`
+ * @param cls the `struct TALER_MERCHANT_OrderClaimHandle`
  * @param response_code HTTP response code, 0 on error
  * @param json response body, should be NULL
  */
 static void
-handle_proposal_lookup_finished (void *cls,
-                                 long response_code,
-                                 const void *response)
+handle_post_order_claim_finished (void *cls,
+                                  long response_code,
+                                  const void *response)
 {
-  struct TALER_MERCHANT_ProposalLookupOperation *plo = cls;
+  struct TALER_MERCHANT_OrderClaimHandle *och = cls;
   json_t *contract_terms;
   struct TALER_MerchantSignatureP sig;
   struct GNUNET_HashCode hash;
@@ -106,7 +101,7 @@ handle_proposal_lookup_finished (void *cls,
     .reply = json
   };
 
-  plo->job = NULL;
+  och->job = NULL;
   if (MHD_HTTP_OK != response_code)
   {
     hr.ec = TALER_JSON_get_error_code (json);
@@ -115,12 +110,12 @@ handle_proposal_lookup_finished (void *cls,
                 "Proposal lookup failed with HTTP status code %u/%d\n",
                 (unsigned int) response_code,
                 (int) hr.ec);
-    plo->cb (plo->cb_cls,
+    och->cb (och->cb_cls,
              &hr,
              NULL,
              NULL,
              NULL);
-    TALER_MERCHANT_proposal_lookup_cancel (plo);
+    TALER_MERCHANT_order_claim_cancel (och);
     return;
   }
 
@@ -130,16 +125,16 @@ handle_proposal_lookup_finished (void *cls,
                          NULL, NULL))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "proposal lookup failed to parse JSON\n");
+                "Claiming order failed: could not parse JSON response\n");
     GNUNET_break_op (0);
     hr.ec = TALER_EC_INVALID_RESPONSE;
     hr.http_status = 0;
-    plo->cb (plo->cb_cls,
+    och->cb (och->cb_cls,
              &hr,
              NULL,
              NULL,
              NULL);
-    TALER_MERCHANT_proposal_lookup_cancel (plo);
+    TALER_MERCHANT_order_claim_cancel (och);
     return;
   }
 
@@ -151,27 +146,22 @@ handle_proposal_lookup_finished (void *cls,
     hr.ec = TALER_EC_CLIENT_INTERNAL_FAILURE;
     hr.http_status = 0;
     GNUNET_JSON_parse_free (spec);
-    plo->cb (plo->cb_cls,
+    och->cb (och->cb_cls,
              &hr,
              NULL,
              NULL,
              NULL);
-    TALER_MERCHANT_proposal_lookup_cancel (plo);
+    TALER_MERCHANT_order_claim_cancel (och);
     return;
   }
 
-  plo->job = NULL;
-  /**
-   * As no data is supposed to be extracted from this
-   * call, we just invoke the provided callback.
-   */
-  plo->cb (plo->cb_cls,
+  och->cb (och->cb_cls,
            &hr,
            contract_terms,
            &sig,
            &hash);
   GNUNET_JSON_parse_free (spec);
-  TALER_MERCHANT_proposal_lookup_cancel (plo);
+  TALER_MERCHANT_order_claim_cancel (och);
 }
 
 
@@ -183,97 +173,97 @@ handle_proposal_lookup_finished (void *cls,
  * @param backend_url base URL of the merchant backend
  * @param order_id order id used to perform the lookup
  * @param nonce nonce used to perform the lookup
- * @param plo_cb callback which will work the response gotten from the backend
- * @param plo_cb_cls closure to pass to @a history_cb
- * @return handle for this operation, NULL upon errors
+ * @param cb callback which will work the response gotten from the backend
+ * @param cb_cls closure to pass to @a cb
+ * @return handle for this handle, NULL upon errors
  */
-struct TALER_MERCHANT_ProposalLookupOperation *
-TALER_MERCHANT_proposal_lookup (
-  struct GNUNET_CURL_Context *ctx,
-  const char *backend_url,
-  const char *order_id,
-  const struct GNUNET_CRYPTO_EddsaPublicKey *nonce,
-  TALER_MERCHANT_ProposalLookupOperationCallback plo_cb,
-  void *plo_cb_cls)
+struct TALER_MERCHANT_OrderClaimHandle *
+TALER_MERCHANT_order_claim (struct GNUNET_CURL_Context *ctx,
+                            const char *backend_url,
+                            const char *order_id,
+                            const struct GNUNET_CRYPTO_EddsaPublicKey *nonce,
+                            TALER_MERCHANT_OrderClaimCallback cb,
+                            void *cb_cls)
 {
-  struct TALER_MERCHANT_ProposalLookupOperation *plo;
-  CURL *eh;
-  char *nonce_str = NULL;
+  struct TALER_MERCHANT_OrderClaimHandle *och;
+  json_t *req_obj;
 
-  plo = GNUNET_new (struct TALER_MERCHANT_ProposalLookupOperation);
-  plo->ctx = ctx;
-  plo->cb = plo_cb;
-  plo->cb_cls = plo_cb_cls;
-  if (NULL != nonce)
+  req_obj = json_pack ("{s:o}",
+                       "nonce",
+                       GNUNET_JSON_from_data_auto (nonce));
+  if (NULL == req_obj)
   {
-    plo->has_nonce = GNUNET_YES;
-    plo->nonce = *nonce;
-    nonce_str = GNUNET_STRINGS_data_to_string_alloc (
-      nonce,
-      sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
+    GNUNET_break (0);
+    return NULL;
   }
-  plo->url = TALER_url_join (backend_url,
-                             "proposal",
-                             "order_id",
-                             order_id,
-                             "nonce",
-                             nonce_str,
-                             NULL);
-  GNUNET_free_non_null (nonce_str);
-  if (NULL == plo->url)
+  och = GNUNET_new (struct TALER_MERCHANT_OrderClaimHandle);
+  och->ctx = ctx;
+  och->cb = cb;
+  och->cb_cls = cb_cls;
+  {
+    char *path;
+
+    GNUNET_asprintf (&path,
+                     "orders/%s/claim",
+                     order_id);
+    och->url = TALER_url_join (backend_url,
+                               path,
+                               NULL);
+    GNUNET_free (path);
+  }
+  if (NULL == och->url)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Could not construct request URL.\n");
-    GNUNET_free (plo);
+    json_decref (req_obj);
+    GNUNET_free (och);
     return NULL;
   }
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "looking up proposal from %s\n",
-              plo->url);
-  eh = curl_easy_init ();
-  if (CURLE_OK != curl_easy_setopt (eh,
-                                    CURLOPT_URL,
-                                    plo->url))
+              "Claiming order at %s\n",
+              och->url);
   {
-    GNUNET_break (0);
-    curl_easy_cleanup (eh);
-    GNUNET_free (plo->url);
-    GNUNET_free (plo);
-    return NULL;
-  }
+    CURL *eh;
 
-  if (NULL == (plo->job = GNUNET_CURL_job_add (ctx,
-                                               eh,
-                                               GNUNET_YES,
-                                               
&handle_proposal_lookup_finished,
-                                               plo)))
-  {
-    GNUNET_break (0);
-    GNUNET_free (plo->url);
-    GNUNET_free (plo);
-    return NULL;
+    eh = curl_easy_init ();
+    GNUNET_assert (NULL != eh);
+    GNUNET_assert (GNUNET_OK ==
+                   TALER_curl_easy_post (&och->post_ctx,
+                                         eh,
+                                         req_obj));
+    json_decref (req_obj);
+    GNUNET_assert (CURLE_OK ==
+                   curl_easy_setopt (eh,
+                                     CURLOPT_URL,
+                                     och->url));
+    och->job = GNUNET_CURL_job_add2 (ctx,
+                                     eh,
+                                     och->post_ctx.headers,
+                                     &handle_post_order_claim_finished,
+                                     och);
+    GNUNET_assert (NULL != och->job);
   }
-  return plo;
+  return och;
 }
 
 
 /**
- * Cancel a GET /proposal request.
+ * Cancel a POST /orders/$ID/claim request.
  *
- * @param plo handle to the request to be canceled
+ * @param och handle to the request to be canceled
  */
 void
-TALER_MERCHANT_proposal_lookup_cancel (
-  struct TALER_MERCHANT_ProposalLookupOperation *plo)
+TALER_MERCHANT_order_claim_cancel (struct TALER_MERCHANT_OrderClaimHandle *och)
 {
-  if (NULL != plo->job)
+  if (NULL != och->job)
   {
-    GNUNET_CURL_job_cancel (plo->job);
-    plo->job = NULL;
+    GNUNET_CURL_job_cancel (och->job);
+    och->job = NULL;
   }
-  GNUNET_free (plo->url);
-  GNUNET_free (plo);
+  TALER_curl_easy_post_finished (&och->post_ctx);
+  GNUNET_free (och->url);
+  GNUNET_free (och);
 }
 
 
-/* end of merchant_api_proposal_lookup.c */
+/* end of merchant_api_post_order_claim.c */
diff --git a/src/lib/merchant_api_post_products.c 
b/src/lib/merchant_api_post_products.c
index af2e4ea..f354fb5 100644
--- a/src/lib/merchant_api_post_products.c
+++ b/src/lib/merchant_api_post_products.c
@@ -243,17 +243,11 @@ TALER_MERCHANT_products_post (
     CURL *eh;
 
     eh = curl_easy_init ();
-    if (GNUNET_OK !=
-        TALER_curl_easy_post (&pph->post_ctx,
-                              eh,
-                              req_obj))
-    {
-      GNUNET_break (0);
-      json_decref (req_obj);
-      GNUNET_free (pph);
-      return NULL;
-    }
-
+    GNUNET_assert (NULL != eh);
+    GNUNET_assert (GNUNET_OK ==
+                   TALER_curl_easy_post (&pph->post_ctx,
+                                         eh,
+                                         req_obj));
     json_decref (req_obj);
     GNUNET_assert (CURLE_OK == curl_easy_setopt (eh,
                                                  CURLOPT_URL,
@@ -263,6 +257,7 @@ TALER_MERCHANT_products_post (
                                      pph->post_ctx.headers,
                                      &handle_post_products_finished,
                                      pph);
+    GNUNET_assert (NULL != pph->job);
   }
   return pph;
 }
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
index d7d0256..c04c5b3 100644
--- a/src/testing/Makefile.am
+++ b/src/testing/Makefile.am
@@ -15,6 +15,7 @@ libtalermerchanttesting_la_LDFLAGS = \
 
 libtalermerchanttesting_la_SOURCES = \
   testing_api_cmd_config.c \
+  testing_api_cmd_claim_order.c \
   testing_api_cmd_get_instance.c \
   testing_api_cmd_get_instances.c \
   testing_api_cmd_get_product.c \
@@ -34,7 +35,6 @@ libtalermerchanttesting_la_SOURCES = \
   testing_api_cmd_pay_abort.c \
   testing_api_cmd_pay_abort_refund.c \
   testing_api_cmd_poll_payment.c \
-  testing_api_cmd_proposal_lookup.c \
   testing_api_cmd_refund_increase.c \
   testing_api_cmd_refund_lookup.c \
   testing_api_cmd_rewind.c \
diff --git a/src/testing/test_merchant_api.c b/src/testing/test_merchant_api.c
index e2fbfc2..a739807 100644
--- a/src/testing/test_merchant_api.c
+++ b/src/testing/test_merchant_api.c
@@ -348,11 +348,11 @@ run (void *cls,
         \"fulfillment_url\": \"https://example.com/\",\
         \"products\": [ {\"description\":\"ice cream\",\
                          \"value\":\"{EUR:5}\"} ] }"),
-    TALER_TESTING_cmd_merchant_post_orders_lookup ("fetch-proposal-2",
-                                                   merchant_url,
-                                                   MHD_HTTP_OK,
-                                                   "create-proposal-2",
-                                                   NULL),
+    TALER_TESTING_cmd_merchant_claim_order ("fetch-proposal-2",
+                                            merchant_url,
+                                            MHD_HTTP_OK,
+                                            "create-proposal-2",
+                                            NULL),
     TALER_TESTING_cmd_pay ("deposit-double-2",
                            merchant_url,
                            MHD_HTTP_CONFLICT,
diff --git a/src/testing/testing_api_cmd_proposal_lookup.c 
b/src/testing/testing_api_cmd_claim_order.c
similarity index 65%
rename from src/testing/testing_api_cmd_proposal_lookup.c
rename to src/testing/testing_api_cmd_claim_order.c
index 78f2fb8..0cdfff0 100644
--- a/src/testing/testing_api_cmd_proposal_lookup.c
+++ b/src/testing/testing_api_cmd_claim_order.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014-2018 Taler Systems SA
+  Copyright (C) 2014-2018, 2020 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
@@ -18,8 +18,8 @@
 */
 
 /**
- * @file exchange/testing_api_cmd_proposal_lookup.c
- * @brief command to execute a proposal lookup
+ * @file exchange/testing_api_cmd_claim_order.c
+ * @brief command to claim an order
  * @author Marcello Stanisci
  */
 #include "platform.h"
@@ -29,10 +29,10 @@
 #include "taler_merchant_testing_lib.h"
 
 /**
- * State for a "proposal lookup" CMD.  Not used by
- * the initial lookup operation.
+ * State for a "order claim" CMD.  Not used by
+ * the initial claim operation.
  */
-struct ProposalLookupState
+struct OrderClaimState
 {
   /**
    * The interpreter state.
@@ -70,18 +70,18 @@ struct ProposalLookupState
   unsigned int http_status;
 
   /**
-   * /proposal/lookup operation handle.
+   * /order/claim operation handle.
    */
-  struct TALER_MERCHANT_ProposalLookupOperation *plo;
+  struct TALER_MERCHANT_OrderClaimHandle *och;
 
   /**
-   * Reference to a proposal operation.  Will offer the
+   * Reference to a order operation.  Will offer the
    * nonce for the operation.
    */
-  const char *proposal_reference;
+  const char *order_reference;
 
   /**
-   * Order id to lookup upon.  If null, the @a proposal_reference
+   * Order id to claim upon.  If null, the @a order_reference
    * will offer this value.
    */
   const char *order_id;
@@ -89,25 +89,25 @@ struct ProposalLookupState
 
 
 /**
- * Free the state of a "proposal lookup" CMD, and possibly
+ * Free the state of a "order claim" CMD, and possibly
  * cancel it if it did not complete.
  *
  * @param cls closure.
  * @param cmd command being freed.
  */
 static void
-proposal_lookup_cleanup (void *cls,
-                         const struct TALER_TESTING_Command *cmd)
+order_claim_cleanup (void *cls,
+                     const struct TALER_TESTING_Command *cmd)
 {
-  struct ProposalLookupState *pls = cls;
+  struct OrderClaimState *pls = cls;
 
-  if (NULL != pls->plo)
+  if (NULL != pls->och)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                 "Command '%s' did not complete\n",
                 cmd->label);
-    TALER_MERCHANT_proposal_lookup_cancel (pls->plo);
-    pls->plo = NULL;
+    TALER_MERCHANT_order_claim_cancel (pls->och);
+    pls->och = NULL;
   }
   if (NULL != pls->contract_terms)
   {
@@ -119,27 +119,27 @@ proposal_lookup_cleanup (void *cls,
 
 
 /**
- * Callback for "proposal lookup" operation, to check the
+ * Callback for "order claim" operation, to check the
  * response code is as expected.
  *
  * @param cls closure
  * @param hr HTTP response we got
  * @param contract_terms the contract terms; they are the
- *        backend-filled up proposal minus cryptographic
+ *        backend-filled up order minus cryptographic
  *        information.
  * @param sig merchant signature over the contract terms.
  * @param hash hash code of the contract terms.
  */
 static void
-proposal_lookup_cb (void *cls,
-                    const struct TALER_MERCHANT_HttpResponse *hr,
-                    const json_t *contract_terms,
-                    const struct TALER_MerchantSignatureP *sig,
-                    const struct GNUNET_HashCode *hash)
+order_claim_cb (void *cls,
+                const struct TALER_MERCHANT_HttpResponse *hr,
+                const json_t *contract_terms,
+                const struct TALER_MerchantSignatureP *sig,
+                const struct GNUNET_HashCode *hash)
 {
-  struct ProposalLookupState *pls = cls;
+  struct OrderClaimState *pls = cls;
 
-  pls->plo = NULL;
+  pls->och = NULL;
   if (pls->http_status != hr->http_status)
     TALER_TESTING_FAIL (pls->is);
   if (MHD_HTTP_OK == hr->http_status)
@@ -173,27 +173,26 @@ proposal_lookup_cb (void *cls,
 
 
 /**
- * Run the "proposal lookup" CMD.
+ * Run the "order claim" CMD.
  *
  * @param cls closure.
  * @param cmd command currently being run.
  * @param is interpreter state.
  */
 static void
-proposal_lookup_run (void *cls,
-                     const struct TALER_TESTING_Command *cmd,
-                     struct TALER_TESTING_Interpreter *is)
+order_claim_run (void *cls,
+                 const struct TALER_TESTING_Command *cmd,
+                 struct TALER_TESTING_Interpreter *is)
 {
-  struct ProposalLookupState *pls = cls;
+  struct OrderClaimState *pls = cls;
   const char *order_id;
   const struct TALER_MerchantPublicKeyP *nonce;
   /* Only used if we do NOT use the nonce from traits.  */
   struct TALER_MerchantPublicKeyP dummy_nonce;
-  #define GET_TRAIT_NONCE(cmd,ptr) \
+#define GET_TRAIT_NONCE(cmd,ptr) \
   TALER_TESTING_get_trait_merchant_pub (cmd, 1, ptr)
 
   pls->is = is;
-
   if (NULL != pls->order_id)
   {
     order_id = pls->order_id;
@@ -204,16 +203,16 @@ proposal_lookup_run (void *cls,
   }
   else
   {
-    const struct TALER_TESTING_Command *proposal_cmd;
-
-    proposal_cmd = TALER_TESTING_interpreter_lookup_command
-                     (is, pls->proposal_reference);
+    const struct TALER_TESTING_Command *order_cmd;
 
-    if (NULL == proposal_cmd)
+    order_cmd
+      = TALER_TESTING_interpreter_lookup_command (is,
+                                                  pls->order_reference);
+    if (NULL == order_cmd)
       TALER_TESTING_FAIL (is);
-
-    if (GNUNET_OK != GET_TRAIT_NONCE (proposal_cmd,
-                                      &nonce))
+    if (GNUNET_OK !=
+        GET_TRAIT_NONCE (order_cmd,
+                         &nonce))
     {
       GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
                                   &dummy_nonce,
@@ -221,17 +220,19 @@ proposal_lookup_run (void *cls,
       nonce = &dummy_nonce;
     }
 
-    if (GNUNET_OK != TALER_TESTING_get_trait_order_id
-          (proposal_cmd, 0, &order_id))
+    if (GNUNET_OK !=
+        TALER_TESTING_get_trait_order_id (order_cmd,
+                                          0,
+                                          &order_id))
       TALER_TESTING_FAIL (is);
   }
-  pls->plo = TALER_MERCHANT_proposal_lookup (is->ctx,
-                                             pls->merchant_url,
-                                             order_id,
-                                             &nonce->eddsa_pub,
-                                             &proposal_lookup_cb,
-                                             pls);
-  GNUNET_assert (NULL != pls->plo);
+  pls->och = TALER_MERCHANT_order_claim (is->ctx,
+                                         pls->merchant_url,
+                                         order_id,
+                                         &nonce->eddsa_pub,
+                                         &order_claim_cb,
+                                         pls);
+  GNUNET_assert (NULL != pls->och);
 }
 
 
@@ -245,12 +246,12 @@ proposal_lookup_run (void *cls,
  * @return #GNUNET_OK on success
  */
 static int
-proposal_lookup_traits (void *cls,
-                        const void **ret,
-                        const char *trait,
-                        unsigned int index)
+order_claim_traits (void *cls,
+                    const void **ret,
+                    const char *trait,
+                    unsigned int index)
 {
-  struct ProposalLookupState *pls = cls;
+  struct OrderClaimState *pls = cls;
   struct TALER_TESTING_Trait traits[] = {
     TALER_TESTING_make_trait_contract_terms (0,
                                              pls->contract_terms),
@@ -271,39 +272,38 @@ proposal_lookup_traits (void *cls,
 
 
 /**
- * Make a "proposal lookup" command.
+ * Make a "order claim" command.
  *
  * @param label command label.
  * @param merchant_url base URL of the merchant backend
- *        serving the proposal lookup request.
+ *        serving the order claim request.
  * @param http_status expected HTTP response code.
- * @param proposal_reference reference to a "proposal" CMD.
- * @param order_id order id to lookup, can be NULL.
- *
+ * @param order_reference reference to a POST order CMD, can be NULL if @a 
order_id given
+ * @param order_id order id to lookup, can be NULL (then we use @a 
order_reference)
  * @return the command.
  */
 struct TALER_TESTING_Command
-TALER_TESTING_cmd_merchant_post_orders_lookup
-  (const char *label,
+TALER_TESTING_cmd_merchant_claim_order (
+  const char *label,
   const char *merchant_url,
   unsigned int http_status,
-  const char *proposal_reference,
+  const char *order_reference,
   const char *order_id)
 {
-  struct ProposalLookupState *pls;
+  struct OrderClaimState *pls;
 
-  pls = GNUNET_new (struct ProposalLookupState);
+  pls = GNUNET_new (struct OrderClaimState);
   pls->http_status = http_status;
-  pls->proposal_reference = proposal_reference;
+  pls->order_reference = order_reference;
   pls->merchant_url = merchant_url;
   pls->order_id = order_id;
   {
     struct TALER_TESTING_Command cmd = {
       .cls = pls,
       .label = label,
-      .run = &proposal_lookup_run,
-      .cleanup = &proposal_lookup_cleanup,
-      .traits = &proposal_lookup_traits
+      .run = &order_claim_run,
+      .cleanup = &order_claim_cleanup,
+      .traits = &order_claim_traits
     };
 
     return cmd;
diff --git a/src/testing/testing_api_cmd_post_orders.c 
b/src/testing/testing_api_cmd_post_orders.c
index c7635e3..d8bf23f 100644
--- a/src/testing/testing_api_cmd_post_orders.c
+++ b/src/testing/testing_api_cmd_post_orders.c
@@ -66,12 +66,11 @@ struct OrdersState
   struct TALER_MERCHANT_PostOrdersOperation *po;
 
   /**
-   * The (initial) GET /orders/$ID operation handle.
-   * The logic is such that after a orders creation,
-   * it soon makes a orders lookup in order to check
-   * if the merchant backend is actually aware.
+   * The (initial) POST /orders/$ID/claim operation handle.
+   * The logic is such that after an order creation,
+   * we immediately claim the order.
    */
-  struct TALER_MERCHANT_ProposalLookupOperation *plo;
+  struct TALER_MERCHANT_OrderClaimHandle *och;
 
   /**
    * The nonce.
@@ -139,7 +138,7 @@ orders_traits (void *cls,
 
 /**
  * Used to fill the "orders" CMD state with backend-provided
- * values.  Also double-checks that the orders was correctly
+ * values.  Also double-checks that the order was correctly
  * created.
  *
  * @param cls closure
@@ -148,11 +147,11 @@ orders_traits (void *cls,
  * @param hash hash over the contract
  */
 static void
-orders_lookup_initial_cb (void *cls,
-                          const struct TALER_MERCHANT_HttpResponse *hr,
-                          const json_t *contract_terms,
-                          const struct TALER_MerchantSignatureP *sig,
-                          const struct GNUNET_HashCode *hash)
+orders_claim_cb (void *cls,
+                 const struct TALER_MERCHANT_HttpResponse *hr,
+                 const json_t *contract_terms,
+                 const struct TALER_MerchantSignatureP *sig,
+                 const struct GNUNET_HashCode *hash)
 {
   struct OrdersState *ps = cls;
   struct TALER_MerchantPublicKeyP merchant_pub;
@@ -164,7 +163,7 @@ orders_lookup_initial_cb (void *cls,
     GNUNET_JSON_spec_end ()
   };
 
-  ps->plo = NULL;
+  ps->och = NULL;
   if (ps->http_status != hr->http_status)
     TALER_TESTING_FAIL (ps->is);
 
@@ -254,12 +253,12 @@ order_cb (void *cls,
   }
 
   if (NULL ==
-      (ps->plo = TALER_MERCHANT_proposal_lookup (ps->is->ctx,
-                                                 ps->merchant_url,
-                                                 ps->order_id,
-                                                 &ps->nonce,
-                                                 &orders_lookup_initial_cb,
-                                                 ps)))
+      (ps->och = TALER_MERCHANT_order_claim (ps->is->ctx,
+                                             ps->merchant_url,
+                                             ps->order_id,
+                                             &ps->nonce,
+                                             &orders_claim_cb,
+                                             ps)))
     TALER_TESTING_FAIL (ps->is);
 }
 
@@ -344,14 +343,14 @@ orders_cleanup (void *cls,
     ps->po = NULL;
   }
 
-  if (NULL != ps->plo)
+  if (NULL != ps->och)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                 "Command '%s' did not complete"
                 " (orders lookup)\n",
                 cmd->label);
-    TALER_MERCHANT_proposal_lookup_cancel (ps->plo);
-    ps->plo = NULL;
+    TALER_MERCHANT_order_claim_cancel (ps->och);
+    ps->och = NULL;
   }
 
   json_decref (ps->contract_terms);

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