diff --git a/modules/service/xchange/dap_chain_net_srv_xchange.c b/modules/service/xchange/dap_chain_net_srv_xchange.c index d620ee7c64fad6d3771446b9fecb7ac5a57ad36f..7dba00c290879a367942ba4c65a9489e6e15c137 100644 --- a/modules/service/xchange/dap_chain_net_srv_xchange.c +++ b/modules/service/xchange/dap_chain_net_srv_xchange.c @@ -37,6 +37,7 @@ static int s_callback_requested(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id, static int s_callback_response_success(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_t *a_srv_client, const void *a_data, size_t a_data_size); static int s_callback_response_error(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_t *a_srv_client, const void *a_data, size_t a_data_size); static int s_callback_receipt_next_success(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_t *a_srv_client, const void *a_data, size_t a_data_size); +static dap_chain_net_srv_xchange_price_t *s_xchange_db_load(char *a_key, uint8_t *a_item); static dap_chain_net_srv_xchange_t *s_srv_xchange; @@ -71,9 +72,16 @@ int dap_chain_net_srv_xchange_init() dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_XCHANGE_ID }; dap_chain_net_srv_t* l_srv = dap_chain_net_srv_add(l_uid, s_callback_requested, s_callback_response_success, s_callback_response_error, s_callback_receipt_next_success); - s_srv_xchange = DAP_NEW_Z(dap_chain_net_srv_xchange_t); + s_srv_xchange = DAP_NEW_Z(dap_chain_net_srv_xchange_t); l_srv->_inhertor = s_srv_xchange; s_srv_xchange->enabled = false; + size_t l_prices_count = 0; + dap_global_db_obj_t *l_prices = dap_chain_global_db_gr_load(GROUP_LOCAL_XCHANGE, &l_prices_count); + for (size_t i = 0; i < l_prices_count; i++) { + dap_chain_net_srv_xchange_price_t *l_price = s_xchange_db_load(l_prices[i].key, l_prices[i].value); + HASH_ADD_KEYPTR(hh, s_srv_xchange->pricelist, l_price->key_ptr, strlen(l_price->key_ptr), l_price); + } + dap_chain_global_db_objs_delete(l_prices, l_prices_count); return 0; } @@ -135,11 +143,12 @@ static dap_chain_datum_tx_receipt_t *s_xchage_receipt_create(dap_chain_net_srv_x { uint32_t l_ext_size = sizeof(uint64_t) + DAP_CHAIN_TICKER_SIZE_MAX; uint8_t *l_ext = DAP_NEW_SIZE(uint8_t, l_ext_size); - dap_lendian_put64(l_ext, a_price->datoshi_sell); - strcpy((char *)&l_ext[sizeof(uint64_t)], a_price->token_sell); + uint64_t l_datoshi_buy = (long double)a_price->datoshi_sell / a_price->rate; + dap_lendian_put64(l_ext, l_datoshi_buy); + strcpy((char *)&l_ext[sizeof(uint64_t)], a_price->token_buy); dap_chain_net_srv_price_unit_uid_t l_unit = { .uint32 = SERV_UNIT_UNDEFINED}; dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_XCHANGE_ID }; - dap_chain_datum_tx_receipt_t *l_receipt = dap_chain_datum_tx_receipt_create(l_uid, l_unit, 0, a_price->datoshi_buy, + dap_chain_datum_tx_receipt_t *l_receipt = dap_chain_datum_tx_receipt_create(l_uid, l_unit, 0, a_price->datoshi_sell, l_ext, l_ext_size); return l_receipt; } @@ -223,13 +232,14 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha // create empty transaction dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); - dap_ledger_t *l_ledger = dap_chain_ledger_by_net_name(a_price->net_sell->pub.name); - dap_chain_addr_t *l_seller_addr = (dap_chain_addr_t *) dap_chain_wallet_get_addr(a_wallet, a_price->net_sell->pub.id); + dap_ledger_t *l_ledger = dap_chain_ledger_by_net_name(a_price->net_buy->pub.name); + dap_chain_addr_t *l_seller_addr = (dap_chain_addr_t *)dap_chain_wallet_get_addr(a_wallet, a_price->net_buy->pub.id); dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0); - uint64_t l_value_sell = 0; // how many coins to transfer + uint64_t l_value_buy = 0; // how many coins to transfer // list of transaction with 'out' items to sell - dap_list_t *l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(l_ledger, a_price->token_sell, - l_seller_addr, a_price->datoshi_sell, &l_value_sell); + uint64_t l_datoshi_buy = ceill(a_price->datoshi_sell / a_price->rate); + dap_list_t *l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(l_ledger, a_price->token_buy, + l_seller_addr, l_datoshi_buy, &l_value_buy); if(!l_list_used_out) { dap_chain_datum_tx_delete(l_tx); log_it(L_WARNING, "Nothing to change (not enough funds)"); @@ -243,7 +253,7 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha // add 'in' items to sell uint64_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); dap_list_free_full(l_list_used_out, free); - if (l_value_to_items != l_value_sell) { + if (l_value_to_items != l_value_buy) { dap_chain_datum_tx_delete(l_tx); DAP_DELETE(l_seller_addr); log_it(L_ERROR, "Can't compose the transaction input"); @@ -266,16 +276,16 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha { // transfer selling coins const dap_chain_addr_t *l_buyer_addr = (dap_chain_addr_t *)l_tx_out_cond->params; - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_buyer_addr, a_price->datoshi_sell, a_price->token_sell) == -1) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_buyer_addr, l_datoshi_buy, a_price->token_buy) == -1) { dap_chain_datum_tx_delete(l_tx); DAP_DELETE(l_seller_addr); log_it(L_ERROR, "Can't add selling coins output"); return NULL; } // coin back - uint64_t l_value_back = l_value_sell - a_price->datoshi_sell; + uint64_t l_value_back = l_value_buy - l_datoshi_buy; if (l_value_back) { - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_seller_addr, l_value_back, a_price->token_sell) == -1) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_seller_addr, l_value_back, a_price->token_buy) == -1) { dap_chain_datum_tx_delete(l_tx); DAP_DELETE(l_seller_addr); log_it(L_ERROR, "Can't add selling coins back output"); @@ -283,7 +293,7 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha } } //transfer buying coins - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_seller_addr, a_price->datoshi_buy, a_price->token_buy) == -1) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_seller_addr, a_price->datoshi_sell, a_price->token_sell) == -1) { dap_chain_datum_tx_delete(l_tx); DAP_DELETE(l_seller_addr); log_it(L_ERROR, "Can't add buying coins output"); @@ -292,9 +302,9 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha DAP_DELETE(l_seller_addr); //transfer unbuying coins (partial exchange) uint64_t l_buying_value = l_tx_out_cond->header.value; - l_value_back = l_buying_value - a_price->datoshi_buy; + l_value_back = l_buying_value - a_price->datoshi_sell; if (l_value_back) { - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_buyer_addr, l_value_back, a_price->token_buy) == -1) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_buyer_addr, l_value_back, a_price->token_sell) == -1) { log_it(L_WARNING, "Can't add buying coins back output (cashback)"); return NULL; } @@ -337,8 +347,8 @@ static bool s_xchage_tx_invalidate(dap_chain_net_srv_xchange_price_t *a_price, d // create empty transaction dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); - dap_ledger_t *l_ledger = dap_chain_ledger_by_net_name(a_price->net_sell->pub.name); - dap_chain_addr_t *l_seller_addr = (dap_chain_addr_t *) dap_chain_wallet_get_addr(a_wallet, a_price->net_sell->pub.id); + dap_ledger_t *l_ledger = dap_chain_ledger_by_net_name(a_price->net_buy->pub.name); + dap_chain_addr_t *l_seller_addr = (dap_chain_addr_t *)dap_chain_wallet_get_addr(a_wallet, a_price->net_buy->pub.id); dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0); // create and add reciept @@ -380,7 +390,7 @@ static bool s_xchage_tx_invalidate(dap_chain_net_srv_xchange_price_t *a_price, d log_it( L_ERROR, "Can't add sign output"); return false; } - if (!s_xchange_tx_put(l_tx, a_price->net_sell)) { + if (!s_xchange_tx_put(l_tx, a_price->net_buy)) { return false; } return true; @@ -399,8 +409,9 @@ char *s_xchange_order_create(dap_chain_net_srv_xchange_price_t *a_price, dap_cha dap_chain_node_addr_t *l_node_addr = dap_chain_net_get_cur_addr(a_price->net_sell); dap_chain_net_srv_price_unit_uid_t l_unit = { .uint32 = SERV_UNIT_UNDEFINED}; dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_XCHANGE_ID }; + uint64_t l_datoshi_buy = ceill(a_price->datoshi_sell / a_price->rate); char *l_order_hash_str = dap_chain_net_srv_order_create(a_price->net_buy, SERV_DIR_SELL, l_uid, *l_node_addr, - l_tx_hash, a_price->datoshi_buy, l_unit, a_price->token_buy, 0, + l_tx_hash, l_datoshi_buy, l_unit, a_price->token_buy, 0, (uint8_t *)&l_ext, l_ext_size, NULL, 0); return l_order_hash_str; } @@ -408,14 +419,49 @@ char *s_xchange_order_create(dap_chain_net_srv_xchange_price_t *a_price, dap_cha dap_chain_net_srv_xchange_price_t *s_xchange_price_from_order(dap_chain_net_t *a_net, dap_chain_net_srv_order_t *a_order) { dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t); - l_price->net_sell = a_net; - strcpy(l_price->token_sell, a_order->price_ticker); - l_price->datoshi_sell = a_order->price; dap_srv_xchange_order_ext_t *l_ext = (dap_srv_xchange_order_ext_t *)a_order->ext; dap_chain_net_id_t l_net_buy_id = { .uint64 = dap_lendian_get64((uint8_t *)&l_ext->net_sell_id) }; - l_price->net_buy = dap_chain_net_by_id(l_net_buy_id); - l_price->datoshi_buy = dap_lendian_get64((uint8_t *)&l_ext->datoshi_sell); - strcpy(l_price->token_buy, l_ext->token_sell); + l_price->net_sell = dap_chain_net_by_id(l_net_buy_id); + l_price->datoshi_sell = dap_lendian_get64((uint8_t *)&l_ext->datoshi_sell); + strcpy(l_price->token_sell, l_ext->token_sell); + l_price->net_buy = a_net; + strcpy(l_price->token_buy, a_order->price_ticker); + l_price->rate = (long double)l_price->datoshi_sell / a_order->price; + return l_price; +} + +static bool s_xchange_db_add(dap_chain_net_srv_xchange_price_t *a_price) +{ + size_t l_size = sizeof(dap_chain_net_srv_xchange_db_item_t) + strlen(a_price->wallet_str) + 1; + dap_chain_net_srv_xchange_db_item_t *l_item = DAP_NEW_Z_SIZE(dap_chain_net_srv_xchange_db_item_t, l_size); + strcpy(l_item->token_sell, a_price->token_sell); + strcpy(l_item->token_buy, a_price->token_buy); + l_item->net_sell_id = a_price->net_sell->pub.id.uint64; + l_item->net_buy_id = a_price->net_buy->pub.id.uint64; + l_item->datoshi_sell = a_price->datoshi_sell; + l_item->rate = a_price->rate; + memcpy(&l_item->tx_hash, &a_price->tx_hash, sizeof(dap_chain_hash_fast_t)); + memcpy(&l_item->order_hash, &a_price->order_hash, sizeof(dap_chain_hash_fast_t)); + strcpy(l_item->wallet_str, a_price->wallet_str); + return dap_chain_global_db_gr_set(dap_strdup(a_price->key_ptr), (uint8_t *)l_item, l_size, GROUP_LOCAL_XCHANGE); +} + +static dap_chain_net_srv_xchange_price_t *s_xchange_db_load(char *a_key, uint8_t *a_item) +{ + dap_chain_net_srv_xchange_db_item_t *l_item = (dap_chain_net_srv_xchange_db_item_t *)a_item; + dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t); + strcpy(l_price->key_ptr, a_key); + strcpy(l_price->token_sell, l_item->token_sell); + strcpy(l_price->token_buy, l_item->token_buy); + dap_chain_net_id_t l_id = { .uint64 = l_item->net_sell_id}; + l_price->net_sell = dap_chain_net_by_id(l_id); + l_id.uint64 = l_item->net_buy_id; + l_price->net_buy = dap_chain_net_by_id(l_id); + l_price->datoshi_sell = l_item->datoshi_sell; + l_price->rate = l_item->rate; + memcpy(&l_price->tx_hash, &l_item->tx_hash, sizeof(dap_chain_hash_fast_t)); + memcpy(&l_price->order_hash, &l_item->order_hash, sizeof(dap_chain_hash_fast_t)); + strcpy(l_price->wallet_str, l_item->wallet_str); return l_price; } @@ -545,24 +591,30 @@ static int s_cli_srv_xchange_price(int a_argc, char **a_argv, int a_arg_index, c l_price->net_buy = l_net_buy; l_price->key_ptr = l_strkey; l_price->datoshi_sell = l_datoshi_sell; - l_price->datoshi_buy = l_datoshi_sell / l_rate; + l_price->rate = l_rate; // Create conditional transaction dap_chain_datum_tx_t *l_tx = s_xchange_tx_create_request(l_price, l_wallet); dap_chain_wallet_close(l_wallet); if (!l_tx) { dap_chain_node_cli_set_reply_text(a_str_reply, "Can't compose the conditional transaction"); DAP_DELETE(l_price); - break; + return -14; } // Create the order & put it to GDB char *l_order_hash_str = s_xchange_order_create(l_price, l_tx); if (l_order_hash_str) { dap_chain_str_to_hash_fast(l_order_hash_str, &l_price->order_hash); if(!s_xchange_tx_put(l_tx, l_net_buy)) { - dap_chain_node_cli_set_reply_text(a_str_reply, "Can't put transaction to mempool/chains"); + dap_chain_node_cli_set_reply_text(a_str_reply, "Can't put transaction to mempool"); + dap_chain_net_srv_order_delete_by_hash_str(l_net_buy, l_order_hash_str); + DAP_DELETE(l_order_hash_str); + return -15; + } + if (!s_xchange_db_add(l_price)) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Can't save price in database"); dap_chain_net_srv_order_delete_by_hash_str(l_net_buy, l_order_hash_str); DAP_DELETE(l_order_hash_str); - break; + return -16; } dap_chain_node_cli_set_reply_text(a_str_reply, "Successfully created order %s", l_order_hash_str); DAP_DELETE(l_order_hash_str); @@ -578,121 +630,127 @@ static int s_cli_srv_xchange_price(int a_argc, char **a_argv, int a_arg_index, c case CMD_UPDATE: { dap_chain_net_srv_xchange_price_t *l_price = NULL; HASH_FIND_STR(s_srv_xchange->pricelist, l_strkey, l_price); - if (l_price) { - if (l_cmd_num == CMD_REMOVE) { - dap_string_t *l_str_reply = dap_string_new(""); - HASH_DEL(s_srv_xchange->pricelist, l_price); - dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_price->wallet_str, dap_chain_wallet_get_path(g_config)); - bool l_ret = s_xchage_tx_invalidate(l_price, l_wallet); - dap_chain_wallet_close(l_wallet); - if (!l_ret) { - char *l_tx_hash_str = dap_chain_hash_fast_to_str_new(&l_price->tx_hash); - dap_string_append_printf(l_str_reply, "Can't invalidate transaction %s\n", l_tx_hash_str); - DAP_DELETE(l_tx_hash_str); - } - char *l_order_hash_str = dap_chain_hash_fast_to_str_new(&l_price->order_hash); - if (dap_chain_net_srv_order_delete_by_hash_str(l_price->net_buy, l_order_hash_str)) { - dap_string_append_printf(l_str_reply, "Can't remove order %s\n", l_order_hash_str); - } - DAP_DELETE(l_order_hash_str); - DAP_DELETE(l_price->key_ptr); - DAP_DELETE(l_price->wallet_str); - DAP_DELETE(l_price); - if (!l_str_reply->len) { - dap_string_append(l_str_reply, "Price successfully removed"); - } - *a_str_reply = dap_string_free(l_str_reply, false); - } else { // CMD_UPDATE - const char *l_val_sell_str = NULL, *l_val_rate_str = NULL, *l_wallet_str = NULL, *l_new_wallet_str = NULL; - uint64_t l_datoshi_sell = 0; - long double l_rate = 0; - dap_chain_wallet_t *l_wallet = NULL; - dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-coins", &l_val_sell_str); - if (l_val_sell_str) { - l_datoshi_sell = strtoull(l_val_sell_str, NULL, 10); - if (!l_datoshi_sell) { - dap_chain_node_cli_set_reply_text(a_str_reply, "Format -coins <unsigned long long>"); - return -9; - } - } - dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-rate", &l_val_rate_str); - if (l_val_rate_str) { - l_rate = strtold(l_val_rate_str, NULL); - if (!l_rate) { - dap_chain_node_cli_set_reply_text(a_str_reply, "Format -rate <long double> = sell / buy"); - return -9; - } - } - dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-wallet", &l_new_wallet_str); - l_wallet_str = l_new_wallet_str ? l_new_wallet_str : l_price->wallet_str; - l_wallet = dap_chain_wallet_open(l_wallet_str, dap_chain_wallet_get_path(g_config)); - if (!l_wallet) { - dap_chain_node_cli_set_reply_text(a_str_reply, "Specified wallet not found"); - return -11; - } - if (!l_val_sell_str && !l_val_rate_str && !l_wallet_str) { - dap_chain_node_cli_set_reply_text(a_str_reply, "At least one of updating parameters is mandatory"); - return -13; - } - if (l_datoshi_sell && dap_chain_wallet_get_balance(l_wallet, l_net_sell->pub.id, l_token_sell_str) < l_datoshi_sell) { - dap_chain_node_cli_set_reply_text(a_str_reply, "Not enough cash in specified wallet"); - dap_chain_wallet_close(l_wallet); - return -12; - } - if (l_val_sell_str) { - l_price->datoshi_sell = l_datoshi_sell; + if (!l_price) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Price with provided pair of token ticker + net name is not exist"); + return -1; + } + if (l_cmd_num == CMD_REMOVE) { + dap_string_t *l_str_reply = dap_string_new(""); + HASH_DEL(s_srv_xchange->pricelist, l_price); + dap_chain_global_db_gr_del(l_price->key_ptr, GROUP_LOCAL_XCHANGE); + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_price->wallet_str, dap_chain_wallet_get_path(g_config)); + bool l_ret = s_xchage_tx_invalidate(l_price, l_wallet); + dap_chain_wallet_close(l_wallet); + if (!l_ret) { + char *l_tx_hash_str = dap_chain_hash_fast_to_str_new(&l_price->tx_hash); + dap_string_append_printf(l_str_reply, "Can't invalidate transaction %s\n", l_tx_hash_str); + DAP_DELETE(l_tx_hash_str); + } + char *l_order_hash_str = dap_chain_hash_fast_to_str_new(&l_price->order_hash); + if (dap_chain_net_srv_order_delete_by_hash_str(l_price->net_buy, l_order_hash_str)) { + dap_string_append_printf(l_str_reply, "Can't remove order %s\n", l_order_hash_str); + } + DAP_DELETE(l_order_hash_str); + DAP_DELETE(l_price->wallet_str); + DAP_DELETE(l_price); + if (!l_str_reply->len) { + dap_string_append(l_str_reply, "Price successfully removed"); + } + *a_str_reply = dap_string_free(l_str_reply, false); + } else { // CMD_UPDATE + const char *l_val_sell_str = NULL, *l_val_rate_str = NULL, *l_wallet_str = NULL, *l_new_wallet_str = NULL; + uint64_t l_datoshi_sell = 0; + long double l_rate = 0; + dap_chain_wallet_t *l_wallet = NULL; + dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-coins", &l_val_sell_str); + if (l_val_sell_str) { + l_datoshi_sell = strtoull(l_val_sell_str, NULL, 10); + if (!l_datoshi_sell) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Format -coins <unsigned long long>"); + return -9; } - if (l_val_rate_str) { - l_price->datoshi_buy = l_price->datoshi_sell / l_rate; + } + dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-rate", &l_val_rate_str); + if (l_val_rate_str) { + l_rate = strtold(l_val_rate_str, NULL); + if (!l_rate) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Format -rate <long double> = sell / buy"); + return -9; } - // Update the transaction - dap_chain_datum_tx_t *l_tx = s_xchange_tx_create_request(l_price, l_wallet); - if (l_new_wallet_str) { + } + dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-wallet", &l_new_wallet_str); + l_wallet_str = l_new_wallet_str ? l_new_wallet_str : l_price->wallet_str; + l_wallet = dap_chain_wallet_open(l_wallet_str, dap_chain_wallet_get_path(g_config)); + if (!l_wallet) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Specified wallet not found"); + return -11; + } + if (!l_val_sell_str && !l_val_rate_str && !l_wallet_str) { + dap_chain_node_cli_set_reply_text(a_str_reply, "At least one of updating parameters is mandatory"); + return -13; + } + if (l_datoshi_sell && dap_chain_wallet_get_balance(l_wallet, l_net_sell->pub.id, l_token_sell_str) < l_datoshi_sell) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Not enough cash in specified wallet"); dap_chain_wallet_close(l_wallet); - l_wallet = dap_chain_wallet_open(l_price->wallet_str, dap_chain_wallet_get_path(g_config)); - DAP_DELETE(l_price->wallet_str); - l_price->wallet_str = dap_strdup(l_new_wallet_str); - } - if (!l_tx) { - dap_chain_node_cli_set_reply_text(a_str_reply, "Can't compose the conditional transaction"); - break; - } - HASH_DEL(s_srv_xchange->pricelist, l_price); - bool l_ret = s_xchage_tx_invalidate(l_price, l_wallet); // may be changed to old price later + return -12; + } + if (l_val_sell_str) { + l_price->datoshi_sell = l_datoshi_sell; + } + if (l_val_rate_str) { + l_price->rate = l_rate; + } + // Update the transaction + dap_chain_datum_tx_t *l_tx = s_xchange_tx_create_request(l_price, l_wallet); + if (l_new_wallet_str) { dap_chain_wallet_close(l_wallet); - if (!l_ret) { - char *l_tx_hash_str = dap_chain_hash_fast_to_str_new(&l_price->tx_hash); - dap_chain_node_cli_set_reply_text(a_str_reply, "Can't invalidate transaction %s\n", l_tx_hash_str); - DAP_DELETE(l_tx_hash_str); - break; + l_wallet = dap_chain_wallet_open(l_price->wallet_str, dap_chain_wallet_get_path(g_config)); + DAP_DELETE(l_price->wallet_str); + l_price->wallet_str = dap_strdup(l_new_wallet_str); + } + if (!l_tx) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Can't compose the conditional transaction"); + return -14; + } + HASH_DEL(s_srv_xchange->pricelist, l_price); + dap_chain_global_db_gr_del(l_price->key_ptr, GROUP_LOCAL_XCHANGE); + bool l_ret = s_xchage_tx_invalidate(l_price, l_wallet); // may be changed to old price later + dap_chain_wallet_close(l_wallet); + if (!l_ret) { + char *l_tx_hash_str = dap_chain_hash_fast_to_str_new(&l_price->tx_hash); + dap_chain_node_cli_set_reply_text(a_str_reply, "Can't invalidate transaction %s\n", l_tx_hash_str); + DAP_DELETE(l_tx_hash_str); + return -17; + } + // Update the order + char *l_order_hash_str = dap_chain_hash_fast_to_str_new(&l_price->order_hash); + dap_chain_net_srv_order_delete_by_hash_str(l_price->net_buy, l_order_hash_str); + DAP_DELETE(l_order_hash_str); + l_order_hash_str = s_xchange_order_create(l_price, l_tx); + if (l_order_hash_str) { + dap_chain_str_to_hash_fast(l_order_hash_str, &l_price->order_hash); + if(!s_xchange_tx_put(l_tx, l_net_buy)) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Can't put transaction to mempool"); + dap_chain_net_srv_order_delete_by_hash_str(l_net_buy, l_order_hash_str); + DAP_DELETE(l_order_hash_str); + return -15; } - // Update the order - char *l_order_hash_str = dap_chain_hash_fast_to_str_new(&l_price->order_hash); - dap_chain_net_srv_order_delete_by_hash_str(l_price->net_buy, l_order_hash_str); - DAP_DELETE(l_order_hash_str); - l_order_hash_str = s_xchange_order_create(l_price, l_tx); - if (l_order_hash_str) { - dap_chain_str_to_hash_fast(l_order_hash_str, &l_price->order_hash); - if(!s_xchange_tx_put(l_tx, l_net_buy)) { - dap_chain_node_cli_set_reply_text(a_str_reply, "Can't put transaction to mempool/chains"); - dap_chain_net_srv_order_delete_by_hash_str(l_net_buy, l_order_hash_str); - break; - } else { - dap_chain_node_cli_set_reply_text(a_str_reply, "Successfully created order %s", l_order_hash_str); - } + if (!s_xchange_db_add(l_price)) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Can't save price in database"); + dap_chain_net_srv_order_delete_by_hash_str(l_net_buy, l_order_hash_str); DAP_DELETE(l_order_hash_str); - } else { - dap_chain_node_cli_set_reply_text(a_str_reply, "Can't compose the order"); - DAP_DELETE(l_price->key_ptr); - DAP_DELETE(l_price); - break; + return -16; } - // Update the pricelist - HASH_ADD_KEYPTR(hh, s_srv_xchange->pricelist, l_price->key_ptr, strlen(l_price->key_ptr), l_price); + dap_chain_node_cli_set_reply_text(a_str_reply, "Successfully created order %s", l_order_hash_str); + DAP_DELETE(l_order_hash_str); + } else { + dap_chain_node_cli_set_reply_text(a_str_reply, "Can't compose the order"); + DAP_DELETE(l_price->key_ptr); + DAP_DELETE(l_price); + return -18; } - } else { - dap_chain_node_cli_set_reply_text(a_str_reply, "Price with provided pair of token ticker + net name is not exist"); - return -1; + // Update the pricelist + HASH_ADD_KEYPTR(hh, s_srv_xchange->pricelist, l_price->key_ptr, strlen(l_price->key_ptr), l_price); } } break; case CMD_LIST: { @@ -700,10 +758,9 @@ static int s_cli_srv_xchange_price(int a_argc, char **a_argv, int a_arg_index, c dap_string_t *l_reply_str = dap_string_new(""); HASH_ITER(hh, s_srv_xchange->pricelist, l_price, l_tmp) { char *l_order_hash_str = dap_chain_hash_fast_to_str_new(&l_price->order_hash); - long double l_rate = (long double)l_price->datoshi_sell / l_price->datoshi_buy; dap_string_append_printf(l_reply_str, "%s\t%s\t%s\t%s\t%s\t%lu\t%ld\t%s\n", l_order_hash_str, l_price->token_sell, l_price->net_sell->pub.name, l_price->token_buy, l_price->net_buy->pub.name, - l_price->datoshi_sell, l_rate, l_price->wallet_str); + l_price->datoshi_sell, l_price->rate, l_price->wallet_str); DAP_DELETE(l_order_hash_str); } if (!l_reply_str->len) { @@ -769,10 +826,9 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, void *a_arg_func, char * continue; // TODO add filters to list (tokens, network, etc.) l_price = s_xchange_price_from_order(l_net, l_order); - long double l_rate = (long double)l_price->datoshi_buy / l_price->datoshi_sell; - dap_string_append_printf(l_reply_str, "%s\t%s\t%s\t%s\t%s\t%lu\t%ld\n", l_orders[i].key, l_price->token_buy, - l_price->net_buy->pub.name, l_price->token_sell, l_price->net_sell->pub.name, - l_price->datoshi_buy, l_rate); + dap_string_append_printf(l_reply_str, "%s\t%s\t%s\t%s\t%s\t%lu\t%ld\n", l_orders[i].key, l_price->token_sell, + l_price->net_sell->pub.name, l_price->token_buy, l_price->net_buy->pub.name, + l_price->datoshi_sell, l_price->rate); DAP_DELETE(l_price); } dap_chain_global_db_objs_delete(l_orders, l_orders_count); @@ -783,7 +839,7 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, void *a_arg_func, char * *a_str_reply = dap_string_free(l_reply_str, false); } break; case CMD_PURCHASE: { - const char *l_net_str = NULL, *l_wallet_str = NULL, *l_order_hash_str = NULL, *l_val_buy_str = NULL; + const char *l_net_str = NULL, *l_wallet_str = NULL, *l_order_hash_str = NULL, *l_val_sell_str = NULL; l_arg_index++; dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); if (!l_net_str) { @@ -810,28 +866,24 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, void *a_arg_func, char * dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'purchase' required parameter -order"); return -12; } - dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-coins", &l_val_buy_str); - if (!l_val_buy_str) { + dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-coins", &l_val_sell_str); + if (!l_val_sell_str) { dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'price create' required parameter -coins"); return -8; } - uint64_t l_datoshi_buy = strtoull(l_val_buy_str, NULL, 10); - if (!l_datoshi_buy) { + uint64_t l_datoshi_sell = strtoull(l_val_sell_str, NULL, 10); + if (!l_datoshi_sell) { dap_chain_node_cli_set_reply_text(a_str_reply, "Format -coins <unsigned long long>"); return -9; } dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_find_by_hash_str(l_net, l_order_hash_str); if (l_order) { dap_chain_net_srv_xchange_price_t *l_price = s_xchange_price_from_order(l_net, l_order); - if (l_price->datoshi_buy != l_datoshi_buy) { - long double l_rate = (long double)l_price->datoshi_buy / l_price->datoshi_sell; - l_price->datoshi_buy = l_datoshi_buy; - l_price->datoshi_sell = ceill(l_datoshi_buy * l_rate); - } + l_price->datoshi_sell = l_datoshi_sell; // Create conditional transaction dap_chain_datum_tx_t *l_tx = s_xchange_tx_create_exchange(l_price, &l_order->tx_cond_hash, l_wallet); if (l_tx && s_xchange_tx_put(l_tx, l_net)) { - // TODO send request to seller to delete order & price + // TODO send request to seller to update / delete order & price dap_chain_net_srv_order_delete_by_hash_str(l_price->net_buy, l_order_hash_str); } DAP_DELETE(l_price); diff --git a/modules/service/xchange/include/dap_chain_net_srv_xchange.h b/modules/service/xchange/include/dap_chain_net_srv_xchange.h index 0ab6610b71c5dd5e0491d7e8021ec87045090b7d..f59791fea9c51326e5026278a59de60c0de0078a 100644 --- a/modules/service/xchange/include/dap_chain_net_srv_xchange.h +++ b/modules/service/xchange/include/dap_chain_net_srv_xchange.h @@ -28,6 +28,7 @@ #include "dap_chain_net_srv_order.h" #define DAP_CHAIN_NET_SRV_XCHANGE_ID 0x2 +#define GROUP_LOCAL_XCHANGE "local.xchange" typedef struct dap_chain_net_srv_xchange_price { char *wallet_str; @@ -36,13 +37,26 @@ typedef struct dap_chain_net_srv_xchange_price { uint64_t datoshi_sell; dap_chain_net_t *net_buy; char token_buy[DAP_CHAIN_TICKER_SIZE_MAX]; - uint64_t datoshi_buy; + long double rate; dap_chain_hash_fast_t tx_hash; dap_chain_hash_fast_t order_hash; char *key_ptr; UT_hash_handle hh; } dap_chain_net_srv_xchange_price_t; +typedef struct dap_chain_net_srv_xchange_db_item { + char token_sell[DAP_CHAIN_TICKER_SIZE_MAX]; + char token_buy[DAP_CHAIN_TICKER_SIZE_MAX]; + uint8_t padding[4]; + uint64_t net_sell_id; + uint64_t net_buy_id; + uint64_t datoshi_sell; + long double rate; + dap_chain_hash_fast_t tx_hash; + dap_chain_hash_fast_t order_hash; + char wallet_str[]; +} DAP_ALIGN_PACKED dap_chain_net_srv_xchange_db_item_t; + typedef struct dap_srv_xchange_order_ext { uint64_t net_sell_id; uint64_t datoshi_sell;