aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2024-09-01 17:37:00 +0200
committerChristian Grothoff <christian@grothoff.org>2024-09-01 17:37:00 +0200
commit0188860eddca95d80d2253c7e2893daf3b3d6dca (patch)
treeb6cc9c5ab4b9d3aad7fd7fe9bdabadd1d2e87345 /src
parent6996910aeee8fad4f0d249590b46570d514d2eb3 (diff)
introduce zero_limits for #9039/#9040 to signal clients that they must do KYC before even attempting to work with an exchange
Diffstat (limited to 'src')
-rw-r--r--src/exchange/taler-exchange-httpd.c7
-rw-r--r--src/exchange/taler-exchange-httpd.h5
-rw-r--r--src/exchange/taler-exchange-httpd_keys.c3
-rw-r--r--src/include/taler_exchange_service.h29
-rw-r--r--src/include/taler_kyclogic_lib.h13
-rw-r--r--src/kyclogic/kyclogic_api.c33
-rw-r--r--src/lib/exchange_api_handle.c69
7 files changed, 159 insertions, 0 deletions
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
index 52e8ef6af..f45865381 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -176,6 +176,11 @@ float TEH_stefan_lin;
json_t *TEH_hard_limits;
/**
+ * JSON array with zero limits for /keys response.
+ */
+json_t *TEH_zero_limits;
+
+/**
* Where to redirect users from "/"?
*/
static char *toplevel_redirect_url;
@@ -2141,6 +2146,8 @@ exchange_serve_process_config (const char *cfg_fn)
}
TEH_hard_limits
= TALER_KYCLOGIC_get_hard_limits ();
+ TEH_zero_limits
+ = TALER_KYCLOGIC_get_zero_limits ();
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_number (TEH_cfg,
"exchange",
diff --git a/src/exchange/taler-exchange-httpd.h b/src/exchange/taler-exchange-httpd.h
index d6350c897..7f2233eab 100644
--- a/src/exchange/taler-exchange-httpd.h
+++ b/src/exchange/taler-exchange-httpd.h
@@ -103,6 +103,11 @@ extern struct TALER_EXCHANGEDB_Plugin *TEH_plugin;
extern json_t *TEH_hard_limits;
/**
+ * JSON array with zero limits for /keys response.
+ */
+extern json_t *TEH_zero_limits;
+
+/**
* Absolute STEFAN parameter.
*/
extern struct TALER_Amount TEH_stefan_abs;
diff --git a/src/exchange/taler-exchange-httpd_keys.c b/src/exchange/taler-exchange-httpd_keys.c
index e57e7d4f5..9998ccbbb 100644
--- a/src/exchange/taler-exchange-httpd_keys.c
+++ b/src/exchange/taler-exchange-httpd_keys.c
@@ -2416,6 +2416,9 @@ create_krd (struct TEH_KeyStateHandle *ksh,
GNUNET_JSON_pack_array_incref (
"hard_limits",
TEH_hard_limits),
+ GNUNET_JSON_pack_array_incref (
+ "zero_limits",
+ TEH_zero_limits),
TALER_JSON_pack_amount ("stefan_abs",
&TEH_stefan_abs),
TALER_JSON_pack_amount ("stefan_log",
diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h
index 3e6840266..b9b1f8778 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -450,6 +450,22 @@ struct TALER_EXCHANGE_WireAccount
/**
+ * Applicable soft limits of zero for an account (or wallet).
+ * Clients should begin a KYC process before attempting
+ * these operations.
+ */
+struct TALER_EXCHANGE_ZeroLimitedOperation
+{
+
+ /**
+ * Operation type for which the restriction applies.
+ */
+ enum TALER_KYCLOGIC_KycTriggerEvent operation_type;
+
+};
+
+
+/**
* Applicable limits for an account (or wallet). Exceeding these limits may
* trigger additional KYC requirements or be categorically verboten.
*/
@@ -569,6 +585,14 @@ struct TALER_EXCHANGE_Keys
struct TALER_EXCHANGE_AccountLimit *hard_limits;
/**
+ * Array of operations with a default soft limit of zero
+ * that apply at this exchange.
+ * Clients should begin a KYC process before attempting
+ * these operations.
+ */
+ struct TALER_EXCHANGE_ZeroLimitedOperation *zero_limits;
+
+ /**
* Array of wire fees by wire method.
*/
struct TALER_EXCHANGE_WireFeesByMethod *fees;
@@ -638,6 +662,11 @@ struct TALER_EXCHANGE_Keys
unsigned int hard_limits_length;
/**
+ * Length of @e zero_limits array.
+ */
+ unsigned int zero_limits_length;
+
+ /**
* Length of the @e wallet_balance_limit_without_kyc
* array.
*/
diff --git a/src/include/taler_kyclogic_lib.h b/src/include/taler_kyclogic_lib.h
index 17ca2fe04..2387ac074 100644
--- a/src/include/taler_kyclogic_lib.h
+++ b/src/include/taler_kyclogic_lib.h
@@ -370,6 +370,19 @@ TALER_KYCLOGIC_get_hard_limits (void);
/**
+ * Return JSON array of ZeroLimitedOperation objects with
+ * operations for which this exchange has a limit
+ * of zero, that means KYC is always required (or
+ * the operation is categorically forbidden).
+ *
+ * @return the JSON array of ZeroLimitedOperation objects,
+ * empty array if there are no hard limits
+ */
+json_t *
+TALER_KYCLOGIC_get_zero_limits (void);
+
+
+/**
* Get human-readable name of KYC rule.
*
* @param r rule to convert
diff --git a/src/kyclogic/kyclogic_api.c b/src/kyclogic/kyclogic_api.c
index 5f5b45f92..16cd16c72 100644
--- a/src/kyclogic/kyclogic_api.c
+++ b/src/kyclogic/kyclogic_api.c
@@ -3585,4 +3585,37 @@ TALER_KYCLOGIC_get_hard_limits ()
}
+json_t *
+TALER_KYCLOGIC_get_zero_limits ()
+{
+ const struct TALER_KYCLOGIC_KycRule *rules
+ = default_rules.kyc_rules;
+ unsigned int num_rules
+ = default_rules.num_kyc_rules;
+ json_t *zero_limits;
+
+ zero_limits = json_array ();
+ GNUNET_assert (NULL != zero_limits);
+ for (unsigned int i = 0; i<num_rules; i++)
+ {
+ const struct TALER_KYCLOGIC_KycRule *rule = &rules[i];
+ json_t *zero_limit;
+
+ if (! rule->exposed)
+ continue;
+ if (rule->verboten)
+ continue; /* see: hard_limits */
+ if (! TALER_amount_is_zero (&rule->threshold))
+ continue;
+ zero_limit = GNUNET_JSON_PACK (
+ TALER_JSON_pack_kycte ("operation_type",
+ rule->trigger));
+ GNUNET_assert (0 ==
+ json_array_append_new (zero_limits,
+ zero_limit));
+ }
+ return zero_limits;
+}
+
+
/* end of kyclogic_api.c */
diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c
index 329e2c2e6..c39440857 100644
--- a/src/lib/exchange_api_handle.c
+++ b/src/lib/exchange_api_handle.c
@@ -813,6 +813,57 @@ parse_hard_limits (const json_t *hard_limits,
/**
+ * Decode the JSON array in @a zero_limits from the /keys response
+ * and store the data in `zero_limits` array the @a key_data.
+ *
+ * @param[in] zero_limits JSON array to parse
+ * @param[out] key_data where to store the results we decoded
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ * (malformed JSON)
+ */
+static enum GNUNET_GenericReturnValue
+parse_zero_limits (const json_t *zero_limits,
+ struct TALER_EXCHANGE_Keys *key_data)
+{
+ json_t *obj;
+ size_t off;
+
+ key_data->zero_limits_length
+ = (unsigned int) json_array_size (zero_limits);
+ if ( ((size_t) key_data->zero_limits_length)
+ != json_array_size (zero_limits))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ key_data->zero_limits
+ = GNUNET_new_array (key_data->zero_limits_length,
+ struct TALER_EXCHANGE_ZeroLimitedOperation);
+
+ json_array_foreach (zero_limits, off, obj)
+ {
+ struct TALER_EXCHANGE_ZeroLimitedOperation *zol
+ = &key_data->zero_limits[off];
+ struct GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_kycte ("operation_type",
+ &zol->operation_type),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (obj,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ }
+ return GNUNET_OK;
+}
+
+
+/**
* Decode the JSON in @a resp_obj from the /keys response
* and store the data in the @a key_data.
*
@@ -976,6 +1027,7 @@ decode_keys_json (const json_t *resp_obj,
}
{
const json_t *hard_limits = NULL;
+ const json_t *zero_limits = NULL;
struct GNUNET_JSON_Specification sspec[] = {
TALER_JSON_spec_currency_specification (
"currency_specification",
@@ -994,6 +1046,11 @@ decode_keys_json (const json_t *resp_obj,
"hard_limits",
&hard_limits),
NULL),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_array_const (
+ "zero_limits",
+ &zero_limits),
+ NULL),
GNUNET_JSON_spec_double (
"stefan_lin",
&key_data->stefan_lin),
@@ -1021,6 +1078,15 @@ decode_keys_json (const json_t *resp_obj,
"Parsing hard limits of /keys failed\n");
EXITIF (1);
}
+ if ( (NULL != zero_limits) &&
+ (GNUNET_OK !=
+ parse_zero_limits (zero_limits,
+ key_data)) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Parsing hard limits of /keys failed\n");
+ EXITIF (1);
+ }
}
key_data->currency = GNUNET_strdup (currency);
@@ -1964,6 +2030,9 @@ TALER_EXCHANGE_keys_decref (struct TALER_EXCHANGE_Keys *keys)
GNUNET_array_grow (keys->hard_limits,
keys->hard_limits_length,
0);
+ GNUNET_array_grow (keys->zero_limits,
+ keys->zero_limits_length,
+ 0);
json_decref (keys->extensions);
GNUNET_free (keys->cspec.name);
json_decref (keys->cspec.map_alt_unit_names);