merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

merchant_api_post_order_pay.c (25010B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014-2023 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify
      6   it under the terms of the GNU Lesser General Public License as
      7   published by the Free Software Foundation; either version 2.1,
      8   or (at your option) any later version.
      9 
     10   TALER is distributed in the hope that it will be useful,
     11   but WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13   GNU Lesser General Public License for more details.
     14 
     15   You should have received a copy of the GNU Lesser General
     16   Public License along with TALER; see the file COPYING.LGPL.
     17   If not, see <http://www.gnu.org/licenses/>
     18 */
     19 /**
     20  * @file merchant_api_post_order_pay.c
     21  * @brief Implementation of the POST /order/$ID/pay request
     22  *        of the merchant's HTTP API
     23  * @author Christian Grothoff
     24  * @author Marcello Stanisci
     25  */
     26 #include "platform.h"
     27 #include <curl/curl.h>
     28 #include <gnunet/gnunet_common.h>
     29 #include <gnunet/gnunet_json_lib.h>
     30 #include <jansson.h>
     31 #include <microhttpd.h> /* just for HTTP status codes */
     32 #include <gnunet/gnunet_util_lib.h>
     33 #include <gnunet/gnunet_curl_lib.h>
     34 #include "taler_merchant_service.h"
     35 #include "merchant_api_common.h"
     36 #include "merchant_api_curl_defaults.h"
     37 #include <stdio.h>
     38 #include <taler/taler_json_lib.h>
     39 #include <taler/taler_signatures.h>
     40 #include <taler/taler_exchange_service.h>
     41 #include <taler/taler_curl_lib.h>
     42 
     43 
     44 /**
     45  * @brief A Pay Handle
     46  */
     47 struct TALER_MERCHANT_OrderPayHandle
     48 {
     49 
     50   /**
     51    * The url for this request.
     52    */
     53   char *url;
     54 
     55   /**
     56    * Handle for the request.
     57    */
     58   struct GNUNET_CURL_Job *job;
     59 
     60   /**
     61    * Function to call with the result in "pay" @e mode.
     62    */
     63   TALER_MERCHANT_OrderPayCallback pay_cb;
     64 
     65   /**
     66    * Closure for @a pay_cb.
     67    */
     68   void *pay_cb_cls;
     69 
     70   /**
     71    * Reference to the execution context.
     72    */
     73   struct GNUNET_CURL_Context *ctx;
     74 
     75   /**
     76    * Minor context that holds body and headers.
     77    */
     78   struct TALER_CURL_PostContext post_ctx;
     79 
     80   /**
     81    * The coins we are paying with.
     82    */
     83   struct TALER_MERCHANT_PaidCoin *coins;
     84 
     85   /**
     86    * Hash of the contract we are paying, set
     87    * if @e am_wallet is true.
     88    */
     89   struct TALER_PrivateContractHashP h_contract_terms;
     90 
     91   /**
     92    * Public key of the merchant (instance) being paid, set
     93    * if @e am_wallet is true.
     94    */
     95   struct TALER_MerchantPublicKeyP merchant_pub;
     96 
     97   /**
     98    * JSON with the full reply, used during async
     99    * processing.
    100    */
    101   json_t *full_reply;
    102 
    103   /**
    104    * Pointer into @e coins array for the coin that
    105    * created a conflict (that we are checking).
    106    */
    107   const struct TALER_MERCHANT_PaidCoin *error_pc;
    108 
    109   /**
    110    * Coin history that proves a conflict.
    111    */
    112   json_t *error_history;
    113 
    114   /**
    115    * Number of @e coins we are paying with.
    116    */
    117   unsigned int num_coins;
    118 
    119   /**
    120    * Set to true if this is the wallet API and we have
    121    * initialized @e h_contract_terms and @e merchant_pub.
    122    */
    123   bool am_wallet;
    124 
    125 };
    126 
    127 
    128 /**
    129  * Parse blindly signed output tokens from response.
    130  *
    131  * @param token_sigs the JSON array with the token signatures. Can be NULL.
    132  * @param tokens where to store the parsed tokens.
    133  * @param num_tokens where to store the length of the @a tokens array.
    134  */
    135 static enum GNUNET_GenericReturnValue
    136 parse_tokens (const json_t *token_sigs,
    137               struct TALER_MERCHANT_OutputToken **tokens,
    138               unsigned int *num_tokens)
    139 {
    140   GNUNET_array_grow (*tokens,
    141                      *num_tokens,
    142                      json_array_size (token_sigs));
    143 
    144   for (unsigned int i = 0; i<(*num_tokens); i++)
    145   {
    146     struct TALER_MERCHANT_OutputToken *token = &(*tokens)[i];
    147     struct GNUNET_JSON_Specification spec[] = {
    148       TALER_JSON_spec_blinded_token_issue_sig ("blind_sig",
    149                                                &token->blinded_sig),
    150       GNUNET_JSON_spec_end ()
    151     };
    152     const json_t *jtoken
    153       = json_array_get (token_sigs,
    154                         i);
    155 
    156     if (NULL == jtoken)
    157     {
    158       GNUNET_break (0);
    159       return GNUNET_SYSERR;
    160     }
    161     if (GNUNET_OK !=
    162         GNUNET_JSON_parse (jtoken,
    163                            spec,
    164                            NULL, NULL))
    165     {
    166       GNUNET_break (0);
    167       return GNUNET_SYSERR;
    168     }
    169   }
    170 
    171   return GNUNET_YES;
    172 }
    173 
    174 
    175 /**
    176  * Function called when we're done processing the
    177  * HTTP /pay request.
    178  *
    179  * @param cls the `struct TALER_MERCHANT_Pay`
    180  * @param response_code HTTP response code, 0 on error
    181  * @param response response body, NULL if not in JSON
    182  */
    183 static void
    184 handle_pay_finished (void *cls,
    185                      long response_code,
    186                      const void *response)
    187 {
    188   struct TALER_MERCHANT_OrderPayHandle *oph = cls;
    189   const json_t *json = response;
    190   struct TALER_MERCHANT_PayResponse pr = {
    191     .hr.http_status = (unsigned int) response_code,
    192     .hr.reply = json
    193   };
    194 
    195   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    196               "Received /pay response with status code %u\n",
    197               (unsigned int) response_code);
    198 
    199   json_dumpf (json,
    200               stderr,
    201               JSON_INDENT (2));
    202 
    203   oph->job = NULL;
    204   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    205               "/pay completed with response code %u\n",
    206               (unsigned int) response_code);
    207   switch (response_code)
    208   {
    209   case 0:
    210     pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    211     break;
    212   case MHD_HTTP_OK:
    213     if (oph->am_wallet)
    214     {
    215       const json_t *token_sigs = NULL;
    216       struct GNUNET_JSON_Specification spec[] = {
    217         GNUNET_JSON_spec_fixed_auto ("sig",
    218                                      &pr.details.ok.merchant_sig),
    219         GNUNET_JSON_spec_mark_optional (
    220           GNUNET_JSON_spec_string ("pos_confirmation",
    221                                    &pr.details.ok.pos_confirmation),
    222           NULL),
    223         GNUNET_JSON_spec_mark_optional (
    224           GNUNET_JSON_spec_array_const ("token_sigs",
    225                                         &token_sigs),
    226           NULL),
    227         GNUNET_JSON_spec_end ()
    228       };
    229 
    230       if (GNUNET_OK !=
    231           GNUNET_JSON_parse (json,
    232                              spec,
    233                              NULL, NULL))
    234       {
    235         GNUNET_break_op (0);
    236         pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    237         pr.hr.http_status = 0;
    238         pr.hr.hint = "sig field missing in response";
    239         break;
    240       }
    241 
    242       if (GNUNET_OK !=
    243           parse_tokens (token_sigs,
    244                         &pr.details.ok.tokens,
    245                         &pr.details.ok.num_tokens))
    246       {
    247         GNUNET_break_op (0);
    248         pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    249         pr.hr.http_status = 0;
    250         pr.hr.hint = "failed to parse token_sigs field in response";
    251         break;
    252       }
    253 
    254       if (GNUNET_OK !=
    255           TALER_merchant_pay_verify (&oph->h_contract_terms,
    256                                      &oph->merchant_pub,
    257                                      &pr.details.ok.merchant_sig))
    258       {
    259         GNUNET_break_op (0);
    260         pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    261         pr.hr.http_status = 0;
    262         pr.hr.hint = "signature invalid";
    263       }
    264     }
    265     break;
    266   /* Tolerating Not Acceptable because sometimes
    267    * - especially in tests - we might want to POST
    268    * coins one at a time.  */
    269   case MHD_HTTP_NOT_ACCEPTABLE:
    270     pr.hr.ec = TALER_JSON_get_error_code (json);
    271     pr.hr.hint = TALER_JSON_get_error_hint (json);
    272     break;
    273   case MHD_HTTP_BAD_REQUEST:
    274     pr.hr.ec = TALER_JSON_get_error_code (json);
    275     pr.hr.hint = TALER_JSON_get_error_hint (json);
    276     /* This should never happen, either us
    277      * or the merchant is buggy (or API version conflict);
    278      * just pass JSON reply to the application */
    279     break;
    280   case MHD_HTTP_PAYMENT_REQUIRED:
    281     /* was originally paid, but then refunded */
    282     pr.hr.ec = TALER_JSON_get_error_code (json);
    283     pr.hr.hint = TALER_JSON_get_error_hint (json);
    284     break;
    285   case MHD_HTTP_FORBIDDEN:
    286     pr.hr.ec = TALER_JSON_get_error_code (json);
    287     pr.hr.hint = TALER_JSON_get_error_hint (json);
    288     break;
    289   case MHD_HTTP_NOT_FOUND:
    290     pr.hr.ec = TALER_JSON_get_error_code (json);
    291     pr.hr.hint = TALER_JSON_get_error_hint (json);
    292     /* Nothing really to verify, this should never
    293        happen, we should pass the JSON reply to the
    294        application */
    295     break;
    296   case MHD_HTTP_REQUEST_TIMEOUT:
    297     pr.hr.ec = TALER_JSON_get_error_code (json);
    298     pr.hr.hint = TALER_JSON_get_error_hint (json);
    299     /* The merchant couldn't generate a timely response, likely because
    300        it itself waited too long on the exchange.
    301        Pass on to application. */
    302     break;
    303   case MHD_HTTP_CONFLICT:
    304     TALER_MERCHANT_parse_error_details_ (json,
    305                                          MHD_HTTP_CONFLICT,
    306                                          &pr.hr);
    307     break;
    308   case MHD_HTTP_GONE:
    309     TALER_MERCHANT_parse_error_details_ (json,
    310                                          response_code,
    311                                          &pr.hr);
    312     /* The merchant says we are too late, the offer has expired or some
    313        denomination key of a coin involved has expired.
    314        Might be a disagreement in timestamps? Still, pass on to application. */
    315     break;
    316   case MHD_HTTP_PRECONDITION_FAILED:
    317     TALER_MERCHANT_parse_error_details_ (json,
    318                                          response_code,
    319                                          &pr.hr);
    320     /* Nothing really to verify, the merchant is blaming us for failing to
    321        satisfy some constraint (likely it does not like our exchange because
    322        of some disagreement on the PKI).  We should pass the JSON reply to the
    323        application */
    324     break;
    325   case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
    326     {
    327       json_t *ebus = json_object_get (json,
    328                                       "exchange_base_urls");
    329       if (NULL == ebus)
    330       {
    331         GNUNET_break_op (0);
    332         pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    333         pr.hr.http_status = 0;
    334         pr.hr.hint = "failed to parse exchange_base_urls field in response";
    335         break;
    336       }
    337       {
    338         size_t alen = json_array_size (ebus);
    339         const char *ebua[GNUNET_NZL (alen)];
    340         size_t idx;
    341         json_t *jebu;
    342         bool ok = true;
    343 
    344         GNUNET_assert (alen <= UINT_MAX);
    345         json_array_foreach (ebus, idx, jebu)
    346         {
    347           ebua[idx] = json_string_value (jebu);
    348           if (NULL == ebua[idx])
    349           {
    350             GNUNET_break_op (0);
    351             pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    352             pr.hr.http_status = 0;
    353             pr.hr.hint = "non-string value in exchange_base_urls in response";
    354             ok = false;
    355             break;
    356           }
    357         }
    358         if (! ok)
    359           break;
    360         pr.details.unavailable_for_legal_reasons.num_exchanges
    361           = (unsigned int) alen;
    362         pr.details.unavailable_for_legal_reasons.exchanges
    363           = ebua;
    364         oph->pay_cb (oph->pay_cb_cls,
    365                      &pr);
    366         TALER_MERCHANT_order_pay_cancel (oph);
    367         return;
    368       }
    369     }
    370     break;
    371   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    372     TALER_MERCHANT_parse_error_details_ (json,
    373                                          response_code,
    374                                          &pr.hr);
    375     /* Server had an internal issue; we should retry,
    376        but this API leaves this to the application */
    377     break;
    378   case MHD_HTTP_BAD_GATEWAY:
    379     /* Nothing really to verify, the merchant is blaming the exchange.
    380        We should pass the JSON reply to the application */
    381     TALER_MERCHANT_parse_error_details_ (json,
    382                                          response_code,
    383                                          &pr.hr);
    384     break;
    385   case MHD_HTTP_SERVICE_UNAVAILABLE:
    386     TALER_MERCHANT_parse_error_details_ (json,
    387                                          response_code,
    388                                          &pr.hr);
    389     /* Exchange couldn't respond properly; the retry is
    390        left to the application */
    391     break;
    392   case MHD_HTTP_GATEWAY_TIMEOUT:
    393     TALER_MERCHANT_parse_error_details_ (json,
    394                                          response_code,
    395                                          &pr.hr);
    396     /* Exchange couldn't respond in a timely fashion;
    397        the retry is left to the application */
    398     break;
    399   default:
    400     TALER_MERCHANT_parse_error_details_ (json,
    401                                          response_code,
    402                                          &pr.hr);
    403     /* unexpected response code */
    404     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    405                 "Unexpected response code %u/%d\n",
    406                 (unsigned int) response_code,
    407                 (int) pr.hr.ec);
    408     GNUNET_break_op (0);
    409     break;
    410   }
    411   oph->pay_cb (oph->pay_cb_cls,
    412                &pr);
    413   TALER_MERCHANT_order_pay_cancel (oph);
    414 }
    415 
    416 
    417 struct TALER_MERCHANT_OrderPayHandle *
    418 TALER_MERCHANT_order_pay_frontend (
    419   struct GNUNET_CURL_Context *ctx,
    420   const char *merchant_url,
    421   const char *order_id,
    422   const char *session_id,
    423   const json_t *wallet_data,
    424   unsigned int num_coins,
    425   const struct TALER_MERCHANT_PaidCoin coins[static num_coins],
    426   unsigned int num_tokens,
    427   const struct TALER_MERCHANT_UsedToken tokens[static num_tokens],
    428   json_t *j_output_tokens, // FIXME: not used, remove?
    429   TALER_MERCHANT_OrderPayCallback pay_cb,
    430   void *pay_cb_cls)
    431 {
    432   struct TALER_MERCHANT_OrderPayHandle *oph;
    433   json_t *pay_obj;
    434   json_t *j_coins;
    435   json_t *j_tokens = NULL;
    436   CURL *eh;
    437   struct TALER_Amount total_fee;
    438   struct TALER_Amount total_amount;
    439 
    440   j_coins = json_array ();
    441   GNUNET_assert (NULL != j_coins);
    442   for (unsigned int i = 0; i<num_coins; i++)
    443   {
    444     json_t *j_coin;
    445     const struct TALER_MERCHANT_PaidCoin *pc = &coins[i];
    446     struct TALER_Amount fee;
    447     struct TALER_DenominationHashP denom_hash;
    448 
    449     if (0 >
    450         TALER_amount_subtract (&fee,
    451                                &pc->amount_with_fee,
    452                                &pc->amount_without_fee))
    453     {
    454       /* Integer underflow, fee larger than total amount?
    455          This should not happen (client violated API!) */
    456       GNUNET_break (0);
    457       json_decref (j_coins);
    458       return NULL;
    459     }
    460     if (0 == i)
    461     {
    462       total_fee = fee;
    463       total_amount = pc->amount_with_fee;
    464     }
    465     else
    466     {
    467       if ( (0 >
    468             TALER_amount_add (&total_fee,
    469                               &total_fee,
    470                               &fee)) ||
    471            (0 >
    472             TALER_amount_add (&total_amount,
    473                               &total_amount,
    474                               &pc->amount_with_fee)) )
    475       {
    476         /* integer overflow */
    477         GNUNET_break (0);
    478         json_decref (j_coins);
    479         return NULL;
    480       }
    481     }
    482 
    483     TALER_denom_pub_hash (&pc->denom_pub,
    484                           &denom_hash);
    485     /* create JSON for this coin */
    486     j_coin = GNUNET_JSON_PACK (
    487       TALER_JSON_pack_amount ("contribution",
    488                               &pc->amount_with_fee),
    489       GNUNET_JSON_pack_data_auto ("coin_pub",
    490                                   &pc->coin_pub),
    491       GNUNET_JSON_pack_string ("exchange_url",
    492                                pc->exchange_url),
    493       GNUNET_JSON_pack_data_auto ("h_denom",
    494                                   &denom_hash),
    495       TALER_JSON_pack_denom_sig ("ub_sig",
    496                                  &pc->denom_sig),
    497       GNUNET_JSON_pack_data_auto ("coin_sig",
    498                                   &pc->coin_sig));
    499     if (0 !=
    500         json_array_append_new (j_coins,
    501                                j_coin))
    502     {
    503       GNUNET_break (0);
    504       json_decref (j_coins);
    505       return NULL;
    506     }
    507   }
    508 
    509   if (0 < num_tokens)
    510   {
    511     j_tokens = json_array ();
    512     GNUNET_assert (NULL != j_tokens);
    513     for (unsigned int i = 0; i<num_tokens; i++)
    514     {
    515       json_t *j_token;
    516       const struct TALER_MERCHANT_UsedToken *ut = &tokens[i];
    517 
    518       j_token = GNUNET_JSON_PACK (
    519         GNUNET_JSON_pack_data_auto ("token_sig",
    520                                     &ut->token_sig),
    521         GNUNET_JSON_pack_data_auto ("token_pub",
    522                                     &ut->token_pub),
    523         GNUNET_JSON_pack_data_auto ("h_issue",
    524                                     &ut->issue_pub.public_key->pub_key_hash),
    525         TALER_JSON_pack_token_issue_sig ("ub_sig",
    526                                          &ut->ub_sig));
    527       if (0 !=
    528           json_array_append_new (j_tokens,
    529                                  j_token))
    530       {
    531         GNUNET_break (0);
    532         json_decref (j_tokens);
    533         return NULL;
    534       }
    535     }
    536   }
    537 
    538   pay_obj = GNUNET_JSON_PACK (
    539     GNUNET_JSON_pack_array_steal ("coins",
    540                                   j_coins),
    541     GNUNET_JSON_pack_allow_null (
    542       GNUNET_JSON_pack_array_steal ("tokens",
    543                                     j_tokens)),
    544     GNUNET_JSON_pack_allow_null (
    545       GNUNET_JSON_pack_object_incref ("wallet_data",
    546                                       (json_t *) wallet_data)),
    547     GNUNET_JSON_pack_allow_null (
    548       GNUNET_JSON_pack_string ("session_id",
    549                                session_id)));
    550 
    551   json_dumpf (pay_obj,
    552               stderr,
    553               JSON_INDENT (2));
    554 
    555   oph = GNUNET_new (struct TALER_MERCHANT_OrderPayHandle);
    556   oph->ctx = ctx;
    557   oph->pay_cb = pay_cb;
    558   oph->pay_cb_cls = pay_cb_cls;
    559   {
    560     char *path;
    561 
    562     GNUNET_asprintf (&path,
    563                      "orders/%s/pay",
    564                      order_id);
    565     oph->url = TALER_url_join (merchant_url,
    566                                path,
    567                                NULL);
    568     GNUNET_free (path);
    569   }
    570   if (NULL == oph->url)
    571   {
    572     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    573                 "Could not construct request URL.\n");
    574     json_decref (pay_obj);
    575     GNUNET_free (oph);
    576     return NULL;
    577   }
    578   oph->num_coins = num_coins;
    579   oph->coins = GNUNET_new_array (num_coins,
    580                                  struct TALER_MERCHANT_PaidCoin);
    581   GNUNET_memcpy (oph->coins,
    582                  coins,
    583                  num_coins * sizeof (struct TALER_MERCHANT_PaidCoin));
    584 
    585   eh = TALER_MERCHANT_curl_easy_get_ (oph->url);
    586   if (GNUNET_OK !=
    587       TALER_curl_easy_post (&oph->post_ctx,
    588                             eh,
    589                             pay_obj))
    590   {
    591     GNUNET_break (0);
    592     curl_easy_cleanup (eh);
    593     json_decref (pay_obj);
    594     GNUNET_free (oph->url);
    595     GNUNET_free (oph);
    596     return NULL;
    597   }
    598   json_decref (pay_obj);
    599   oph->job = GNUNET_CURL_job_add2 (ctx,
    600                                    eh,
    601                                    oph->post_ctx.headers,
    602                                    &handle_pay_finished,
    603                                    oph);
    604   return oph;
    605 }
    606 
    607 
    608 struct TALER_MERCHANT_OrderPayHandle *
    609 TALER_MERCHANT_order_pay (
    610   struct GNUNET_CURL_Context *ctx,
    611   const char *merchant_url,
    612   const char *session_id,
    613   const struct TALER_PrivateContractHashP *h_contract_terms,
    614   int choice_index,
    615   const struct TALER_Amount *amount,
    616   const struct TALER_Amount *max_fee,
    617   const struct TALER_MerchantPublicKeyP *merchant_pub,
    618   const struct TALER_MerchantSignatureP *merchant_sig,
    619   struct GNUNET_TIME_Timestamp timestamp,
    620   struct GNUNET_TIME_Timestamp refund_deadline,
    621   struct GNUNET_TIME_Timestamp pay_deadline,
    622   const struct TALER_MerchantWireHashP *h_wire,
    623   const char *order_id,
    624   unsigned int num_coins,
    625   const struct TALER_MERCHANT_PayCoin coins[static num_coins],
    626   unsigned int num_tokens,
    627   const struct TALER_MERCHANT_UseToken tokens[static num_tokens],
    628   unsigned int num_output_tokens,
    629   const struct TALER_MERCHANT_OutputToken output_tokens[static num_output_tokens
    630   ],
    631   TALER_MERCHANT_OrderPayCallback pay_cb,
    632   void *pay_cb_cls)
    633 {
    634   json_t *j_output_tokens = NULL;
    635   const json_t *wallet_data = NULL;
    636   struct GNUNET_HashCode wallet_data_hash;
    637 
    638   if (GNUNET_YES !=
    639       TALER_amount_cmp_currency (amount,
    640                                  max_fee))
    641   {
    642     GNUNET_break (0);
    643     return NULL;
    644   }
    645   if ((0 < num_tokens || 0 < num_output_tokens) && 0 > choice_index)
    646   {
    647     /* Tokens (input or output) require a valid choice_index to be set.
    648        Only contracts with coices can use or issue tokens. */
    649     GNUNET_break (0);
    650     return NULL;
    651   }
    652   if (0 < num_output_tokens)
    653   {
    654     /* Build token envelopes json array. */
    655     j_output_tokens = json_array ();
    656     GNUNET_assert (NULL != j_output_tokens);
    657     for (unsigned int i = 0; i<num_output_tokens; i++)
    658     {
    659       json_t *j_token_ev;
    660       const struct TALER_MERCHANT_OutputToken *ev = &output_tokens[i];
    661 
    662       j_token_ev = GNUNET_JSON_PACK (
    663         TALER_JSON_pack_token_envelope (NULL,
    664                                         &ev->envelope));
    665 
    666       if (0 !=
    667           json_array_append_new (j_output_tokens,
    668                                  j_token_ev))
    669       {
    670         GNUNET_break (0);
    671         json_decref (j_output_tokens);
    672         return NULL;
    673       }
    674     }
    675   }
    676   if (0 <= choice_index)
    677   {
    678     wallet_data = GNUNET_JSON_PACK (
    679       GNUNET_JSON_pack_int64 ("choice_index",
    680                               choice_index),
    681       GNUNET_JSON_pack_allow_null (
    682         GNUNET_JSON_pack_array_incref ("tokens_evs",
    683                                        j_output_tokens)));
    684     TALER_json_hash (wallet_data,
    685                      &wallet_data_hash);
    686   }
    687   {
    688     struct TALER_MERCHANT_PaidCoin pc[num_coins];
    689     struct TALER_MERCHANT_UsedToken ut[num_tokens];
    690 
    691     for (unsigned int i = 0; i<num_coins; i++)
    692     {
    693       const struct TALER_MERCHANT_PayCoin *coin = &coins[i]; // coin priv.
    694       struct TALER_MERCHANT_PaidCoin *p = &pc[i]; // coin pub.
    695       struct TALER_Amount fee;
    696       struct TALER_DenominationHashP h_denom_pub;
    697 
    698       if (0 >
    699           TALER_amount_subtract (&fee,
    700                                  &coin->amount_with_fee,
    701                                  &coin->amount_without_fee))
    702       {
    703         /* Integer underflow, fee larger than total amount?
    704            This should not happen (client violated API!) */
    705         GNUNET_break (0);
    706         return NULL;
    707       }
    708       TALER_denom_pub_hash (&coin->denom_pub,
    709                             &h_denom_pub);
    710       TALER_wallet_deposit_sign (&coin->amount_with_fee,
    711                                  &fee,
    712                                  h_wire,
    713                                  h_contract_terms,
    714                                  (NULL != wallet_data)
    715                                  ? &wallet_data_hash
    716                                  : NULL,
    717                                  coin->h_age_commitment,
    718                                  NULL /* h_extensions! */,
    719                                  &h_denom_pub,
    720                                  timestamp,
    721                                  merchant_pub,
    722                                  refund_deadline,
    723                                  &coin->coin_priv,
    724                                  &p->coin_sig);
    725       p->denom_pub = coin->denom_pub;
    726       p->denom_sig = coin->denom_sig;
    727       p->denom_value = coin->denom_value;
    728       GNUNET_CRYPTO_eddsa_key_get_public (&coin->coin_priv.eddsa_priv,
    729                                           &p->coin_pub.eddsa_pub);
    730       p->amount_with_fee = coin->amount_with_fee;
    731       p->amount_without_fee = coin->amount_without_fee;
    732       p->exchange_url = coin->exchange_url;
    733     }
    734     for (unsigned int i = 0; i<num_tokens; i++)
    735     {
    736       const struct TALER_MERCHANT_UseToken *token = &tokens[i];
    737       struct TALER_MERCHANT_UsedToken *t = &ut[i];
    738 
    739       TALER_wallet_token_use_sign (h_contract_terms,
    740                                    &wallet_data_hash, // checked for != NULL above
    741                                    &token->token_priv,
    742                                    &t->token_sig);
    743       t->ub_sig = token->ub_sig;
    744       t->issue_pub = token->issue_pub;
    745       GNUNET_CRYPTO_eddsa_key_get_public (&token->token_priv.private_key,
    746                                           &t->token_pub.public_key);
    747     }
    748     {
    749       struct TALER_MERCHANT_OrderPayHandle *oph;
    750 
    751       oph = TALER_MERCHANT_order_pay_frontend (ctx,
    752                                                merchant_url,
    753                                                order_id,
    754                                                session_id,
    755                                                wallet_data,
    756                                                num_coins,
    757                                                pc,
    758                                                num_tokens,
    759                                                ut,
    760                                                j_output_tokens,
    761                                                pay_cb,
    762                                                pay_cb_cls);
    763       if (NULL == oph)
    764         return NULL;
    765       oph->h_contract_terms = *h_contract_terms;
    766       oph->merchant_pub = *merchant_pub;
    767       oph->am_wallet = true;
    768       return oph;
    769     }
    770   }
    771 }
    772 
    773 
    774 void
    775 TALER_MERCHANT_order_pay_cancel (struct TALER_MERCHANT_OrderPayHandle *oph)
    776 {
    777   if (NULL != oph->job)
    778   {
    779     GNUNET_CURL_job_cancel (oph->job);
    780     oph->job = NULL;
    781   }
    782   TALER_curl_easy_post_finished (&oph->post_ctx);
    783   json_decref (oph->error_history);
    784   json_decref (oph->full_reply);
    785   GNUNET_free (oph->coins);
    786   GNUNET_free (oph->url);
    787   GNUNET_free (oph);
    788 }
    789 
    790 
    791 /* end of merchant_api_post_order_pay.c */