begin API change to allow AML officers to trigger KYC process

This commit is contained in:
Christian Grothoff 2023-02-14 14:26:00 +01:00
parent 437e6ec86a
commit afe3f70d33
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
13 changed files with 90 additions and 4 deletions

View File

@ -50,6 +50,7 @@ TEH_handler_post_aml_decision (
uint32_t new_state32; uint32_t new_state32;
enum TALER_AmlDecisionState new_state; enum TALER_AmlDecisionState new_state;
struct TALER_AmlOfficerSignatureP officer_sig; struct TALER_AmlOfficerSignatureP officer_sig;
json_t *kyc_requirements = NULL;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("officer_sig", GNUNET_JSON_spec_fixed_auto ("officer_sig",
&officer_sig), &officer_sig),
@ -64,6 +65,10 @@ TEH_handler_post_aml_decision (
&decision_time), &decision_time),
GNUNET_JSON_spec_uint32 ("new_state", GNUNET_JSON_spec_uint32 ("new_state",
&new_state32), &new_state32),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_json ("kyc_requirements",
&kyc_requirements),
NULL),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
@ -89,6 +94,7 @@ TEH_handler_post_aml_decision (
&new_threshold, &new_threshold,
&h_payto, &h_payto,
new_state, new_state,
kyc_requirements,
officer_pub, officer_pub,
&officer_sig)) &officer_sig))
{ {
@ -99,6 +105,8 @@ TEH_handler_post_aml_decision (
TALER_EC_EXCHANGE_AML_DECISION_ADD_SIGNATURE_INVALID, TALER_EC_EXCHANGE_AML_DECISION_ADD_SIGNATURE_INVALID,
NULL); NULL);
} }
// FIXME: check kyc_requirements is well-formed!
{ {
enum GNUNET_DB_QueryStatus qs; enum GNUNET_DB_QueryStatus qs;
struct GNUNET_TIME_Timestamp last_date; struct GNUNET_TIME_Timestamp last_date;
@ -112,6 +120,7 @@ TEH_handler_post_aml_decision (
new_state, new_state,
decision_time, decision_time,
justification, justification,
kyc_requirements,
officer_pub, officer_pub,
&officer_sig, &officer_sig,
&invalid_officer, &invalid_officer,
@ -127,6 +136,11 @@ TEH_handler_post_aml_decision (
TALER_EC_GENERIC_DB_STORE_FAILED, TALER_EC_GENERIC_DB_STORE_FAILED,
"add aml_decision"); "add aml_decision");
} }
if (NULL != kyc_requirements)
{
// FIXME: act on these!
}
if (invalid_officer) if (invalid_officer)
{ {
GNUNET_break_op (0); GNUNET_break_op (0);

View File

@ -32,6 +32,7 @@ BEGIN
',new_status INT4 NOT NULL DEFAULT(0)' ',new_status INT4 NOT NULL DEFAULT(0)'
',decision_time INT8 NOT NULL DEFAULT(0)' ',decision_time INT8 NOT NULL DEFAULT(0)'
',justification VARCHAR NOT NULL' ',justification VARCHAR NOT NULL'
',kyc_requirements VARCHAR'
',decider_pub BYTEA CHECK (LENGTH(decider_pub)=32)' ',decider_pub BYTEA CHECK (LENGTH(decider_pub)=32)'
',decider_sig BYTEA CHECK (LENGTH(decider_sig)=64)' ',decider_sig BYTEA CHECK (LENGTH(decider_sig)=64)'
') %s ;' ') %s ;'
@ -80,6 +81,12 @@ BEGIN
,table_name ,table_name
,partition_suffix ,partition_suffix
); );
PERFORM comment_partitioned_column(
'Additional KYC requirements imposed by the AML staff member. Serialized JSON array of strings.'
,'kyc_requirements'
,table_name
,partition_suffix
);
PERFORM comment_partitioned_column( PERFORM comment_partitioned_column(
'Signature key of the staff member affirming the AML decision; of type AML_DECISION' 'Signature key of the staff member affirming the AML decision; of type AML_DECISION'
,'decider_sig' ,'decider_sig'
@ -114,7 +121,6 @@ BEGIN
); );
END $$; END $$;
-- FIXME: also have INSERT on AML decisions to update AML status!
INSERT INTO exchange_tables INSERT INTO exchange_tables
(name (name

View File

@ -24,6 +24,7 @@ CREATE OR REPLACE FUNCTION exchange_do_insert_aml_decision(
IN in_decider_pub BYTEA, IN in_decider_pub BYTEA,
IN in_decider_sig BYTEA, IN in_decider_sig BYTEA,
IN in_notify_s VARCHAR, IN in_notify_s VARCHAR,
IN in_kyc_requirements VARCHAR,
OUT out_invalid_officer BOOLEAN, OUT out_invalid_officer BOOLEAN,
OUT out_last_date INT8) OUT out_last_date INT8)
LANGUAGE plpgsql LANGUAGE plpgsql
@ -84,6 +85,7 @@ INSERT INTO exchange.aml_history
,new_status ,new_status
,decision_time ,decision_time
,justification ,justification
,kyc_requirements
,decider_pub ,decider_pub
,decider_sig ,decider_sig
) VALUES ) VALUES
@ -93,6 +95,7 @@ INSERT INTO exchange.aml_history
,in_new_status ,in_new_status
,in_decision_time ,in_decision_time
,in_justification ,in_justification
,in_kyc_requirements
,in_decider_pub ,in_decider_pub
,in_decider_sig); ,in_decider_sig);
@ -116,5 +119,5 @@ END IF;
END $$; END $$;
COMMENT ON FUNCTION exchange_do_insert_aml_decision(BYTEA, INT8, INT4, INT4, INT8, VARCHAR, BYTEA, BYTEA, VARCHAR) COMMENT ON FUNCTION exchange_do_insert_aml_decision(BYTEA, INT8, INT4, INT4, INT8, VARCHAR, BYTEA, BYTEA, VARCHAR, VARCHAR)
IS 'Checks whether the AML officer is eligible to make AML decisions and if so inserts the decision into the table'; IS 'Checks whether the AML officer is eligible to make AML decisions and if so inserts the decision into the table';

View File

@ -35,6 +35,7 @@ TEH_PG_insert_aml_decision (
enum TALER_AmlDecisionState new_status, enum TALER_AmlDecisionState new_status,
struct GNUNET_TIME_Timestamp decision_time, struct GNUNET_TIME_Timestamp decision_time,
const char *justification, const char *justification,
const json_t *kyc_requirements,
const struct TALER_AmlOfficerPublicKeyP *decider_pub, const struct TALER_AmlOfficerPublicKeyP *decider_pub,
const struct TALER_AmlOfficerSignatureP *decider_sig, const struct TALER_AmlOfficerSignatureP *decider_sig,
bool *invalid_officer, bool *invalid_officer,
@ -48,6 +49,9 @@ TEH_PG_insert_aml_decision (
.h_payto = *h_payto .h_payto = *h_payto
}; };
char *notify_s = GNUNET_PG_get_event_notify_channel (&rep.header); char *notify_s = GNUNET_PG_get_event_notify_channel (&rep.header);
char *kyc_s = (NULL != kyc_requirements)
? json_dumps (kyc_requirements, JSON_COMPACT)
: NULL;
struct GNUNET_PQ_QueryParam params[] = { struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (h_payto), GNUNET_PQ_query_param_auto_from_type (h_payto),
TALER_PQ_query_param_amount (new_threshold), TALER_PQ_query_param_amount (new_threshold),
@ -57,6 +61,9 @@ TEH_PG_insert_aml_decision (
GNUNET_PQ_query_param_auto_from_type (decider_pub), GNUNET_PQ_query_param_auto_from_type (decider_pub),
GNUNET_PQ_query_param_auto_from_type (decider_sig), GNUNET_PQ_query_param_auto_from_type (decider_sig),
GNUNET_PQ_query_param_string (notify_s), GNUNET_PQ_query_param_string (notify_s),
NULL != kyc_requirements
? GNUNET_PQ_query_param_string (kyc_s)
: GNUNET_PQ_query_param_null (),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
}; };
struct GNUNET_PQ_ResultSpec rs[] = { struct GNUNET_PQ_ResultSpec rs[] = {
@ -74,11 +81,13 @@ TEH_PG_insert_aml_decision (
" out_invalid_officer" " out_invalid_officer"
",out_last_date" ",out_last_date"
" FROM exchange_do_insert_aml_decision" " FROM exchange_do_insert_aml_decision"
"($1, $2, $3, $4, $5, $6, $7, $8, $9);"); "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);");
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"do_insert_aml_decision", "do_insert_aml_decision",
params, params,
rs); rs);
GNUNET_free (notify_s); GNUNET_free (notify_s);
if (NULL != kyc_s)
free (kyc_s);
return qs; return qs;
} }

View File

@ -36,6 +36,7 @@
* @param new_status AML decision status * @param new_status AML decision status
* @param decision_time when was the decision made * @param decision_time when was the decision made
* @param justification human-readable text justifying the decision * @param justification human-readable text justifying the decision
* @param kyc_requirements JSON array with KYC requirements
* @param decider_pub public key of the staff member * @param decider_pub public key of the staff member
* @param decider_sig signature of the staff member * @param decider_sig signature of the staff member
* @param[out] invalid_officer set to TRUE if @a decider_pub is not allowed to make decisions right now * @param[out] invalid_officer set to TRUE if @a decider_pub is not allowed to make decisions right now
@ -51,6 +52,7 @@ TEH_PG_insert_aml_decision (
enum TALER_AmlDecisionState new_status, enum TALER_AmlDecisionState new_status,
struct GNUNET_TIME_Timestamp decision_time, struct GNUNET_TIME_Timestamp decision_time,
const char *justification, const char *justification,
const json_t *kyc_requirements,
const struct TALER_AmlOfficerPublicKeyP *decider_pub, const struct TALER_AmlOfficerPublicKeyP *decider_pub,
const struct TALER_AmlOfficerSignatureP *decider_sig, const struct TALER_AmlOfficerSignatureP *decider_sig,
bool *invalid_officer, bool *invalid_officer,

View File

@ -2406,6 +2406,8 @@ TALER_officer_aml_query_verify (
* @param h_payto payto URI hash of the account the * @param h_payto payto URI hash of the account the
* decision is about * decision is about
* @param new_state updated AML state * @param new_state updated AML state
* @param kyc_requirements additional KYC requirements to
* impose, can be NULL
* @param officer_priv private key of AML officer * @param officer_priv private key of AML officer
* @param[out] officer_sig where to write the signature * @param[out] officer_sig where to write the signature
*/ */
@ -2416,6 +2418,7 @@ TALER_officer_aml_decision_sign (
const struct TALER_Amount *new_threshold, const struct TALER_Amount *new_threshold,
const struct TALER_PaytoHashP *h_payto, const struct TALER_PaytoHashP *h_payto,
enum TALER_AmlDecisionState new_state, enum TALER_AmlDecisionState new_state,
const json_t *kyc_requirements,
const struct TALER_AmlOfficerPrivateKeyP *officer_priv, const struct TALER_AmlOfficerPrivateKeyP *officer_priv,
struct TALER_AmlOfficerSignatureP *officer_sig); struct TALER_AmlOfficerSignatureP *officer_sig);
@ -2430,6 +2433,8 @@ TALER_officer_aml_decision_sign (
* @param h_payto payto URI hash of the account the * @param h_payto payto URI hash of the account the
* decision is about * decision is about
* @param new_state updated AML state * @param new_state updated AML state
* @param kyc_requirements additional KYC requirements to
* impose, can be NULL
* @param officer_pub public key of AML officer * @param officer_pub public key of AML officer
* @param officer_sig signature to verify * @param officer_sig signature to verify
* @return #GNUNET_OK if the signature is valid * @return #GNUNET_OK if the signature is valid
@ -2441,6 +2446,7 @@ TALER_officer_aml_decision_verify (
const struct TALER_Amount *new_threshold, const struct TALER_Amount *new_threshold,
const struct TALER_PaytoHashP *h_payto, const struct TALER_PaytoHashP *h_payto,
enum TALER_AmlDecisionState new_state, enum TALER_AmlDecisionState new_state,
const json_t *kyc_requirements,
const struct TALER_AmlOfficerPublicKeyP *officer_pub, const struct TALER_AmlOfficerPublicKeyP *officer_pub,
const struct TALER_AmlOfficerSignatureP *officer_sig); const struct TALER_AmlOfficerSignatureP *officer_sig);

View File

@ -4608,6 +4608,7 @@ typedef void
* @param h_payto payto URI hash of the account the * @param h_payto payto URI hash of the account the
* decision is about * decision is about
* @param new_state updated AML state * @param new_state updated AML state
* @param kyc_requirements JSON array of KYC requirements being imposed, NULL for none
* @param officer_priv private key of the deciding AML officer * @param officer_priv private key of the deciding AML officer
* @param cb function to call with the exchange's result * @param cb function to call with the exchange's result
* @param cb_cls closure for @a cb * @param cb_cls closure for @a cb
@ -4622,6 +4623,7 @@ TALER_EXCHANGE_add_aml_decision (
const struct TALER_Amount *new_threshold, const struct TALER_Amount *new_threshold,
const struct TALER_PaytoHashP *h_payto, const struct TALER_PaytoHashP *h_payto,
enum TALER_AmlDecisionState new_state, enum TALER_AmlDecisionState new_state,
const json_t *kyc_requirements,
const struct TALER_AmlOfficerPrivateKeyP *officer_priv, const struct TALER_AmlOfficerPrivateKeyP *officer_priv,
TALER_EXCHANGE_AddAmlDecisionCallback cb, TALER_EXCHANGE_AddAmlDecisionCallback cb,
void *cb_cls); void *cb_cls);

View File

@ -6704,6 +6704,7 @@ struct TALER_EXCHANGEDB_Plugin
enum TALER_AmlDecisionState new_status, enum TALER_AmlDecisionState new_status,
struct GNUNET_TIME_Timestamp decision_time, struct GNUNET_TIME_Timestamp decision_time,
const char *justification, const char *justification,
const json_t *kyc_requirements,
const struct TALER_AmlOfficerPublicKeyP *decider_pub, const struct TALER_AmlOfficerPublicKeyP *decider_pub,
const struct TALER_AmlOfficerSignatureP *decider_sig, const struct TALER_AmlOfficerSignatureP *decider_sig,
bool *invalid_officer, bool *invalid_officer,

View File

@ -2741,6 +2741,7 @@ TALER_TESTING_cmd_set_officer (
* @param new_threshold new threshold to set * @param new_threshold new threshold to set
* @param justification justification given for the decision * @param justification justification given for the decision
* @param new_state new AML state for the account * @param new_state new AML state for the account
* @param kyc_requirement KYC requirement to impose
* @param expected_response expected HTTP return status * @param expected_response expected HTTP return status
* @return the command * @return the command
*/ */
@ -2752,6 +2753,7 @@ TALER_TESTING_cmd_take_aml_decision (
const char *new_threshold, const char *new_threshold,
const char *justification, const char *justification,
enum TALER_AmlDecisionState new_state, enum TALER_AmlDecisionState new_state,
const char *kyc_requirement,
unsigned int expected_response); unsigned int expected_response);

View File

@ -132,6 +132,7 @@ TALER_EXCHANGE_add_aml_decision (
const struct TALER_Amount *new_threshold, const struct TALER_Amount *new_threshold,
const struct TALER_PaytoHashP *h_payto, const struct TALER_PaytoHashP *h_payto,
enum TALER_AmlDecisionState new_state, enum TALER_AmlDecisionState new_state,
const json_t *kyc_requirements,
const struct TALER_AmlOfficerPrivateKeyP *officer_priv, const struct TALER_AmlOfficerPrivateKeyP *officer_priv,
TALER_EXCHANGE_AddAmlDecisionCallback cb, TALER_EXCHANGE_AddAmlDecisionCallback cb,
void *cb_cls) void *cb_cls)
@ -149,6 +150,7 @@ TALER_EXCHANGE_add_aml_decision (
new_threshold, new_threshold,
h_payto, h_payto,
new_state, new_state,
kyc_requirements,
officer_priv, officer_priv,
&officer_sig); &officer_sig);
wh = GNUNET_new (struct TALER_EXCHANGE_AddAmlDecision); wh = GNUNET_new (struct TALER_EXCHANGE_AddAmlDecision);
@ -190,6 +192,9 @@ TALER_EXCHANGE_add_aml_decision (
h_payto), h_payto),
GNUNET_JSON_pack_uint64 ("new_state", GNUNET_JSON_pack_uint64 ("new_state",
(uint32_t) new_state), (uint32_t) new_state),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_array_incref ("kyc_requirements",
(json_t *) kyc_requirements)),
TALER_JSON_pack_amount ("new_threshold", TALER_JSON_pack_amount ("new_threshold",
new_threshold), new_threshold),
GNUNET_JSON_pack_timestamp ("decision_time", GNUNET_JSON_pack_timestamp ("decision_time",

View File

@ -448,6 +448,7 @@ run (void *cls,
"EUR:10000", "EUR:10000",
"party time", "party time",
TALER_AML_NORMAL, TALER_AML_NORMAL,
NULL,
MHD_HTTP_FORBIDDEN), MHD_HTTP_FORBIDDEN),
/* Check that no decision was taken, but that we are allowed /* Check that no decision was taken, but that we are allowed
to read this information */ to read this information */
@ -468,6 +469,7 @@ run (void *cls,
"EUR:10000", "EUR:10000",
"party time", "party time",
TALER_AML_NORMAL, TALER_AML_NORMAL,
NULL,
MHD_HTTP_NO_CONTENT), MHD_HTTP_NO_CONTENT),
TALER_TESTING_cmd_check_aml_decisions ("check-decisions-one-normal", TALER_TESTING_cmd_check_aml_decisions ("check-decisions-one-normal",
"create-aml-officer-1", "create-aml-officer-1",
@ -489,6 +491,7 @@ run (void *cls,
"EUR:1000", "EUR:1000",
"party over", "party over",
TALER_AML_FROZEN, TALER_AML_FROZEN,
NULL,
MHD_HTTP_NO_CONTENT), MHD_HTTP_NO_CONTENT),
TALER_TESTING_cmd_check_aml_decisions ("check-decisions-one-frozen", TALER_TESTING_cmd_check_aml_decisions ("check-decisions-one-frozen",
"create-aml-officer-1", "create-aml-officer-1",

View File

@ -72,6 +72,11 @@ struct AmlDecisionState
*/ */
const char *justification; const char *justification;
/**
* KYC requirement to add.
*/
const char *kyc_requirement;
/** /**
* Threshold transaction amount. * Threshold transaction amount.
*/ */
@ -133,6 +138,7 @@ take_aml_decision_run (void *cls,
const struct TALER_PaytoHashP *h_payto; const struct TALER_PaytoHashP *h_payto;
const struct TALER_AmlOfficerPrivateKeyP *officer_priv; const struct TALER_AmlOfficerPrivateKeyP *officer_priv;
const struct TALER_TESTING_Command *ref; const struct TALER_TESTING_Command *ref;
json_t *kyc_requirements = NULL;
(void) cmd; (void) cmd;
now = GNUNET_TIME_timestamp_get (); now = GNUNET_TIME_timestamp_get ();
@ -160,6 +166,15 @@ take_aml_decision_run (void *cls,
TALER_TESTING_get_trait_officer_priv (ref, TALER_TESTING_get_trait_officer_priv (ref,
&officer_priv)); &officer_priv));
ds->h_payto = *h_payto; ds->h_payto = *h_payto;
if (NULL != ds->kyc_requirement)
{
kyc_requirements = json_array ();
GNUNET_assert (NULL != kyc_requirements);
GNUNET_assert (0 ==
json_array_append (kyc_requirements,
json_string (ds->kyc_requirement)));
}
ds->dh = TALER_EXCHANGE_add_aml_decision ( ds->dh = TALER_EXCHANGE_add_aml_decision (
is->ctx, is->ctx,
is->exchange_url, is->exchange_url,
@ -168,9 +183,11 @@ take_aml_decision_run (void *cls,
&ds->new_threshold, &ds->new_threshold,
h_payto, h_payto,
ds->new_state, ds->new_state,
kyc_requirements,
officer_priv, officer_priv,
&take_aml_decision_cb, &take_aml_decision_cb,
ds); ds);
json_decref (kyc_requirements);
if (NULL == ds->dh) if (NULL == ds->dh)
{ {
GNUNET_break (0); GNUNET_break (0);
@ -246,6 +263,7 @@ TALER_TESTING_cmd_take_aml_decision (
const char *new_threshold, const char *new_threshold,
const char *justification, const char *justification,
enum TALER_AmlDecisionState new_state, enum TALER_AmlDecisionState new_state,
const char *kyc_requirement,
unsigned int expected_response) unsigned int expected_response)
{ {
struct AmlDecisionState *ds; struct AmlDecisionState *ds;
@ -253,6 +271,7 @@ TALER_TESTING_cmd_take_aml_decision (
ds = GNUNET_new (struct AmlDecisionState); ds = GNUNET_new (struct AmlDecisionState);
ds->officer_ref_cmd = ref_officer; ds->officer_ref_cmd = ref_officer;
ds->account_ref_cmd = ref_operation; ds->account_ref_cmd = ref_operation;
ds->kyc_requirement = kyc_requirement;
if (GNUNET_OK != if (GNUNET_OK !=
TALER_string_to_amount (new_threshold, TALER_string_to_amount (new_threshold,
&ds->new_threshold)) &ds->new_threshold))

View File

@ -56,6 +56,12 @@ struct TALER_AmlDecisionPS
*/ */
struct TALER_PaytoHashP h_payto GNUNET_PACKED; struct TALER_PaytoHashP h_payto GNUNET_PACKED;
/**
* Hash over JSON array with KYC requirements that were imposed. All zeros
* for none.
*/
struct GNUNET_HashCode h_kyc_requirements;
/** /**
* What is the new AML status? * What is the new AML status?
*/ */
@ -72,6 +78,7 @@ TALER_officer_aml_decision_sign (
const struct TALER_Amount *new_threshold, const struct TALER_Amount *new_threshold,
const struct TALER_PaytoHashP *h_payto, const struct TALER_PaytoHashP *h_payto,
enum TALER_AmlDecisionState new_state, enum TALER_AmlDecisionState new_state,
const json_t *kyc_requirements,
const struct TALER_AmlOfficerPrivateKeyP *officer_priv, const struct TALER_AmlOfficerPrivateKeyP *officer_priv,
struct TALER_AmlOfficerSignatureP *officer_sig) struct TALER_AmlOfficerSignatureP *officer_sig)
{ {
@ -87,6 +94,9 @@ TALER_officer_aml_decision_sign (
&ad.h_justification); &ad.h_justification);
TALER_amount_hton (&ad.new_threshold, TALER_amount_hton (&ad.new_threshold,
new_threshold); new_threshold);
if (NULL != kyc_requirements)
TALER_json_hash (kyc_requirements,
&ad.h_kyc_requirements);
GNUNET_CRYPTO_eddsa_sign (&officer_priv->eddsa_priv, GNUNET_CRYPTO_eddsa_sign (&officer_priv->eddsa_priv,
&ad, &ad,
&officer_sig->eddsa_signature); &officer_sig->eddsa_signature);
@ -100,6 +110,7 @@ TALER_officer_aml_decision_verify (
const struct TALER_Amount *new_threshold, const struct TALER_Amount *new_threshold,
const struct TALER_PaytoHashP *h_payto, const struct TALER_PaytoHashP *h_payto,
enum TALER_AmlDecisionState new_state, enum TALER_AmlDecisionState new_state,
const json_t *kyc_requirements,
const struct TALER_AmlOfficerPublicKeyP *officer_pub, const struct TALER_AmlOfficerPublicKeyP *officer_pub,
const struct TALER_AmlOfficerSignatureP *officer_sig) const struct TALER_AmlOfficerSignatureP *officer_sig)
{ {
@ -115,6 +126,9 @@ TALER_officer_aml_decision_verify (
&ad.h_justification); &ad.h_justification);
TALER_amount_hton (&ad.new_threshold, TALER_amount_hton (&ad.new_threshold,
new_threshold); new_threshold);
if (NULL != kyc_requirements)
TALER_json_hash (kyc_requirements,
&ad.h_kyc_requirements);
return GNUNET_CRYPTO_eddsa_verify ( return GNUNET_CRYPTO_eddsa_verify (
TALER_SIGNATURE_AML_DECISION, TALER_SIGNATURE_AML_DECISION,
&ad, &ad,