gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [taler-merchant] branch master updated (72900a8 -> 894c5b1)


From: gnunet
Subject: [GNUnet-SVN] [taler-merchant] branch master updated (72900a8 -> 894c5b1)
Date: Thu, 09 Mar 2017 15:45:36 +0100

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

marcello pushed a change to branch master
in repository merchant.

    from 72900a8  Payments generator creates reserves.
     new 3fd4633  Implementing withdraw and proposal submission in the payments 
generator.
     new 894c5b1  Implementing payments in payments generator.

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/samples/generate_payments.c | 685 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 685 insertions(+)

diff --git a/src/samples/generate_payments.c b/src/samples/generate_payments.c
index c225720..004a7b5 100644
--- a/src/samples/generate_payments.c
+++ b/src/samples/generate_payments.c
@@ -32,6 +32,8 @@
 
 #define BANK_URI "http://localhost:8083/";
 
+#define ORDER_MAX_SIZE 1000
+
 /**
  * Task run on timeout.
  */
@@ -165,6 +167,54 @@ struct Command
   {
 
     /**
+     * Information for a #OC_WITHDRAW_SIGN command.
+     */
+    struct
+    {
+
+      /**
+       * Which reserve should we withdraw from?
+       */
+      const char *reserve_reference;
+
+      /**
+       * String describing the denomination value we should withdraw.
+       * A corresponding denomination key must exist in the exchange's
+       * offerings.  Can be NULL if @e pk is set instead.
+       */
+      const char *amount;
+
+      /**
+       * If @e amount is NULL, this specifies the denomination key to
+       * use.  Otherwise, this will be set (by the interpreter) to the
+       * denomination PK matching @e amount.
+       */
+      const struct TALER_EXCHANGE_DenomPublicKey *pk;
+
+      /**
+       * Set (by the interpreter) to the exchange's signature over the
+       * coin's public key.
+       */
+      struct TALER_DenominationSignature sig;
+
+      /**
+       * Set (by the interpreter) to the coin's private key.
+       */
+      struct TALER_CoinSpendPrivateKeyP coin_priv;
+
+      /**
+       * Blinding key used for the operation.
+       */
+      struct TALER_DenominationBlindingKeyP blinding_key;
+
+      /**
+       * Withdraw handle (while operation is running).
+       */
+      struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh;
+
+    } reserve_withdraw;
+
+    /**
      * Information for a #OC_ADMIN_ADD_INCOMING command.
      */
     struct
@@ -205,6 +255,100 @@ struct Command
 
     } admin_add_incoming;
 
+    /**
+     * Information for an #OC_PROPOSAL command.
+     */
+    struct
+    {
+
+      /**
+       * The order.
+       * It's dynamically generated because we need different transaction_id
+       * for different merchant instances.
+       */
+      char order[ORDER_MAX_SIZE];
+
+      /**
+       * Handle to the active PUT /proposal operation, or NULL.
+       */
+      struct TALER_MERCHANT_ProposalOperation *po;
+
+      /**
+       * Full contract in JSON, set by the /contract operation.
+       * FIXME: verify in the code that this bit is actually proposal
+       * data and not the whole proposal.
+       */
+      json_t *proposal_data;
+
+      /**
+       * Proposal's signature.
+       */
+      struct TALER_MerchantSignatureP merchant_sig;
+
+      /**
+       * Proposal data's hashcode.
+       */
+      struct GNUNET_HashCode hash;
+
+    } proposal;
+
+    /**
+     * Information for a #OC_PAY command.
+     * FIXME: support tests where we pay with multiple coins at once.
+     */
+    struct
+    {
+
+      /**
+       * Reference to the contract.
+       */
+      const char *contract_ref;
+
+      /**
+       * Reference to a reserve_withdraw operation for a coin to
+       * be used for the /deposit operation.
+       */
+      const char *coin_ref;
+
+      /**
+       * If this @e coin_ref refers to an operation that generated
+       * an array of coins, this value determines which coin to use.
+       */
+      unsigned int coin_idx;
+
+      /**
+       * Amount to pay (from the coin, including fee).
+       */
+      const char *amount_with_fee;
+
+      /**
+       * Amount to pay (from the coin, excluding fee).  The sum of the
+       * deltas between all @e amount_with_fee and the @e
+       * amount_without_fee must be less than max_fee, and the sum of
+       * the @e amount_with_fee must be larger than the @e
+       * total_amount.
+       */
+      const char *amount_without_fee;
+
+      /**
+       * Deposit handle while operation is running.
+       */
+      struct TALER_MERCHANT_Pay *ph;
+
+      /**
+       * Hashcode of the proposal data associated to this payment.
+       */
+      struct GNUNET_HashCode h_proposal_data;
+
+      /**
+       * Merchant's public key
+       */
+      struct TALER_MerchantPublicKeyP merchant_pub;
+
+    } pay;
+
+
+
   } details;
 
 };
@@ -259,6 +403,133 @@ next_command (struct InterpreterState *is)
 }
 
 /**
+ * Callback that works PUT /proposal's output.
+ *
+ * @param cls closure
+ * @param http_status HTTP response code, 200 indicates success;
+ *                    0 if the backend's reply is bogus (fails to follow the 
protocol)
+ * @param ec taler-specific error code
+ * @param obj the full received JSON reply, or
+ *            error details if the request failed
+ * @param proposal_data the order + additional information provided by the
+ * backend, NULL on error.
+ * @param sig merchant's signature over the contract, NULL on error
+ * @param h_contract hash of the contract, NULL on error
+ */
+static void
+proposal_cb (void *cls,
+             unsigned int http_status,
+            enum TALER_ErrorCode ec,
+             const json_t *obj,
+             const json_t *proposal_data,
+             const struct TALER_MerchantSignatureP *sig,
+             const struct GNUNET_HashCode *hash)
+{
+  struct InterpreterState *is = cls;
+  struct Command *cmd = &is->commands[is->ip];
+
+  cmd->details.proposal.po = NULL;
+  switch (http_status)
+  {
+  case MHD_HTTP_OK:
+    cmd->details.proposal.proposal_data = json_incref ((json_t *) 
proposal_data);
+    cmd->details.proposal.merchant_sig = *sig;
+    cmd->details.proposal.hash = *hash;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Hashed proposal, '%s'\n",
+                GNUNET_h2s (hash));
+    break;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "unexpected status code from /proposal: %u. Step %u\n",
+                http_status,
+                is->ip);
+    json_dumpf (obj, stderr, 0);
+    GNUNET_break (0);
+    fail (is);
+    return;
+  }
+  next_command (is);
+}
+
+/**
+ * Function called with the result of a /pay operation.
+ *
+ * @param cls closure with the interpreter state
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful 
deposit;
+ *                    0 if the exchange's reply is bogus (fails to follow the 
protocol)
+ * @param ec taler-specific error code
+ * @param obj the received JSON reply, should be kept as proof (and, in case 
of errors,
+ *            be forwarded to the customer)
+ */
+static void
+pay_cb (void *cls,
+        unsigned int http_status,
+       enum TALER_ErrorCode ec,
+        const json_t *obj)
+{
+  struct InterpreterState *is = cls;
+  struct Command *cmd = &is->commands[is->ip];
+  struct PaymentResponsePS mr;
+  struct GNUNET_CRYPTO_EddsaSignature sig;
+  struct GNUNET_HashCode h_proposal_data;
+  const char *error_name;
+  unsigned int error_line;
+
+  cmd->details.pay.ph = NULL;
+  if (cmd->expected_response_code != http_status)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Unexpected response code %u to command %s\n",
+                http_status,
+                cmd->label);
+    json_dumpf (obj, stderr, 0);
+    fail (is);
+    return;
+  }
+  if (MHD_HTTP_OK == http_status)
+  {
+    /* Check signature */
+    struct GNUNET_JSON_Specification spec[] = {
+      GNUNET_JSON_spec_fixed_auto ("sig", &sig),
+      GNUNET_JSON_spec_fixed_auto ("h_proposal_data", &h_proposal_data),
+      GNUNET_JSON_spec_end ()
+    };
+    if (GNUNET_OK !=
+        GNUNET_JSON_parse (obj,
+                           spec,
+                           &error_name,
+                           &error_line))
+    {
+      GNUNET_break_op (0);
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Parser failed on %s:%u\n",
+                  error_name,
+                  error_line);
+      fail (is);
+      return;
+    }
+    mr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_PAYMENT_OK);
+    mr.purpose.size = htonl (sizeof (mr));
+    mr.h_proposal_data = h_proposal_data;
+    if (GNUNET_OK !=
+        GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_PAYMENT_OK,
+                                    &mr.purpose,
+                                   &sig,
+                                   &cmd->details.pay.merchant_pub.eddsa_pub))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Merchant signature given in response to /pay invalid\n");
+      fail (is);
+      return;
+    }
+
+  }
+
+  next_command (is);
+}
+
+/**
  * Function called upon completion of our /admin/add/incoming request.
  *
  * @param cls closure with the interpreter state
@@ -318,6 +589,114 @@ find_command (const struct InterpreterState *is,
 }
 
 /**
+ * Function called upon completion of our /reserve/withdraw request.
+ *
+ * @param cls closure with the interpreter state
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful 
status request
+ *                    0 if the exchange's reply is bogus (fails to follow the 
protocol)
+ * @param ec taler-specific error code
+ * @param sig signature over the coin, NULL on error
+ * @param full_response full response from the exchange (for logging, in case 
of errors)
+ */
+static void
+reserve_withdraw_cb (void *cls,
+                     unsigned int http_status,
+                    enum TALER_ErrorCode ec,
+                     const struct TALER_DenominationSignature *sig,
+                     const json_t *full_response)
+{
+  struct InterpreterState *is = cls;
+  struct Command *cmd = &is->commands[is->ip];
+
+  cmd->details.reserve_withdraw.wsh = NULL;
+  if (cmd->expected_response_code != http_status)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Unexpected response code %u to command %s\n",
+                http_status,
+                cmd->label);
+    json_dumpf (full_response, stderr, 0);
+    GNUNET_break (0);
+    fail (is);
+    return;
+  }
+  switch (http_status)
+  {
+  case MHD_HTTP_OK:
+    if (NULL == sig)
+    {
+      GNUNET_break (0);
+      fail (is);
+      return;
+    }
+    cmd->details.reserve_withdraw.sig.rsa_signature
+      = GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature);
+    break;
+  case MHD_HTTP_PAYMENT_REQUIRED:
+    /* nothing to check */
+    break;
+  default:
+    /* Unsupported status code (by test harness) */
+    GNUNET_break (0);
+    break;
+  }
+  next_command (is);
+}
+
+/**
+ * Find denomination key matching the given amount.
+ *
+ * @param keys array of keys to search
+ * @param amount coin value to look for
+ * @return NULL if no matching key was found
+ */
+static const struct TALER_EXCHANGE_DenomPublicKey *
+find_pk (const struct TALER_EXCHANGE_Keys *keys,
+         const struct TALER_Amount *amount)
+{
+  unsigned int i;
+  struct GNUNET_TIME_Absolute now;
+  struct TALER_EXCHANGE_DenomPublicKey *pk;
+  char *str;
+
+  now = GNUNET_TIME_absolute_get ();
+  for (i=0;i<keys->num_denom_keys;i++)
+  {
+    pk = &keys->denom_keys[i];
+    if ( (0 == TALER_amount_cmp (amount,
+                                 &pk->value)) &&
+         (now.abs_value_us >= pk->valid_from.abs_value_us) &&
+         (now.abs_value_us < pk->withdraw_valid_until.abs_value_us) )
+      return pk;
+  }
+  /* do 2nd pass to check if expiration times are to blame for failure */
+  str = TALER_amount_to_string (amount);
+  for (i=0;i<keys->num_denom_keys;i++)
+  {
+    pk = &keys->denom_keys[i];
+    if ( (0 == TALER_amount_cmp (amount,
+                                 &pk->value)) &&
+         ( (now.abs_value_us < pk->valid_from.abs_value_us) ||
+           (now.abs_value_us > pk->withdraw_valid_until.abs_value_us) ) )
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Have denomination key for `%s', but with wrong expiration 
range %llu vs [%llu,%llu)\n",
+                  str,
+                  (unsigned long long) now.abs_value_us,
+                  (unsigned long long) pk->valid_from.abs_value_us,
+                  (unsigned long long) pk->withdraw_valid_until.abs_value_us);
+      GNUNET_free (str);
+      return NULL;
+    }
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+              "No denomination key for amount %s found\n",
+              str);
+  GNUNET_free (str);
+  return NULL;
+}
+
+/**
  * Run the main interpreter loop that performs exchange operations.
  *
  * @param cls contains the `struct InterpreterState`
@@ -358,6 +737,165 @@ interpreter_run (void *cls)
       GNUNET_SCHEDULER_shutdown ();
       return;
 
+  case OC_PAY:
+    {
+      struct TALER_MERCHANT_PayCoin pc;
+      const char *order_id;
+      struct GNUNET_TIME_Absolute refund_deadline;
+      struct GNUNET_TIME_Absolute pay_deadline;
+      struct GNUNET_TIME_Absolute timestamp;
+      struct GNUNET_HashCode h_wire;
+      struct TALER_MerchantPublicKeyP merchant_pub;
+      struct TALER_MerchantSignatureP merchant_sig;
+      struct TALER_Amount total_amount;
+      struct TALER_Amount max_fee;
+      const char *error_name;
+      unsigned int error_line;
+
+      /* get proposal */
+      ref = find_command (is,
+                          cmd->details.pay.contract_ref);
+      GNUNET_assert (NULL != ref);
+      merchant_sig = ref->details.proposal.merchant_sig;
+      GNUNET_assert (NULL != ref->details.proposal.proposal_data);
+      {
+        /* Get information that need to be replied in the deposit permission */
+        struct GNUNET_JSON_Specification spec[] = {
+          GNUNET_JSON_spec_string ("order_id", &order_id),
+          GNUNET_JSON_spec_absolute_time ("refund_deadline", &refund_deadline),
+          GNUNET_JSON_spec_absolute_time ("pay_deadline", &pay_deadline),
+          GNUNET_JSON_spec_absolute_time ("timestamp", &timestamp),
+          GNUNET_JSON_spec_fixed_auto ("merchant_pub", &merchant_pub),
+          GNUNET_JSON_spec_fixed_auto ("H_wire", &h_wire),
+          TALER_JSON_spec_amount ("amount", &total_amount),
+          TALER_JSON_spec_amount ("max_fee", &max_fee),
+          GNUNET_JSON_spec_end()
+        };
+
+        if (GNUNET_OK !=
+            GNUNET_JSON_parse (ref->details.proposal.proposal_data,
+                               spec,
+                               &error_name,
+                               &error_line))
+        {
+          GNUNET_break_op (0);
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                      "Parser failed on %s:%u\n",
+                      error_name,
+                      error_line);
+          fail (is);
+          return;
+        }
+        cmd->details.pay.merchant_pub = merchant_pub;
+      }
+
+      {
+        const struct Command *coin_ref;
+       memset (&pc, 0, sizeof (pc));
+       coin_ref = find_command (is,
+                                cmd->details.pay.coin_ref);
+       GNUNET_assert (NULL != ref);
+       switch (coin_ref->oc)
+       {
+       case OC_WITHDRAW_SIGN:
+         pc.coin_priv = coin_ref->details.reserve_withdraw.coin_priv;
+         pc.denom_pub = coin_ref->details.reserve_withdraw.pk->key;
+         pc.denom_sig = coin_ref->details.reserve_withdraw.sig;
+          pc.denom_value = coin_ref->details.reserve_withdraw.pk->value;
+         break;
+       default:
+         GNUNET_assert (0);
+       }
+
+       if (GNUNET_OK !=
+           TALER_string_to_amount (cmd->details.pay.amount_without_fee,
+                                   &pc.amount_without_fee))
+       {
+         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                     "Failed to parse amount `%s' at %u\n",
+                     cmd->details.pay.amount_without_fee,
+                     is->ip);
+         fail (is);
+         return;
+       }
+
+       if (GNUNET_OK !=
+           TALER_string_to_amount (cmd->details.pay.amount_with_fee,
+                                   &pc.amount_with_fee))
+       {
+         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                     "Failed to parse amount `%s' at %u\n",
+                     cmd->details.pay.amount_with_fee,
+                     is->ip);
+         fail (is);
+         return;
+       }
+      }
+
+      cmd->details.pay.ph
+       = TALER_MERCHANT_pay_wallet (ctx,
+                                    MERCHANT_URI,
+                                     "default",
+                                    &ref->details.proposal.hash,
+                                    &total_amount,
+                                    &max_fee,
+                                    &merchant_pub,
+                                     &merchant_sig,
+                                    timestamp,
+                                    refund_deadline,
+                                    pay_deadline,
+                                    &h_wire,
+                                    EXCHANGE_URI,
+                                     order_id,
+                                    1 /* num_coins */,
+                                    &pc /* coins */,
+                                    &pay_cb,
+                                    is);
+    }
+    if (NULL == cmd->details.pay.ph)
+    {
+      GNUNET_break (0);
+      fail (is);
+      return;
+    }
+    return;
+
+
+    case OC_PROPOSAL:
+      {
+        json_t *order;
+        json_error_t error;
+  
+        order = json_loads (cmd->details.proposal.order,
+                            JSON_REJECT_DUPLICATES,
+                            &error);
+        if (NULL == order)
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                      "Failed to parse the order `%s' at command #%u: %s at 
%u\n",
+                      cmd->details.proposal.order,
+                      is->ip,
+                      error.text,
+                      (unsigned int) error.column);
+          fail (is);
+          return;
+        }
+        cmd->details.proposal.po
+          = TALER_MERCHANT_order_put (ctx,
+                                      MERCHANT_URI,
+                                      order,
+                                      &proposal_cb,
+                                      is);
+        json_decref (order);
+        if (NULL == cmd->details.proposal.po)
+        {
+          GNUNET_break (0);
+          fail (is);
+          return;
+        }
+        return;
+      }
+
     case OC_ADMIN_ADD_INCOMING:
       if (NULL !=
           cmd->details.admin_add_incoming.reserve_reference)
@@ -519,6 +1057,74 @@ interpreter_run (void *cls)
 
       return;
 
+    case OC_WITHDRAW_SIGN:
+      GNUNET_assert (NULL !=
+                     cmd->details.reserve_withdraw.reserve_reference);
+      ref = find_command (is,
+                          cmd->details.reserve_withdraw.reserve_reference);
+      GNUNET_assert (NULL != ref);
+      GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc);
+      if (NULL != cmd->details.reserve_withdraw.amount)
+      {
+        if (GNUNET_OK !=
+            TALER_string_to_amount (cmd->details.reserve_withdraw.amount,
+                                    &amount))
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                      "Failed to parse amount `%s' at %u\n",
+                      cmd->details.reserve_withdraw.amount,
+                      is->ip);
+          fail (is);
+          return;
+        }
+        cmd->details.reserve_withdraw.pk = find_pk (is->keys,
+                                                    &amount);
+      }
+      if (NULL == cmd->details.reserve_withdraw.pk)
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                    "Failed to determine denomination key at %u\n",
+                    is->ip);
+        fail (is);
+        return;
+      }
+  
+      /* create coin's private key */
+      {
+        struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
+  
+        priv = GNUNET_CRYPTO_eddsa_key_create ();
+        cmd->details.reserve_withdraw.coin_priv.eddsa_priv = *priv;
+        GNUNET_free (priv);
+      }
+      GNUNET_CRYPTO_eddsa_key_get_public 
(&cmd->details.reserve_withdraw.coin_priv.eddsa_priv,
+                                          &coin_pub.eddsa_pub);
+      GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
+                                  &cmd->details.reserve_withdraw.blinding_key,
+                                  sizeof 
(cmd->details.reserve_withdraw.blinding_key));
+  
+      cmd->details.reserve_withdraw.wsh
+        = TALER_EXCHANGE_reserve_withdraw (exchange,
+                                           cmd->details.reserve_withdraw.pk,
+                                           
&ref->details.admin_add_incoming.reserve_priv,
+                                           
&cmd->details.reserve_withdraw.coin_priv,
+                                           
&cmd->details.reserve_withdraw.blinding_key,
+                                           &reserve_withdraw_cb,
+                                           is);
+      if (NULL == cmd->details.reserve_withdraw.wsh)
+      {
+        GNUNET_break (0);
+        fail (is);
+        return;
+      }
+      return;
+
+    default:
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Unknown command, OC: %d, label: %s.\n",
+                  cmd->oc,
+                  cmd->label);
+      fail (is);
   }
 }
 
@@ -599,6 +1205,53 @@ do_shutdown (void *cls)
     case OC_END:
       GNUNET_assert (0);
       break;
+
+    case OC_PAY:
+      if (NULL != cmd->details.pay.ph)
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                    "Command %u (%s) did not complete\n",
+                    i,
+                    cmd->label);
+        TALER_MERCHANT_pay_cancel (cmd->details.pay.ph);
+        cmd->details.pay.ph = NULL;
+      }
+      break;
+
+    case OC_PROPOSAL:
+      if (NULL != cmd->details.proposal.po)
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                    "Command %u (%s) did not complete\n",
+                    i,
+                    cmd->label);
+        TALER_MERCHANT_proposal_cancel (cmd->details.proposal.po);
+        cmd->details.proposal.po = NULL;
+      }
+      if (NULL != cmd->details.proposal.proposal_data)
+      {
+        json_decref (cmd->details.proposal.proposal_data);
+        cmd->details.proposal.proposal_data = NULL;
+      }
+      break;
+
+    case OC_WITHDRAW_SIGN:
+      if (NULL != cmd->details.reserve_withdraw.wsh)
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                    "Command %u (%s) did not complete\n",
+                    i,
+                    cmd->label);
+        TALER_EXCHANGE_reserve_withdraw_cancel 
(cmd->details.reserve_withdraw.wsh);
+        cmd->details.reserve_withdraw.wsh = NULL;
+      }
+      if (NULL != cmd->details.reserve_withdraw.sig.rsa_signature)
+      {
+        GNUNET_CRYPTO_rsa_signature_free 
(cmd->details.reserve_withdraw.sig.rsa_signature);
+        cmd->details.reserve_withdraw.sig.rsa_signature = NULL;
+      }
+      break;
+
     case OC_ADMIN_ADD_INCOMING:
       if (NULL != cmd->details.admin_add_incoming.aih)
       {
@@ -663,6 +1316,38 @@ run (void *cls)
       .details.admin_add_incoming.sender_details = "{ \"type\":\"test\", 
\"bank_uri\":\"" BANK_URI "\", \"account_number\":62, \"uuid\":1 }",
       .details.admin_add_incoming.transfer_details = "{ \"uuid\": 1}",
       .details.admin_add_incoming.amount = "EUR:5.01" },
+    /* Withdraw a 5 EUR coin, at fee of 1 ct */
+    { .oc = OC_WITHDRAW_SIGN,
+      .label = "withdraw-coin-1",
+      .expected_response_code = MHD_HTTP_OK,
+      .details.reserve_withdraw.reserve_reference = "create-reserve-1",
+      .details.reserve_withdraw.amount = "EUR:5" },
+
+    /* Create proposal */
+    { .oc = OC_PROPOSAL,
+      .label = "create-proposal-1",
+      .expected_response_code = MHD_HTTP_OK,
+      .details.proposal.order = "{\
+                  \"max_fee\":\
+                     {\"currency\":\"EUR\", \"value\":0, 
\"fraction\":50000000},\
+                  \"order_id\":\"1\",\
+                  \"timestamp\":\"\\/Date(42)\\/\",\
+                  \"refund_deadline\":\"\\/Date(0)\\/\",\
+                  \"pay_deadline\":\"\\/Date(9999999999)\\/\",\
+                  \"amount\":{\"currency\":\"EUR\", \"value\":5, 
\"fraction\":0},\
+                  \"merchant\":{\"instance\":\"default\"},\
+                 \"summary\": \"merchant-lib testcase\",\
+                  \"products\":\
+                     [ {\"description\":\"ice cream\", \"value\":\"{EUR:5}\"} 
] }"},
+
+    { .oc = OC_PAY,
+      .label = "deposit-simple",
+      .expected_response_code = MHD_HTTP_OK,
+      .details.pay.contract_ref = "create-proposal-1",
+      .details.pay.coin_ref = "withdraw-coin-1",
+      .details.pay.amount_with_fee = "EUR:5",
+      .details.pay.amount_without_fee = "EUR:4.99" },
+
     { .oc = OC_END,
       .label = "end-of-commands"}
   };

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



reply via email to

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