gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant] branch master updated: -fix tests: add receiver-name to


From: gnunet
Subject: [taler-merchant] branch master updated: -fix tests: add receiver-name to payto
Date: Mon, 06 Jun 2022 11:26:14 +0200

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

grothoff pushed a commit to branch master
in repository merchant.

The following commit(s) were added to refs/heads/master by this push:
     new 04868472 -fix tests: add receiver-name to payto
04868472 is described below

commit 048684728159fba1c7417fd9ee881de97dc6949d
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Mon Jun 6 11:26:01 2022 +0200

    -fix tests: add receiver-name to payto
---
 src/lib/merchant_api_post_order_pay.c  | 220 +++++++++++++++++++++++++--------
 src/testing/test_kyc_api.c             |  28 ++---
 src/testing/test_kyc_api.conf          |   2 +-
 src/testing/test_merchant_api-cs.conf  |   2 +-
 src/testing/test_merchant_api-rsa.conf |   2 +-
 src/testing/test_merchant_api.c        |  24 ++--
 src/testing/test_template.conf         |   4 +-
 7 files changed, 203 insertions(+), 79 deletions(-)

diff --git a/src/lib/merchant_api_post_order_pay.c 
b/src/lib/merchant_api_post_order_pay.c
index bd6fca6f..4310838f 100644
--- a/src/lib/merchant_api_post_order_pay.c
+++ b/src/lib/merchant_api_post_order_pay.c
@@ -90,6 +90,29 @@ struct TALER_MERCHANT_OrderPayHandle
    */
   struct TALER_MerchantPublicKeyP merchant_pub;
 
+  /**
+   * JSON with the full reply, used during async
+   * processing.
+   */
+  json_t *full_reply;
+
+  /**
+   * Pointer into @e coins array for the coin that
+   * created a conflict (that we are checking).
+   */
+  const struct TALER_MERCHANT_PaidCoin *error_pc;
+
+  /**
+   * Coin history that proves a conflict.
+   */
+  json_t *error_history;
+
+  /**
+   * Handle to the exchange that issued a problematic
+   * coin (if any).
+   */
+  struct TALER_EXCHANGE_Handle *exchange;
+
   /**
    * Number of @e coins we are paying with.
    */
@@ -109,38 +132,28 @@ struct TALER_MERCHANT_OrderPayHandle
  * Now we need to check the provided cryptographic proof that the
  * coin was actually already spent!
  *
- * @param pc handle of the original coin we paid with
- * @param json cryptographic proof of coin's transaction
- *        history as was returned by the exchange/merchant
- * @return #GNUNET_OK if proof checks out
+ * @param oph operation handle
+ * @param keys key data from the exchange
+ * @return #GNUNET_OK if conflict is valid
  */
 static enum GNUNET_GenericReturnValue
-check_coin_history (const struct TALER_MERCHANT_PaidCoin *pc,
-                    json_t *json)
+check_conflict (struct TALER_MERCHANT_OrderPayHandle *oph,
+                const struct TALER_EXCHANGE_Keys *keys)
 {
-#if FIXME
   struct TALER_Amount spent;
   struct TALER_Amount spent_plus_contrib;
   struct TALER_DenominationHashP h_denom_pub_pc;
   const struct TALER_EXCHANGE_DenomPublicKey *dpk;
-  const struct TALER_EXCHANGE_Keys *keys;
-  struct TALER_EXCHANGE_Handle *exchange;
 
-  exchange = TALER_EXCHANGE_connect (ctx,
-                                     pc->exchange_url,
-                                     &cert_cb,
-                                     ctx,
-                                     TALER_EXCHANGE_OPTION_END);
-  keys = TALER_EXCHANGE_get_keys (exchange);
-  TALER_denom_pub_hash (&pc->denom_pub,
+  TALER_denom_pub_hash (&oph->error_pc->denom_pub,
                         &h_denom_pub_pc);
   dpk = TALER_EXCHANGE_get_denomination_key_by_hash (
     keys,
     &h_denom_pub_pc);
   if (GNUNET_OK !=
       TALER_EXCHANGE_verify_coin_history (dpk,
-                                          &pc->coin_pub,
-                                          json,
+                                          &oph->error_pc->coin_pub,
+                                          oph->error_history,
                                           &spent))
   {
     /* Exchange's history fails to verify */
@@ -150,13 +163,13 @@ check_coin_history (const struct TALER_MERCHANT_PaidCoin 
*pc,
   if (0 >
       TALER_amount_add (&spent_plus_contrib,
                         &spent,
-                        &pc->amount_with_fee))
+                        &oph->error_pc->amount_with_fee))
   {
     /* We got an integer overflow? Bad application! */
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
-  if (-1 != TALER_amount_cmp (&pc->denom_value,
+  if (-1 != TALER_amount_cmp (&oph->error_pc->denom_value,
                               &spent_plus_contrib))
   {
     /* according to our calculations, the transaction should
@@ -165,13 +178,97 @@ check_coin_history (const struct TALER_MERCHANT_PaidCoin 
*pc,
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
   }
-#endif
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Accepting proof of double-spending (or coin public key 
re-use)\n");
   return GNUNET_OK;
 }
 
 
+/**
+ * We got the fee structure from the exchange. Now
+ * validate the conflict error.
+ *
+ * @param cls a `struct TALER_MERCHANT_OrderPayHandle`
+ * @param ehr reply from the exchange
+ * @param keys the key structure
+ * @param compat protocol compatibility indication
+ */
+static void
+cert_cb (void *cls,
+         const struct TALER_EXCHANGE_HttpResponse *ehr,
+         const struct TALER_EXCHANGE_Keys *keys,
+         enum TALER_EXCHANGE_VersionCompatibility compat)
+{
+  struct TALER_MERCHANT_OrderPayHandle *oph = cls;
+
+  if (TALER_EXCHANGE_VC_INCOMPATIBLE & compat)
+  {
+    struct TALER_MERCHANT_HttpResponse hr = {
+      .http_status = MHD_HTTP_CONFLICT,
+      .exchange_http_status = 0,
+      .ec = TALER_EC_WALLET_EXCHANGE_PROTOCOL_VERSION_INCOMPATIBLE,
+      .reply = oph->full_reply,
+      .exchange_reply = ehr->reply,
+      .hint = "could not check error: incompatible exchange version"
+    };
+
+    oph->pay_cb (oph->pay_cb_cls,
+                 &hr,
+                 NULL);
+    TALER_MERCHANT_order_pay_cancel (oph);
+    return;
+  }
+  if ( (MHD_HTTP_OK != ehr->http_status) ||
+       (NULL == keys) )
+  {
+    struct TALER_MERCHANT_HttpResponse hr = {
+      .http_status = MHD_HTTP_CONFLICT,
+      .exchange_http_status = ehr->http_status,
+      .ec = TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
+      .reply = oph->full_reply,
+      .exchange_reply = ehr->reply,
+      .hint = "failed to download /keys from the exchange"
+    };
+
+    oph->pay_cb (oph->pay_cb_cls,
+                 &hr,
+                 NULL);
+    TALER_MERCHANT_order_pay_cancel (oph);
+    return;
+  }
+
+  if (GNUNET_OK !=
+      check_conflict (oph,
+                      keys))
+  {
+    struct TALER_MERCHANT_HttpResponse hr = {
+      .http_status = 0,
+      .ec = TALER_EC_GENERIC_INVALID_RESPONSE,
+      .reply = oph->full_reply
+    };
+
+    oph->pay_cb (oph->pay_cb_cls,
+                 &hr,
+                 NULL);
+    TALER_MERCHANT_order_pay_cancel (oph);
+    return;
+  }
+
+  {
+    struct TALER_MERCHANT_HttpResponse hr = {
+      .http_status = MHD_HTTP_CONFLICT,
+      .ec = TALER_JSON_get_error_code (oph->full_reply),
+      .reply = oph->full_reply
+    };
+
+    oph->pay_cb (oph->pay_cb_cls,
+                 &hr,
+                 NULL);
+    TALER_MERCHANT_order_pay_cancel (oph);
+  }
+}
+
+
 /**
  * We got a 409 response back from the exchange (or the merchant).
  * Now we need to check the provided cryptograophic proof that the
@@ -180,22 +277,26 @@ check_coin_history (const struct TALER_MERCHANT_PaidCoin 
*pc,
  * @param oph handle of the original pay operation
  * @param json cryptograophic proof returned by the
  *        exchange/merchant
- * @return #GNUNET_OK if proof checks out
+ * @return #GNUNET_OK if proof checks out,
+ *         #GNUNET_SYSERR if it is wrong,
+ *         #GNUNET_NO if checking continues asynchronously
  */
 static enum GNUNET_GenericReturnValue
-check_conflict (struct TALER_MERCHANT_OrderPayHandle *oph,
+parse_conflict (struct TALER_MERCHANT_OrderPayHandle *oph,
                 const json_t *json)
 {
-  json_t *history;
   json_t *ereply;
   struct TALER_CoinSpendPublicKeyP coin_pub;
   struct GNUNET_JSON_Specification spec[] = {
-    GNUNET_JSON_spec_json ("exchange_reply", &ereply),
-    GNUNET_JSON_spec_fixed_auto ("coin_pub", &coin_pub),
+    GNUNET_JSON_spec_json ("exchange_reply",
+                           &ereply),
+    GNUNET_JSON_spec_fixed_auto ("coin_pub",
+                                 &coin_pub),
     GNUNET_JSON_spec_end ()
   };
   struct GNUNET_JSON_Specification hspec[] = {
-    GNUNET_JSON_spec_json ("history", &history),
+    GNUNET_JSON_spec_json ("history",
+                           &oph->error_history),
     GNUNET_JSON_spec_end ()
   };
 
@@ -224,12 +325,14 @@ check_conflict (struct TALER_MERCHANT_OrderPayHandle *oph,
         GNUNET_memcmp (&oph->coins[i].coin_pub,
                        &coin_pub))
     {
-      enum GNUNET_GenericReturnValue ret;
-
-      ret = check_coin_history (&oph->coins[i],
-                                history);
-      GNUNET_JSON_parse_free (hspec);
-      return ret;
+      oph->error_pc = &oph->coins[i];
+      oph->full_reply = json_incref ((json_t *) json);
+      oph->exchange = TALER_EXCHANGE_connect (oph->ctx,
+                                              oph->error_pc->exchange_url,
+                                              &cert_cb,
+                                              oph,
+                                              TALER_EXCHANGE_OPTION_END);
+      return GNUNET_NO;
     }
   }
   GNUNET_break_op (0); /* complaint is not about any of the coins
@@ -338,15 +441,6 @@ handle_pay_finished (void *cls,
        happen, we should pass the JSON reply to the
        application */
     break;
-  case MHD_HTTP_PRECONDITION_FAILED:
-    TALER_MERCHANT_parse_error_details_ (json,
-                                         response_code,
-                                         &hr);
-    /* Nothing really to verify, the merchant is blaming us for failing to
-       satisfy some constraint (likely it does not like our exchange because
-       of some disagreement on the PKI).  We should pass the JSON reply to the
-       application */
-    break;
   case MHD_HTTP_REQUEST_TIMEOUT:
     hr.ec = TALER_JSON_get_error_code (json);
     hr.hint = TALER_JSON_get_error_hint (json);
@@ -355,15 +449,27 @@ handle_pay_finished (void *cls,
        Pass on to application. */
     break;
   case MHD_HTTP_CONFLICT:
-    hr.ec = TALER_JSON_get_error_code (json);
-    hr.hint = TALER_JSON_get_error_hint (json);
-    if (GNUNET_OK != check_conflict (oph,
-                                     json))
     {
-      GNUNET_break_op (0);
-      response_code = 0;
+      enum GNUNET_GenericReturnValue ret;
+
+      hr.ec = TALER_JSON_get_error_code (json);
+      hr.hint = TALER_JSON_get_error_hint (json);
+      ret = parse_conflict (oph,
+                            json);
+      switch (ret)
+      {
+      case GNUNET_OK:
+        break;
+      case GNUNET_NO:
+        /* handled asynchronously! */
+        return; /* ! */
+      case GNUNET_SYSERR:
+        GNUNET_break_op (0);
+        response_code = 0;
+        break;
+      }
+      break;
     }
-    break;
   case MHD_HTTP_GONE:
     hr.ec = TALER_JSON_get_error_code (json);
     hr.hint = TALER_JSON_get_error_hint (json);
@@ -371,6 +477,15 @@ handle_pay_finished (void *cls,
        denomination key of a coin involved has expired.
        Might be a disagreement in timestamps? Still, pass on to application. */
     break;
+  case MHD_HTTP_PRECONDITION_FAILED:
+    TALER_MERCHANT_parse_error_details_ (json,
+                                         response_code,
+                                         &hr);
+    /* Nothing really to verify, the merchant is blaming us for failing to
+       satisfy some constraint (likely it does not like our exchange because
+       of some disagreement on the PKI).  We should pass the JSON reply to the
+       application */
+    break;
   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     hr.ec = TALER_JSON_get_error_code (json);
     hr.hint = TALER_JSON_get_error_hint (json);
@@ -670,7 +785,14 @@ TALER_MERCHANT_order_pay_cancel (struct 
TALER_MERCHANT_OrderPayHandle *oph)
     GNUNET_CURL_job_cancel (oph->job);
     oph->job = NULL;
   }
+  if (NULL != oph->exchange)
+  {
+    TALER_EXCHANGE_disconnect (oph->exchange);
+    oph->exchange = NULL;
+  }
   TALER_curl_easy_post_finished (&oph->post_ctx);
+  json_decref (oph->error_history);
+  json_decref (oph->full_reply);
   GNUNET_free (oph->coins);
   GNUNET_free (oph->url);
   GNUNET_free (oph);
diff --git a/src/testing/test_kyc_api.c b/src/testing/test_kyc_api.c
index c1bc0d56..490aa6e4 100644
--- a/src/testing/test_kyc_api.c
+++ b/src/testing/test_kyc_api.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014-2021 Taler Systems SA
+  Copyright (C) 2014-2022 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as
@@ -17,7 +17,7 @@
   <http://www.gnu.org/licenses/>
 */
 /**
- * @file test_merchant_api.c
+ * @file test_kyc_api.c
  * @brief testcase to test exchange's HTTP API interface
  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
  * @author Christian Grothoff
@@ -43,7 +43,7 @@
  */
 #define CONFIG_FILE "test_kyc_api.conf"
 
-#define PAYTO_I1 "payto://x-taler-bank/localhost/3"
+#define PAYTO_I1 "payto://x-taler-bank/localhost/3?receiver-name=3"
 
 /**
  * Exchange base URL.  Could also be taken from config.
@@ -272,7 +272,7 @@ run (void *cls,
                                    MHD_HTTP_NO_CONTENT,
                                    false),
     TALER_TESTING_cmd_wire_add ("add-wire-account",
-                                "payto://x-taler-bank/localhost/2",
+                                
"payto://x-taler-bank/localhost/2?receiver-name=2",
                                 MHD_HTTP_NO_CONTENT,
                                 false),
     TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys",
@@ -305,7 +305,7 @@ int
 main (int argc,
       char *const *argv)
 {
-  unsigned int ret;
+  enum GNUNET_GenericReturnValue ret;
 
   /* These environment variables get in the way... */
   unsetenv ("XDG_DATA_HOME");
@@ -319,14 +319,19 @@ main (int argc,
                                       &bc))
     return 77;
 
-  payer_payto = ("payto://x-taler-bank/localhost/" USER_ACCOUNT_NAME);
-  exchange_payto = ("payto://x-taler-bank/localhost/" EXCHANGE_ACCOUNT_NAME);
-  merchant_payto = ("payto://x-taler-bank/localhost/" MERCHANT_ACCOUNT_NAME);
+  payer_payto =
+    ("payto://x-taler-bank/localhost/" USER_ACCOUNT_NAME "?receiver-name="
+     USER_ACCOUNT_NAME);
+  exchange_payto =
+    ("payto://x-taler-bank/localhost/" EXCHANGE_ACCOUNT_NAME "?receiver-name="
+     EXCHANGE_ACCOUNT_NAME);
+  merchant_payto =
+    ("payto://x-taler-bank/localhost/" MERCHANT_ACCOUNT_NAME "?receiver-name="
+     MERCHANT_ACCOUNT_NAME);
 
   if (NULL ==
       (merchant_url = TALER_TESTING_prepare_merchant (CONFIG_FILE)))
     return 77;
-
   GNUNET_asprintf (&merchant_url_i1a,
                    "%sinstances/i1a/",
                    merchant_url);
@@ -341,23 +346,18 @@ main (int argc,
     return 1;
   case GNUNET_NO:
     return 77;
-
   case GNUNET_OK:
-
     if (NULL == (merchantd =
                    TALER_TESTING_run_merchant (CONFIG_FILE,
                                                merchant_url)))
       return 1;
-
     ret = TALER_TESTING_setup_with_exchange (&run,
                                              NULL,
                                              CONFIG_FILE);
-
     GNUNET_OS_process_kill (merchantd, SIGTERM);
     GNUNET_OS_process_wait (merchantd);
     GNUNET_OS_process_destroy (merchantd);
     GNUNET_free (merchant_url);
-
     if (GNUNET_OK != ret)
       return 1;
     break;
diff --git a/src/testing/test_kyc_api.conf b/src/testing/test_kyc_api.conf
index eea5538c..e28cd641 100644
--- a/src/testing/test_kyc_api.conf
+++ b/src/testing/test_kyc_api.conf
@@ -132,7 +132,7 @@ CONFIG = postgres:///talercheck
 # Account of the EXCHANGE
 [exchange-account-exchange]
 # What is the exchange's bank account (with the "Taler Bank" demo system)?
-PAYTO_URI = "payto://x-taler-bank/localhost/2"
+PAYTO_URI = "payto://x-taler-bank/localhost/2?receiver-name=2"
 ENABLE_DEBIT = YES
 ENABLE_CREDIT = YES
 
diff --git a/src/testing/test_merchant_api-cs.conf 
b/src/testing/test_merchant_api-cs.conf
index 006fb644..502d807a 100644
--- a/src/testing/test_merchant_api-cs.conf
+++ b/src/testing/test_merchant_api-cs.conf
@@ -114,7 +114,7 @@ CONFIG = postgres:///talercheck
 # Account of the EXCHANGE
 [exchange-account-exchange]
 # What is the exchange's bank account (with the "Taler Bank" demo system)?
-PAYTO_URI = "payto://x-taler-bank/localhost/2"
+PAYTO_URI = "payto://x-taler-bank/localhost/2?receiver-name=2"
 ENABLE_DEBIT = YES
 ENABLE_CREDIT = YES
 
diff --git a/src/testing/test_merchant_api-rsa.conf 
b/src/testing/test_merchant_api-rsa.conf
index b0f2b49e..5246fc40 100644
--- a/src/testing/test_merchant_api-rsa.conf
+++ b/src/testing/test_merchant_api-rsa.conf
@@ -114,7 +114,7 @@ CONFIG = postgres:///talercheck
 # Account of the EXCHANGE
 [exchange-account-exchange]
 # What is the exchange's bank account (with the "Taler Bank" demo system)?
-PAYTO_URI = "payto://x-taler-bank/localhost/2"
+PAYTO_URI = "payto://x-taler-bank/localhost/2?receiver-name=2"
 ENABLE_DEBIT = YES
 ENABLE_CREDIT = YES
 
diff --git a/src/testing/test_merchant_api.c b/src/testing/test_merchant_api.c
index 8fc0f4ad..27129066 100644
--- a/src/testing/test_merchant_api.c
+++ b/src/testing/test_merchant_api.c
@@ -59,7 +59,7 @@
  */
 static char *config_file;
 
-#define PAYTO_I1 "payto://x-taler-bank/localhost/3"
+#define PAYTO_I1 "payto://x-taler-bank/localhost/3?receiver-name=3"
 
 /**
  * Exchange base URL.  Could also be taken from config.
@@ -1278,7 +1278,7 @@ run (void *cls,
                                    MHD_HTTP_NO_CONTENT,
                                    false),
     TALER_TESTING_cmd_wire_add ("add-wire-account",
-                                "payto://x-taler-bank/localhost/2",
+                                
"payto://x-taler-bank/localhost/2?receiver-name=2",
                                 MHD_HTTP_NO_CONTENT,
                                 false),
     TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys",
@@ -1458,7 +1458,7 @@ run (void *cls,
     TALER_TESTING_cmd_merchant_post_instances ("instance-create-i2-non-idem",
                                                merchant_url,
                                                "i2",
-                                               "payto://other-method/",
+                                               
"payto://other-method/?receiver-name=X",
                                                "EUR",
                                                MHD_HTTP_CONFLICT),
     TALER_TESTING_cmd_merchant_delete_instance ("instance-delete-i2",
@@ -1640,12 +1640,11 @@ main (int argc,
       char *const *argv)
 {
   char *cipher;
-  unsigned int ret;
+  enum GNUNET_GenericReturnValue ret;
 
   /* These environment variables get in the way... */
   unsetenv ("XDG_DATA_HOME");
   unsetenv ("XDG_CONFIG_HOME");
-
   GNUNET_log_setup (argv[0],
                     "DEBUG",
                     NULL);
@@ -1661,19 +1660,23 @@ main (int argc,
                                       &bc))
     return 77;
 
-  payer_payto = ("payto://x-taler-bank/localhost/" USER_ACCOUNT_NAME);
-  exchange_payto = ("payto://x-taler-bank/localhost/" EXCHANGE_ACCOUNT_NAME);
-  merchant_payto = ("payto://x-taler-bank/localhost/" MERCHANT_ACCOUNT_NAME);
+  payer_payto =
+    ("payto://x-taler-bank/localhost/" USER_ACCOUNT_NAME "?receiver-name="
+     USER_ACCOUNT_NAME);
+  exchange_payto =
+    ("payto://x-taler-bank/localhost/" EXCHANGE_ACCOUNT_NAME "?receiver-name="
+     EXCHANGE_ACCOUNT_NAME);
+  merchant_payto =
+    ("payto://x-taler-bank/localhost/" MERCHANT_ACCOUNT_NAME "?receiver-name="
+     MERCHANT_ACCOUNT_NAME);
 
   if (NULL ==
       (merchant_url = TALER_TESTING_prepare_merchant (config_file)))
     return 77;
-
   GNUNET_asprintf (&merchant_url_i1a,
                    "%sinstances/i1a/",
                    merchant_url);
   TALER_TESTING_cleanup_files (config_file);
-
   switch (TALER_TESTING_prepare_exchange (config_file,
                                           GNUNET_YES,
                                           &ec))
@@ -1697,7 +1700,6 @@ main (int argc,
     GNUNET_OS_process_wait (merchantd);
     GNUNET_OS_process_destroy (merchantd);
     GNUNET_free (merchant_url);
-
     if (GNUNET_OK != ret)
       return 1;
     break;
diff --git a/src/testing/test_template.conf b/src/testing/test_template.conf
index 20fee4b8..e9b94761 100644
--- a/src/testing/test_template.conf
+++ b/src/testing/test_template.conf
@@ -63,7 +63,7 @@ MAX_DEBT = TESTKUDOS:50.0
 MAX_DEBT_BANK = TESTKUDOS:100000.0
 HTTP_PORT = 8082
 SUGGESTED_EXCHANGE = http://localhost:8081/
-SUGGESTED_EXCHANGE_PAYTO = payto://x-taler-bank/localhost/2
+SUGGESTED_EXCHANGE_PAYTO = "payto://x-taler-bank/localhost/2?receiver-name=2"
 ALLOW_REGISTRATIONS = YES
 SERVE = http
 
@@ -72,7 +72,7 @@ IDLE_RESERVE_EXPIRATION_TIME = 4 weeks
 LEGAL_RESERVE_EXPIRATION_TIME = 7 years
 
 [exchange-account-1]
-PAYTO_URI = payto://x-taler-bank/localhost/Exchange
+PAYTO_URI = "payto://x-taler-bank/localhost/Exchange?receiver-name=Exchange"
 enable_debit = yes
 enable_credit = yes
 

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