diff options
-rw-r--r-- | configure.ac | 10 | ||||
-rw-r--r-- | src/include/taler_crypto_lib.h | 12 | ||||
-rw-r--r-- | src/include/taler_mintdb_plugin.h | 42 | ||||
-rw-r--r-- | src/include/taler_signatures.h | 19 | ||||
-rw-r--r-- | src/mint-lib/mint_api_context.c | 10 | ||||
-rw-r--r-- | src/mint-lib/mint_api_deposit.c | 33 | ||||
-rw-r--r-- | src/mint-lib/mint_api_handle.c | 4 | ||||
-rw-r--r-- | src/mint-lib/mint_api_wire.c | 1 | ||||
-rw-r--r-- | src/mint-lib/test_mint_api.c | 1 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd.c | 8 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_db.c | 93 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_db.h | 20 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_responses.c | 51 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_responses.h | 40 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_tracking.c | 86 | ||||
-rw-r--r-- | src/mintdb/perf_taler_mintdb_interpreter.c | 2 | ||||
-rw-r--r-- | src/mintdb/plugin_mintdb_postgres.c | 32 | ||||
-rw-r--r-- | src/util/wireformats.c | 12 |
18 files changed, 422 insertions, 54 deletions
diff --git a/configure.ac b/configure.ac index 498053c35..6a64cbff7 100644 --- a/configure.ac +++ b/configure.ac @@ -142,6 +142,11 @@ AS_IF([test $jansson = 0], *** ]])]) +# test for postgres +AX_LIB_POSTGRESQL([9.3]) +if test "$found_postgresql" = "yes"; then + postgres=true +fi else @@ -195,11 +200,6 @@ AC_SUBST(TALER_LIB_LDFLAGS) AC_SUBST(TALER_PLUGIN_LDFLAGS) -# test for postgres -AX_LIB_POSTGRESQL([9.3]) -if test "$found_postgresql" = "yes"; then - postgres=true -fi AM_CONDITIONAL(HAVE_POSTGRESQL, test x$postgres = xtrue) # check for libgnurl diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h index 082b439b2..16240e5a3 100644 --- a/src/include/taler_crypto_lib.h +++ b/src/include/taler_crypto_lib.h @@ -102,6 +102,18 @@ struct TALER_MerchantPrivateKeyP /** + * @brief Type of signatures made by merchants. + */ +struct TALER_MerchantSignatureP +{ + /** + * Taler uses EdDSA for merchants. + */ + struct GNUNET_CRYPTO_EddsaSignature eddsa_sig; +}; + + +/** * @brief Type of transfer public keys used during refresh * operations. */ diff --git a/src/include/taler_mintdb_plugin.h b/src/include/taler_mintdb_plugin.h index d83cf9d44..d9a1c6c85 100644 --- a/src/include/taler_mintdb_plugin.h +++ b/src/include/taler_mintdb_plugin.h @@ -569,6 +569,23 @@ typedef void /** + * Function called with the results of the lookup of the + * wire transfer identifier information. + * + * @param cls closure + * @param wtid base32-encoded wire transfer identifier, NULL + * if the transaction was not yet done + * @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 mint + */ +typedef void +(*TALER_MINTDB_DepositWtidCallback)(void *cls, + const char *wtid, + struct GNUNET_TIME_Absolute execution_time); + +/** * @brief The plugin API, returned from the plugin's "init" function. * The argument given to "init" is simply a configuration handle. */ @@ -1177,6 +1194,31 @@ struct TALER_MINTDB_Plugin struct TALER_MINTDB_TransactionList *list); + /** + * Try to find the wire transfer details for a deposit operation. + * If we did not execute the deposit yet, return when it is supposed + * to be executed. + * + * @param cls closure + * @param h_contract hash of the contract + * @param h_wire hash of merchant wire details + * @param coin_pub public key of deposited coin + * @param merchant_pub merchant public key + * @param transaction_id transaction identifier + * @param cb function to call with the result + * @param cb_cls closure to pass to @a cb + * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors + */ + int + (*wire_lookup_deposit_wtid)(void *cls, + const struct GNUNET_HashCode *h_contract, + const struct GNUNET_HashCode *h_wire, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_MerchantPublicKeyP *merchant_pub, + uint64_t transaction_id, + TALER_MINTDB_DepositWtidCallback cb, + void *cb_cls); + }; diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h index ea9ed600a..fb2916cff 100644 --- a/src/include/taler_signatures.h +++ b/src/include/taler_signatures.h @@ -843,6 +843,25 @@ struct TALER_DepositTrackPS }; +/** + * The contract sent by the merchant to the wallet. + */ +struct TALER_ContractPS +{ + /** + * Purpose header for the signature over the contract with + * purpose #TALER_SIGNATURE_MERCHANT_CONTRACT. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Hash of the JSON contract in UTF-8 including 0-termination, + * using JSON_COMPACT | JSON_SORT_KEYS + */ + struct GNUNET_HashCode h_contract; + +}; + GNUNET_NETWORK_STRUCT_END diff --git a/src/mint-lib/mint_api_context.c b/src/mint-lib/mint_api_context.c index 4ab46e4ee..be3df7c21 100644 --- a/src/mint-lib/mint_api_context.c +++ b/src/mint-lib/mint_api_context.c @@ -333,15 +333,23 @@ TALER_MINT_get_select_info (struct TALER_MINT_Context *ctx, int *max_fd, long *timeout) { + long to; + GNUNET_assert (CURLM_OK == curl_multi_fdset (ctx->multi, read_fd_set, write_fd_set, except_fd_set, max_fd)); + to = *timeout; GNUNET_assert (CURLM_OK == curl_multi_timeout (ctx->multi, - timeout)); + &to)); + /* Only if what we got back from curl is smaller than what we + already had (-1 == infinity!), then update timeout */ + if ( (to < *timeout) && + (-1 != to) ) + *timeout = to; if ( (-1 == (*timeout)) && (NULL != ctx->jobs_head) ) *timeout = 1000 * 60 * 5; /* curl is not always good about giving timeouts */ diff --git a/src/mint-lib/mint_api_deposit.c b/src/mint-lib/mint_api_deposit.c index bf00ffa28..541317763 100644 --- a/src/mint-lib/mint_api_deposit.c +++ b/src/mint-lib/mint_api_deposit.c @@ -312,39 +312,6 @@ verify_signatures (const struct TALER_MINT_DenomPublicKey *dki, &dki->fee_deposit); dr.merchant = *merchant_pub; dr.coin_pub = *coin_pub; - - char *contract_str = GNUNET_STRINGS_data_to_string_alloc (h_contract, - sizeof (struct GNUNET_HashCode)); - char *wire_str = GNUNET_STRINGS_data_to_string_alloc (h_wire, - sizeof (struct GNUNET_HashCode)); - char *merchant_pub_str = GNUNET_STRINGS_data_to_string_alloc (merchant_pub, - sizeof (struct TALER_MerchantPublicKeyP)); - char *coin_pub_str = GNUNET_STRINGS_data_to_string_alloc (coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP)); - printf ("verifying:\ncontract [%s]\nwire [%s]\n" - "timestamp [%llu]\nrefund deadline [%llu]\n" - "transaction id [%llu]\namount [%s %llu.%lu]\n" - "fee deposit [%s %llu.%lu]\nmerch pub [%s]\n" - "coin pub [%s]\n", - contract_str, - wire_str, - timestamp.abs_value_us, - refund_deadline.abs_value_us, - transaction_id, - amount->currency, - amount->value, - amount->fraction, - dki->fee_deposit.currency, - dki->fee_deposit.value, - dki->fee_deposit.fraction, - merchant_pub_str, - coin_pub_str); - - GNUNET_free (contract_str); - GNUNET_free (wire_str); - GNUNET_free (merchant_pub_str); - GNUNET_free (coin_pub_str); - if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT, &dr.purpose, diff --git a/src/mint-lib/mint_api_handle.c b/src/mint-lib/mint_api_handle.c index ef3da60ec..0ee24123f 100644 --- a/src/mint-lib/mint_api_handle.c +++ b/src/mint-lib/mint_api_handle.c @@ -695,6 +695,10 @@ MAH_path_to_url (struct TALER_MINT_Handle *h, { char *url; + if ( ('/' == path[0]) && + (0 < strlen (h->url)) && + ('/' == h->url[strlen (h->url) - 1]) ) + path++; /* avoid generating URL with "//" from concat */ GNUNET_asprintf (&url, "%s%s", h->url, diff --git a/src/mint-lib/mint_api_wire.c b/src/mint-lib/mint_api_wire.c index 2af9e6ed0..5fc82f72d 100644 --- a/src/mint-lib/mint_api_wire.c +++ b/src/mint-lib/mint_api_wire.c @@ -358,6 +358,7 @@ request_wire_method (struct TALER_MINT_WireHandle *wh) GNUNET_YES, &handle_wire_method_finished, wh); + TALER_MINT_perform (ctx); } diff --git a/src/mint-lib/test_mint_api.c b/src/mint-lib/test_mint_api.c index 5f465363e..024e080fc 100644 --- a/src/mint-lib/test_mint_api.c +++ b/src/mint-lib/test_mint_api.c @@ -1524,6 +1524,7 @@ interpreter_run (void *cls, fail (is); return; } + json_decref (wire); trigger_context_task (); return; } diff --git a/src/mint/taler-mint-httpd.c b/src/mint/taler-mint-httpd.c index 4f35103a7..26a440c95 100644 --- a/src/mint/taler-mint-httpd.c +++ b/src/mint/taler-mint-httpd.c @@ -365,10 +365,10 @@ handle_mhd_request (void *cls, upload_data_size); } return TMH_MHD_handler_static_response (&h404, - connection, - con_cls, - upload_data, - upload_data_size); + connection, + con_cls, + upload_data, + upload_data_size); } diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c index 2d8af2759..2b4ade595 100644 --- a/src/mint/taler-mint-httpd_db.c +++ b/src/mint/taler-mint-httpd_db.c @@ -1551,4 +1551,97 @@ TMH_DB_execute_admin_add_incoming (struct MHD_Connection *connection, } +/** + * Closure for #handle_wtid_data. + */ +struct DepositWtidContext +{ + + /** + * Where should we send the reply? + */ + struct MHD_Connection *connection; + + /** + * MHD result code to return. + */ + int res; +}; + + +/** + * Function called with the results of the lookup of the + * wire transfer identifier information. + * + * @param cls our context for transmission + * @param wtid base32-encoded wire transfer identifier, NULL + * if the transaction was not yet done + * @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 mint + */ +static void +handle_wtid_data (void *cls, + const char *wtid, + struct GNUNET_TIME_Absolute execution_time) +{ + struct DepositWtidContext *ctx = cls; + + if (NULL == wtid) + { + if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us == + execution_time.abs_value_us) + ctx->res = TMH_RESPONSE_reply_deposit_unknown (ctx->connection); + else + ctx->res = TMH_RESPONSE_reply_deposit_pending (ctx->connection); + } + else + { + ctx->res = TMH_RESPONSE_reply_deposit_wtid (ctx->connection); + } +} + + +/** + * Execute a "/deposit/wtid". Returns the transfer information + * associated with the given deposit. + * + * @param connection the MHD connection to handle + * @param h_contract hash of the contract + * @param h_wire hash of the wire details + * @param coin_pub public key of the coin to link + * @param merchant_pub public key of the merchant + * @param transaction_id transaction ID of the merchant + * @return MHD result code + */ +int +TMH_DB_execute_deposit_wtid (struct MHD_Connection *connection, + const struct GNUNET_HashCode *h_contract, + const struct GNUNET_HashCode *h_wire, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_MerchantPublicKeyP *merchant_pub, + uint64_t transaction_id) +{ + int ret; + struct DepositWtidContext ctx; + + ctx.connection = connection; + ret = TMH_plugin->wire_lookup_deposit_wtid (TMH_plugin->cls, + h_contract, + h_wire, + coin_pub, + merchant_pub, + transaction_id, + &handle_wtid_data, + connection); + if (GNUNET_SYSERR == ret) + { + GNUNET_break (0); + return TMH_RESPONSE_reply_internal_db_error (connection); + } + return ctx.res; +} + + /* end of taler-mint-httpd_db.c */ diff --git a/src/mint/taler-mint-httpd_db.h b/src/mint/taler-mint-httpd_db.h index f1d9fbfb8..d9adba2d9 100644 --- a/src/mint/taler-mint-httpd_db.h +++ b/src/mint/taler-mint-httpd_db.h @@ -192,5 +192,25 @@ TMH_DB_execute_admin_add_incoming (struct MHD_Connection *connection, json_t *wire); +/** + * Execute a "/deposit/wtid". Returns the transfer information + * associated with the given deposit. + * + * @param connection the MHD connection to handle + * @param h_contract hash of the contract + * @param h_wire hash of the wire details + * @param coin_pub public key of the coin to link + * @param merchant_pub public key of the merchant + * @param transaction_id transaction ID of the merchant + * @return MHD result code + */ +int +TMH_DB_execute_deposit_wtid (struct MHD_Connection *connection, + const struct GNUNET_HashCode *h_contract, + const struct GNUNET_HashCode *h_wire, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_MerchantPublicKeyP *merchant_pub, + uint64_t transaction_id); + #endif /* TALER_MINT_HTTPD_DB_H */ diff --git a/src/mint/taler-mint-httpd_responses.c b/src/mint/taler-mint-httpd_responses.c index 3b04fdb3c..f3498b469 100644 --- a/src/mint/taler-mint-httpd_responses.c +++ b/src/mint/taler-mint-httpd_responses.c @@ -1050,4 +1050,55 @@ TMH_RESPONSE_reply_refresh_link_success (struct MHD_Connection *connection, } +/** + * A merchant asked for details about a deposit, but + * we do not know anything about the deposit. Generate the + * 404 reply. + * + * @param connection connection to the client + * @param + * @return MHD result code + */ +int +TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection, + ...) +{ + GNUNET_break (0); // FIXME: not implemented + return MHD_NO; +} + + +/** + * A merchant asked for details about a deposit, but + * we did not execute the deposit yet. Generate a 202 reply. + * + * @param connection connection to the client + * @param + * @return MHD result code + */ +int +TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection, + ...) +{ + GNUNET_break (0); // FIXME: not implemented + return MHD_NO; +} + + +/** + * A merchant asked for details about a deposit. Provide + * them. Generates the 200 reply. + * + * @param connection connection to the client + * @param + * @return MHD result code + */ +int +TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection, + ...) +{ + GNUNET_break (0); // FIXME: not implemented + return MHD_NO; +} + /* end of taler-mint-httpd_responses.c */ diff --git a/src/mint/taler-mint-httpd_responses.h b/src/mint/taler-mint-httpd_responses.h index 9746ef90b..5d1523b4b 100644 --- a/src/mint/taler-mint-httpd_responses.h +++ b/src/mint/taler-mint-httpd_responses.h @@ -248,6 +248,46 @@ TMH_RESPONSE_reply_deposit_insufficient_funds (struct MHD_Connection *connection /** + * A merchant asked for details about a deposit, but + * we do not know anything about the deposit. Generate the + * 404 reply. + * + * @param connection connection to the client + * @param + * @return MHD result code + */ +int +TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection, + ...); + + +/** + * A merchant asked for details about a deposit, but + * we did not execute the deposit yet. Generate a 202 reply. + * + * @param connection connection to the client + * @param + * @return MHD result code + */ +int +TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection, + ...); + + +/** + * A merchant asked for details about a deposit. Provide + * them. Generates the 200 reply. + * + * @param connection connection to the client + * @param + * @return MHD result code + */ +int +TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection, + ...); + + +/** * Send reserve status information to client. * * @param connection connection to the client diff --git a/src/mint/taler-mint-httpd_tracking.c b/src/mint/taler-mint-httpd_tracking.c index beb4b4dd1..59d029429 100644 --- a/src/mint/taler-mint-httpd_tracking.c +++ b/src/mint/taler-mint-httpd_tracking.c @@ -23,6 +23,7 @@ #include <jansson.h> #include <microhttpd.h> #include <pthread.h> +#include "taler_signatures.h" #include "taler-mint-httpd_parsing.h" #include "taler-mint-httpd_tracking.h" #include "taler-mint-httpd_responses.h" @@ -51,6 +52,43 @@ TMH_TRACKING_handler_wire_deposits (struct TMH_RequestHandler *rh, /** + * Check the merchant signature, and if it is valid, + * return the wire transfer identifier. + * + * @param connection the MHD connection to handle + * @param tps signed request to execute + * @param merchant_pub public key from the merchant + * @param merchant_sig signature from the merchant (to be checked) + * @param transaction_id transaction ID (in host byte order) + * @return MHD result code + */ +static int +check_and_handle_deposit_wtid_request (struct MHD_Connection *connection, + const struct TALER_DepositTrackPS *tps, + struct TALER_MerchantPublicKeyP *merchant_pub, + struct TALER_MerchantSignatureP *merchant_sig, + uint64_t transaction_id) +{ + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_DEPOSIT_WTID, + &tps->purpose, + &merchant_sig->eddsa_sig, + &merchant_pub->eddsa_pub)) + { + GNUNET_break_op (0); + return TMH_RESPONSE_reply_signature_invalid (connection, + "merchant_sig"); + } + return TMH_DB_execute_deposit_wtid (connection, + &tps->h_contract, + &tps->h_wire, + &tps->coin_pub, + merchant_pub, + transaction_id); +} + + +/** * Handle a "/deposit/wtid" request. * * @param rh context of the handler @@ -59,7 +97,7 @@ TMH_TRACKING_handler_wire_deposits (struct TMH_RequestHandler *rh, * @param upload_data upload data * @param[in,out] upload_data_size number of bytes (left) in @a upload_data * @return MHD result code - */ + */ int TMH_TRACKING_handler_deposit_wtid (struct TMH_RequestHandler *rh, struct MHD_Connection *connection, @@ -67,8 +105,50 @@ TMH_TRACKING_handler_deposit_wtid (struct TMH_RequestHandler *rh, const char *upload_data, size_t *upload_data_size) { - GNUNET_break (0); // not implemented - return MHD_NO; + int res; + json_t *json; + struct TALER_DepositTrackPS tps; + uint64_t transaction_id; + struct TALER_MerchantSignatureP merchant_sig; + struct TALER_MerchantPublicKeyP merchant_pub; + struct TMH_PARSE_FieldSpecification spec[] = { + TMH_PARSE_member_fixed ("H_wire", &tps.h_wire), + TMH_PARSE_member_fixed ("H_contract", &tps.h_contract), + TMH_PARSE_member_fixed ("coin_pub", &tps.coin_pub), + TMH_PARSE_member_uint64 ("transaction_id", &transaction_id), + TMH_PARSE_member_fixed ("merchant_pub", &merchant_pub), + TMH_PARSE_member_fixed ("merchant_sig", &merchant_sig), + TMH_PARSE_MEMBER_END + }; + + res = TMH_PARSE_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); + if (GNUNET_SYSERR == res) + return MHD_NO; + if ( (GNUNET_NO == res) || (NULL == json) ) + return MHD_YES; + res = TMH_PARSE_json_data (connection, + json, + spec); + if (GNUNET_OK != res) + { + json_decref (json); + return (GNUNET_NO == res) ? MHD_YES : MHD_NO; + } + tps.purpose.size = htonl (sizeof (struct TALER_DepositTrackPS)); + tps.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_DEPOSIT_WTID); + tps.transaction_id = GNUNET_htonll (transaction_id); + res = check_and_handle_deposit_wtid_request (connection, + &tps, + &merchant_pub, + &merchant_sig, + transaction_id); + TMH_PARSE_release_data (spec); + json_decref (json); + return res; } diff --git a/src/mintdb/perf_taler_mintdb_interpreter.c b/src/mintdb/perf_taler_mintdb_interpreter.c index 31f5d6508..9084513fb 100644 --- a/src/mintdb/perf_taler_mintdb_interpreter.c +++ b/src/mintdb/perf_taler_mintdb_interpreter.c @@ -1735,7 +1735,7 @@ interpret (struct PERF_TALER_MINTDB_interpreter_state *state) 1, 1, refresh_commit); - + GNUNET_assert (GNUNET_OK == ret); } break; diff --git a/src/mintdb/plugin_mintdb_postgres.c b/src/mintdb/plugin_mintdb_postgres.c index 6ed52e5e4..0f32cfb8e 100644 --- a/src/mintdb/plugin_mintdb_postgres.c +++ b/src/mintdb/plugin_mintdb_postgres.c @@ -3355,7 +3355,6 @@ postgres_get_coin_transactions (void *cls, } PQclear (result); } - /* FIXME: Handle locked coins (#3625) */ return head; cleanup: if (NULL != head) @@ -3366,6 +3365,36 @@ postgres_get_coin_transactions (void *cls, /** + * Try to find the wire transfer details for a deposit operation. + * If we did not execute the deposit yet, return when it is supposed + * to be executed. + * + * @param cls closure + * @param h_contract hash of the contract + * @param h_wire hash of merchant wire details + * @param coin_pub public key of deposited coin + * @param merchant_pub merchant public key + * @param transaction_id transaction identifier + * @param cb function to call with the result + * @param cb_cls closure to pass to @a cb + * @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors + */ +static int +postgres_wire_lookup_deposit_wtid (void *cls, + const struct GNUNET_HashCode *h_contract, + const struct GNUNET_HashCode *h_wire, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_MerchantPublicKeyP *merchant_pub, + uint64_t transaction_id, + TALER_MINTDB_DepositWtidCallback cb, + void *cb_cls) +{ + GNUNET_break (0); // not implemented + return GNUNET_SYSERR; +} + + +/** * Initialize Postgres database subsystem. * * @param cls a configuration instance @@ -3436,6 +3465,7 @@ libtaler_plugin_mintdb_postgres_init (void *cls) plugin->get_transfer = &postgres_get_transfer; plugin->get_coin_transactions = &postgres_get_coin_transactions; plugin->free_coin_transaction_list = &common_free_coin_transaction_list; + plugin->wire_lookup_deposit_wtid = &postgres_wire_lookup_deposit_wtid; return plugin; } diff --git a/src/util/wireformats.c b/src/util/wireformats.c index 594eaf426..dab7fb926 100644 --- a/src/util/wireformats.c +++ b/src/util/wireformats.c @@ -329,12 +329,12 @@ validate_sepa (const json_t *wire) ((json_t *) wire, &error, JSON_STRICT, "{" - "s:s " /* TYPE: sepa */ - "s:s " /* IBAN: iban */ - "s:s " /* name: beneficiary name */ - "s:s " /* BIC: beneficiary bank's BIC */ - "s:i " /* r: random 64-bit integer nounce */ - "s?s " /* address: address of the beneficiary */ + "s:s," /* TYPE: sepa */ + "s:s," /* IBAN: iban */ + "s:s," /* name: beneficiary name */ + "s:s," /* BIC: beneficiary bank's BIC */ + "s:i," /* r: random 64-bit integer nounce */ + "s:s" /* address: address of the beneficiary */ "}", "type", &type, "IBAN", &iban, |