implement returning KYC status from GET /deposits/ endpoint

This commit is contained in:
Christian Grothoff 2021-10-17 13:22:15 +02:00
parent 0739405f67
commit 932d2aaf88
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
6 changed files with 150 additions and 178 deletions

View File

@ -136,6 +136,11 @@ struct DepositWtidContext
*/ */
struct TALER_Amount coin_delta; struct TALER_Amount coin_delta;
/**
* KYC status information for the receiving account.
*/
struct TALER_EXCHANGEDB_KycStatus kyc;
/** /**
* Set to #GNUNET_YES by #handle_wtid if the wire transfer is still pending * Set to #GNUNET_YES by #handle_wtid if the wire transfer is still pending
* (and the above were not set). * (and the above were not set).
@ -145,52 +150,6 @@ struct DepositWtidContext
}; };
/**
* Function called with the results of the lookup of the
* wire transfer identifier information.
*
* @param cls our context for transmission, a `struct DepositWtidContext *`
* @param wtid raw wire transfer identifier, NULL
* if the transaction was not yet done
* @param coin_contribution how much did the coin we asked about
* contribute to the total transfer value? (deposit value including fee)
* @param coin_fee how much did the exchange charge for the deposit fee
* @param execution_time when was the transaction done, or
* when we expect it to be done (if @a wtid was NULL);
* #GNUNET_TIME_UNIT_FOREVER_ABS if the /deposit is unknown
* to the exchange
*/
static void
handle_wtid_data (void *cls,
const struct TALER_WireTransferIdentifierRawP *wtid,
const struct TALER_Amount *coin_contribution,
const struct TALER_Amount *coin_fee,
struct GNUNET_TIME_Absolute execution_time)
{
struct DepositWtidContext *ctx = cls;
if (NULL == wtid)
{
ctx->pending = GNUNET_YES;
ctx->execution_time = execution_time;
return;
}
if (0 >
TALER_amount_subtract (&ctx->coin_delta,
coin_contribution,
coin_fee))
{
GNUNET_break (0);
ctx->pending = GNUNET_SYSERR;
return;
}
ctx->wtid = *wtid;
ctx->execution_time = execution_time;
ctx->coin_contribution = *coin_contribution;
ctx->coin_fee = *coin_fee;
}
/** /**
* Execute a "deposits" GET. Returns the transfer information * Execute a "deposits" GET. Returns the transfer information
* associated with the given deposit. * associated with the given deposit.
@ -214,14 +173,21 @@ deposits_get_transaction (void *cls,
{ {
struct DepositWtidContext *ctx = cls; struct DepositWtidContext *ctx = cls;
enum GNUNET_DB_QueryStatus qs; enum GNUNET_DB_QueryStatus qs;
bool pending;
struct TALER_Amount fee;
qs = TEH_plugin->lookup_transfer_by_deposit (TEH_plugin->cls, qs = TEH_plugin->lookup_transfer_by_deposit (TEH_plugin->cls,
&ctx->tps->h_contract_terms, &ctx->tps->h_contract_terms,
&ctx->tps->h_wire, &ctx->tps->h_wire,
&ctx->tps->coin_pub, &ctx->tps->coin_pub,
ctx->merchant_pub, ctx->merchant_pub,
&handle_wtid_data,
ctx); &pending,
&ctx->wtid,
&ctx->execution_time,
&ctx->coin_contribution,
&fee,
&ctx->kyc);
if (0 > qs) if (0 > qs)
{ {
if (GNUNET_DB_STATUS_HARD_ERROR == qs) if (GNUNET_DB_STATUS_HARD_ERROR == qs)
@ -242,6 +208,17 @@ deposits_get_transaction (void *cls,
NULL); NULL);
return GNUNET_DB_STATUS_HARD_ERROR; return GNUNET_DB_STATUS_HARD_ERROR;
} }
if (0 >
TALER_amount_subtract (&ctx->coin_delta,
&ctx->coin_contribution,
&fee))
{
GNUNET_break (0);
ctx->pending = GNUNET_SYSERR;
return qs;
}
ctx->pending = (pending) ? GNUNET_YES : GNUNET_NO;
return qs; return qs;
} }
@ -262,7 +239,6 @@ handle_track_transaction_request (
{ {
MHD_RESULT mhd_ret; MHD_RESULT mhd_ret;
struct DepositWtidContext ctx = { struct DepositWtidContext ctx = {
.pending = GNUNET_NO,
.tps = tps, .tps = tps,
.merchant_pub = merchant_pub .merchant_pub = merchant_pub
}; };
@ -274,17 +250,21 @@ handle_track_transaction_request (
&deposits_get_transaction, &deposits_get_transaction,
&ctx)) &ctx))
return mhd_ret; return mhd_ret;
if (GNUNET_YES == ctx.pending)
return TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_ACCEPTED,
GNUNET_JSON_pack_time_abs ("execution_time",
ctx.execution_time));
if (GNUNET_SYSERR == ctx.pending) if (GNUNET_SYSERR == ctx.pending)
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR, MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_INVARIANT_FAILURE, TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
"wire fees exceed aggregate in database"); "wire fees exceed aggregate in database");
if (GNUNET_YES == ctx.pending)
return TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_ACCEPTED,
GNUNET_JSON_pack_uint64 ("payment_target_uuid",
ctx.kyc.payment_target_uuid),
GNUNET_JSON_pack_bool ("kyc_ok",
ctx.kyc.ok),
GNUNET_JSON_pack_time_abs ("execution_time",
ctx.execution_time));
return reply_deposit_details (connection, return reply_deposit_details (connection,
&tps->h_contract_terms, &tps->h_contract_terms,
&tps->h_wire, &tps->h_wire,

View File

@ -948,7 +948,9 @@ prepare_statements (struct PostgresClosure *pg)
Used in #postgres_lookup_transfer_by_deposit(). */ Used in #postgres_lookup_transfer_by_deposit(). */
GNUNET_PQ_make_prepare ("get_deposit_for_wtid", GNUNET_PQ_make_prepare ("get_deposit_for_wtid",
"SELECT" "SELECT"
" amount_with_fee_val" " FALSE AS kyc_ok" // FIXME
",CAST (0 AS INT8) AS payment_target_uuid" // FIXME
",amount_with_fee_val"
",amount_with_fee_frac" ",amount_with_fee_frac"
",denom.fee_deposit_val" ",denom.fee_deposit_val"
",denom.fee_deposit_frac" ",denom.fee_deposit_frac"
@ -957,9 +959,9 @@ prepare_statements (struct PostgresClosure *pg)
" JOIN known_coins USING (known_coin_id)" " JOIN known_coins USING (known_coin_id)"
" JOIN denominations denom USING (denominations_serial)" " JOIN denominations denom USING (denominations_serial)"
" WHERE ((coin_pub=$1)" " WHERE ((coin_pub=$1)"
" AND (merchant_pub=$2)" " AND (merchant_pub=$4)"
" AND (h_contract_terms=$3)" " AND (h_contract_terms=$2)"
" AND (h_wire=$4)" " AND (h_wire=$3)"
" );", " );",
4), 4),
/* Used in #postgres_get_ready_deposit() */ /* Used in #postgres_get_ready_deposit() */
@ -6686,10 +6688,16 @@ postgres_lookup_wire_transfer (
* @param h_wire hash of merchant wire details * @param h_wire hash of merchant wire details
* @param coin_pub public key of deposited coin * @param coin_pub public key of deposited coin
* @param merchant_pub merchant public key * @param merchant_pub merchant public key
* @param cb function to call with the result * @param[out] pending set to true if the transaction is still pending
* @param cb_cls closure to pass to @a cb * @param[out] wtid wire transfer identifier, only set if @a pending is false
* @param[out] coin_contribution how much did the coin we asked about
* contribute to the total transfer value? (deposit value including fee)
* @param[out] coin_fee how much did the exchange charge for the deposit fee
* @param[out] execution_time when was the transaction done, or
* when we expect it to be done (if @a pending is false)
* @param[out] kyc set to the kyc status of the receiver (if @a pending)
* @return transaction status code * @return transaction status code
- */ */
static enum GNUNET_DB_QueryStatus static enum GNUNET_DB_QueryStatus
postgres_lookup_transfer_by_deposit ( postgres_lookup_transfer_by_deposit (
void *cls, void *cls,
@ -6697,8 +6705,12 @@ postgres_lookup_transfer_by_deposit (
const struct GNUNET_HashCode *h_wire, const struct GNUNET_HashCode *h_wire,
const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_MerchantPublicKeyP *merchant_pub, const struct TALER_MerchantPublicKeyP *merchant_pub,
TALER_EXCHANGEDB_WireTransferByCoinCallback cb, bool *pending,
void *cb_cls) struct TALER_WireTransferIdentifierRawP *wtid,
struct GNUNET_TIME_Absolute *exec_time,
struct TALER_Amount *amount_with_fee,
struct TALER_Amount *deposit_fee,
struct TALER_EXCHANGEDB_KycStatus *kyc)
{ {
struct PostgresClosure *pg = cls; struct PostgresClosure *pg = cls;
enum GNUNET_DB_QueryStatus qs; enum GNUNET_DB_QueryStatus qs;
@ -6709,39 +6721,39 @@ postgres_lookup_transfer_by_deposit (
GNUNET_PQ_query_param_auto_from_type (merchant_pub), GNUNET_PQ_query_param_auto_from_type (merchant_pub),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
}; };
struct TALER_WireTransferIdentifierRawP wtid;
struct GNUNET_TIME_Absolute exec_time;
struct TALER_Amount amount_with_fee;
struct TALER_Amount deposit_fee;
struct GNUNET_PQ_ResultSpec rs[] = { struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_auto_from_type ("wtid_raw", GNUNET_PQ_result_spec_auto_from_type ("wtid_raw",
&wtid), wtid),
TALER_PQ_result_spec_absolute_time ("execution_date", TALER_PQ_result_spec_absolute_time ("execution_date",
&exec_time), exec_time),
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee", TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
&amount_with_fee), amount_with_fee),
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit", TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
&deposit_fee), deposit_fee),
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
/* check if the melt record exists and get it */ /* check if the aggregation record exists and get it */
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"lookup_deposit_wtid", "lookup_deposit_wtid",
params, params,
rs); rs);
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
{ {
cb (cb_cls, *pending = false;
&wtid, memset (kyc,
&amount_with_fee, 0,
&deposit_fee, sizeof (*kyc));
exec_time); kyc->type = TALER_EXCHANGEDB_KYC_DEPOSIT;
kyc->ok = true;
return qs; return qs;
} }
if (0 > qs) if (0 > qs)
return qs; return qs;
*pending = true;
memset (wtid,
0,
sizeof (*wtid));
GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs); GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"lookup_deposit_wtid returned 0 matching rows\n"); "lookup_deposit_wtid returned 0 matching rows\n");
@ -6749,38 +6761,27 @@ postgres_lookup_transfer_by_deposit (
/* Check if transaction exists in deposits, so that we just /* Check if transaction exists in deposits, so that we just
do not have a WTID yet, if so, do call the CB with a NULL wtid do not have a WTID yet, if so, do call the CB with a NULL wtid
and return #GNUNET_YES! */ and return #GNUNET_YES! */
struct GNUNET_PQ_QueryParam params2[] = { uint8_t ok8 = 0;
GNUNET_PQ_query_param_auto_from_type (coin_pub),
GNUNET_PQ_query_param_auto_from_type (merchant_pub),
GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
GNUNET_PQ_query_param_auto_from_type (h_wire),
GNUNET_PQ_query_param_end
};
struct GNUNET_TIME_Absolute exec_time;
struct TALER_Amount amount_with_fee;
struct TALER_Amount deposit_fee;
struct GNUNET_PQ_ResultSpec rs2[] = { struct GNUNET_PQ_ResultSpec rs2[] = {
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee", &amount_with_fee), GNUNET_PQ_result_spec_uint64 ("payment_target_uuid",
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit", &deposit_fee), &kyc->payment_target_uuid),
TALER_PQ_result_spec_absolute_time ("wire_deadline", &exec_time), GNUNET_PQ_result_spec_auto_from_type ("kyc_ok",
&ok8),
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
amount_with_fee),
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
deposit_fee),
TALER_PQ_result_spec_absolute_time ("wire_deadline",
exec_time),
GNUNET_PQ_result_spec_end GNUNET_PQ_result_spec_end
}; };
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"get_deposit_for_wtid", "get_deposit_for_wtid",
params2, params,
rs2); rs2);
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) kyc->type = TALER_EXCHANGEDB_KYC_DEPOSIT;
{ kyc->ok = (0 != ok8);
/* Ok, we're aware of the transaction, but it has not yet been
executed */
cb (cb_cls,
NULL,
&amount_with_fee,
&deposit_fee,
exec_time);
return qs;
}
return qs; return qs;
} }
} }

View File

@ -716,20 +716,6 @@ cb_wt_never (void *cls,
} }
/**
* Callback that should never be called.
*/
static void
cb_wtid_never (void *cls,
const struct TALER_WireTransferIdentifierRawP *wtid,
const struct TALER_Amount *coin_contribution,
const struct TALER_Amount *coin_fee,
struct GNUNET_TIME_Absolute execution_time)
{
GNUNET_assert (0);
}
static struct TALER_MerchantPublicKeyP merchant_pub_wt; static struct TALER_MerchantPublicKeyP merchant_pub_wt;
static struct GNUNET_HashCode h_wire_wt; static struct GNUNET_HashCode h_wire_wt;
static struct GNUNET_HashCode h_contract_terms_wt; static struct GNUNET_HashCode h_contract_terms_wt;
@ -777,28 +763,6 @@ cb_wt_check (void *cls,
} }
/**
* Callback that should be called with the WT data.
*/
static void
cb_wtid_check (void *cls,
const struct TALER_WireTransferIdentifierRawP *wtid,
const struct TALER_Amount *coin_contribution,
const struct TALER_Amount *coin_fee,
struct GNUNET_TIME_Absolute execution_time)
{
GNUNET_assert (cls == &cb_wtid_never);
GNUNET_assert (0 == GNUNET_memcmp (wtid,
&wire_out_wtid));
GNUNET_assert (execution_time.abs_value_us ==
wire_out_date.abs_value_us);
GNUNET_assert (0 == TALER_amount_cmp (coin_contribution,
&coin_value_wt));
GNUNET_assert (0 == TALER_amount_cmp (coin_fee,
&coin_fee_wt));
}
/** /**
* Here #deposit_cb() will store the row ID of the deposit. * Here #deposit_cb() will store the row ID of the deposit.
*/ */
@ -1285,6 +1249,12 @@ test_wire_out (const struct TALER_EXCHANGEDB_Deposit *deposit)
{ {
struct GNUNET_HashCode h_contract_terms_wt2 = h_contract_terms_wt; struct GNUNET_HashCode h_contract_terms_wt2 = h_contract_terms_wt;
bool pending;
struct TALER_WireTransferIdentifierRawP wtid2;
struct TALER_Amount coin_contribution2;
struct TALER_Amount coin_fee2;
struct GNUNET_TIME_Absolute execution_time2;
struct TALER_EXCHANGEDB_KycStatus kyc;
h_contract_terms_wt2.bits[0]++; h_contract_terms_wt2.bits[0]++;
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
@ -1293,8 +1263,12 @@ test_wire_out (const struct TALER_EXCHANGEDB_Deposit *deposit)
&h_wire_wt, &h_wire_wt,
&coin_pub_wt, &coin_pub_wt,
&merchant_pub_wt, &merchant_pub_wt,
&cb_wtid_never, &pending,
NULL)); &wtid2,
&execution_time2,
&coin_contribution2,
&coin_fee2,
&kyc));
} }
/* insert WT data */ /* insert WT data */
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
@ -1338,14 +1312,35 @@ test_wire_out (const struct TALER_EXCHANGEDB_Deposit *deposit)
&wire_out_wtid, &wire_out_wtid,
&cb_wt_check, &cb_wt_check,
&cb_wt_never)); &cb_wt_never));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != {
plugin->lookup_transfer_by_deposit (plugin->cls, bool pending;
&h_contract_terms_wt, struct TALER_WireTransferIdentifierRawP wtid2;
&h_wire_wt, struct TALER_Amount coin_contribution2;
&coin_pub_wt, struct TALER_Amount coin_fee2;
&merchant_pub_wt, struct GNUNET_TIME_Absolute execution_time2;
&cb_wtid_check, struct TALER_EXCHANGEDB_KycStatus kyc;
&cb_wtid_never));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->lookup_transfer_by_deposit (plugin->cls,
&h_contract_terms_wt,
&h_wire_wt,
&coin_pub_wt,
&merchant_pub_wt,
&pending,
&wtid2,
&execution_time2,
&coin_contribution2,
&coin_fee2,
&kyc));
GNUNET_assert (0 == GNUNET_memcmp (&wtid2,
&wire_out_wtid));
GNUNET_assert (execution_time2.abs_value_us ==
wire_out_date.abs_value_us);
GNUNET_assert (0 == TALER_amount_cmp (&coin_contribution2,
&coin_value_wt));
GNUNET_assert (0 == TALER_amount_cmp (&coin_fee2,
&coin_fee_wt));
}
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->select_wire_out_above_serial_id (plugin->cls, plugin->select_wire_out_above_serial_id (plugin->cls,
0, 0,

View File

@ -1874,6 +1874,12 @@ struct TALER_EXCHANGE_GetDepositResponse
* to check for its KYC status. * to check for its KYC status.
*/ */
uint64_t payment_target_uuid; uint64_t payment_target_uuid;
/**
* Set to 'true' if the KYC check is already finished and
* the exchange is merely waiting for the @e execution_time.
*/
bool kyc_ok;
} accepted; } accepted;
} details; } details;

View File

@ -1832,29 +1832,6 @@ typedef void
const struct TALER_EXCHANGEDB_LinkList *ldl); const struct TALER_EXCHANGEDB_LinkList *ldl);
/**
* Function called with the results of the lookup of the wire transfer
* identifier information. Only called if we are at least aware of the
* transaction existing.
*
* @param cls closure
* @param wtid wire transfer identifier, NULL
* if the transaction was not yet done
* @param coin_contribution how much did the coin we asked about
* contribute to the total transfer value? (deposit value including fee)
* @param coin_fee how much did the exchange charge for the deposit fee
* @param execution_time when was the transaction done, or
* when we expect it to be done (if @a wtid was NULL)
*/
typedef void
(*TALER_EXCHANGEDB_WireTransferByCoinCallback)(
void *cls,
const struct TALER_WireTransferIdentifierRawP *wtid,
const struct TALER_Amount *coin_contribution,
const struct TALER_Amount *coin_fee,
struct GNUNET_TIME_Absolute execution_time);
/** /**
* Function called with the results of the lookup of the * Function called with the results of the lookup of the
* transaction data associated with a wire transfer identifier. * transaction data associated with a wire transfer identifier.
@ -2916,8 +2893,14 @@ struct TALER_EXCHANGEDB_Plugin
* @param h_wire hash of merchant wire details * @param h_wire hash of merchant wire details
* @param coin_pub public key of deposited coin * @param coin_pub public key of deposited coin
* @param merchant_pub merchant public key * @param merchant_pub merchant public key
* @param cb function to call with the result * @param[out] pending set to true if the transaction is still pending
* @param cb_cls closure to pass to @a cb * @param[out] wtid wire transfer identifier, only set if @a pending is false
* @param[out] coin_contribution how much did the coin we asked about
* contribute to the total transfer value? (deposit value including fee)
* @param[out] coin_fee how much did the exchange charge for the deposit fee
* @param[out] execution_time when was the transaction done, or
* when we expect it to be done (if @a pending is false)
* @param[out] kyc set to the kyc status of the receiver (if @a pending)
* @return transaction status code * @return transaction status code
*/ */
enum GNUNET_DB_QueryStatus enum GNUNET_DB_QueryStatus
@ -2927,8 +2910,12 @@ struct TALER_EXCHANGEDB_Plugin
const struct GNUNET_HashCode *h_wire, const struct GNUNET_HashCode *h_wire,
const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_MerchantPublicKeyP *merchant_pub, const struct TALER_MerchantPublicKeyP *merchant_pub,
TALER_EXCHANGEDB_WireTransferByCoinCallback cb, bool *pending,
void *cb_cls); struct TALER_WireTransferIdentifierRawP *wtid,
struct GNUNET_TIME_Absolute *exec_time,
struct TALER_Amount *amount_with_fee,
struct TALER_Amount *deposit_fee,
struct TALER_EXCHANGEDB_KycStatus *kyc);
/** /**

View File

@ -197,6 +197,10 @@ handle_deposit_wtid_finished (void *cls,
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_absolute_time ("execution_time", TALER_JSON_spec_absolute_time ("execution_time",
&dr.details.accepted.execution_time), &dr.details.accepted.execution_time),
GNUNET_JSON_spec_uint64 ("execution_time",
&dr.details.accepted.payment_target_uuid),
GNUNET_JSON_spec_bool ("kyc_ok",
&dr.details.accepted.kyc_ok),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
@ -210,7 +214,6 @@ handle_deposit_wtid_finished (void *cls,
dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break; break;
} }
dr.details.accepted.payment_target_uuid; // FIXME
dwh->cb (dwh->cb_cls, dwh->cb (dwh->cb_cls,
&dr); &dr);
TALER_EXCHANGE_deposits_get_cancel (dwh); TALER_EXCHANGE_deposits_get_cancel (dwh);