From d7122e0d7cab93b4ff20d9bbb8a99b5e47741d87 Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Fri, 22 May 2020 14:45:38 +0300
Subject: [PATCH] [*] eXchange with local node debugged

---
 modules/chain/dap_chain_ledger.c              | 38 +++++----
 modules/common/dap_chain_datum_tx_items.c     | 12 ++-
 .../common/include/dap_chain_datum_tx_items.h |  2 +-
 modules/mempool/dap_chain_mempool.c           | 12 ++-
 modules/net/dap_chain_node.c                  |  4 +-
 modules/net/srv/dap_chain_net_srv_order.c     |  1 +
 .../xchange/dap_chain_net_srv_xchange.c       | 83 ++++++++++++-------
 7 files changed, 96 insertions(+), 56 deletions(-)

diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c
index 4bce2c45a6..ae594fca2e 100644
--- a/modules/chain/dap_chain_ledger.c
+++ b/modules/chain/dap_chain_ledger.c
@@ -254,7 +254,7 @@ int dap_chain_ledger_token_ticker_check(dap_ledger_t * a_ledger, const char *a_t
     }
     dap_chain_ledger_token_item_t *l_token_item;
     HASH_FIND_STR(PVT(a_ledger)->tokens, a_token_ticker, l_token_item);
-    return (int)l_token_item;
+    return (size_t)l_token_item;
 }
 
 /**
@@ -642,7 +642,7 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
      &&
      3. hash(tx1) == tx2.dap_chain_datump_tx_in.tx_prev_hash
      &&
-     4. tx1.dap_chain_datum_tx_out.addr.data.key == tx2.dap_chain_datum_tx_sig.pkey for unconditioned output
+     4. tx1.dap_chain_datum_tx_out.addr.data.key == tx2.dap_chain_datum_tx_sig.pkey for unconditional output
      &&
      5. tx1.dap_chain_datum_tx_out.condition == verify_svc_type(tx2) for conditional ouput
      &&
@@ -680,9 +680,11 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
     // find all conditional 'in' items in current transaction
     dap_list_t *l_list_tmp = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t *)a_tx, TX_ITEM_TYPE_IN_COND,
                                                           &l_prev_tx_count);
-    // add conditional input to common list
-    dap_list_append(l_list_in, l_list_tmp->data);
-    dap_list_free(l_list_tmp);
+    if (l_list_tmp) {
+        // add conditional input to common list
+        dap_list_append(l_list_in, l_list_tmp->data);
+        dap_list_free(l_list_tmp);
+    }
     l_list_tmp = l_list_in;
     int l_list_tmp_num = 0;
 
@@ -975,7 +977,7 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
     //log_it ( L_INFO, "dap_chain_ledger_tx_add() check passed for tx %s",l_tx_hash_str);
 
 
-    char * l_token_ticker = NULL;
+    char * l_token_ticker = NULL, *l_token_ticker_cond = NULL;
     dap_chain_ledger_tx_item_t *l_item_tmp = NULL;
     pthread_rwlock_wrlock(&l_ledger_priv->ledger_rwlock);
     HASH_FIND(hh, l_ledger_priv->ledger_items, l_tx_hash, sizeof(dap_chain_hash_fast_t), l_item_tmp); // tx_hash already in the hash?
@@ -1025,6 +1027,8 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
             /// Mark 'out' item in cache because it used
             l_tx_prev_hash = &(l_prev_item_out->tx_hash_spent_fast[l_tx_in->header.tx_out_prev_idx]);
         } else {
+            if (l_token_ticker_cond == NULL)
+                l_token_ticker_cond = dap_strdup(l_prev_item_out->token_tiker);
             // all balance deducts performed with previous conditional transaction
             dap_chain_tx_in_cond_t *l_tx_in_cond = bound_item->tx_cur_in_cond;
             /// Mark 'out' item in cache because it used
@@ -1069,7 +1073,12 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
     }
     if (l_list_bound_items)
         dap_list_free_full(l_list_bound_items, free);
-
+    if (l_token_ticker_cond) {
+        if (l_token_ticker) {
+            DAP_DELETE(l_token_ticker);
+        }
+        l_token_ticker = dap_strdup(l_token_ticker_cond);
+    }
     // Try to find token ticker if wasn't
     if ( l_token_ticker == NULL){
         int l_base_tx_count = 0;
@@ -1105,7 +1114,7 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
                 wallet_balance = DAP_NEW_Z(dap_ledger_wallet_balance_t);
                 wallet_balance->key = l_wallet_balance_key;
                 wallet_balance->balance += l_out_item->header.value;
-                dap_stpcpy(wallet_balance->token_ticker, l_token_ticker);
+                dap_stpcpy(wallet_balance->token_ticker, l_token_ticker_ex);
                 //log_it(L_DEBUG,"!!! Create new balance item: %s %s", l_addr_str, l_token_ticker);
                 HASH_ADD_KEYPTR(hh, PVT(a_ledger)->balance_accounts, wallet_balance->key,
                                 strlen(l_wallet_balance_key), wallet_balance);
@@ -1179,6 +1188,9 @@ FIN:
     if (l_token_ticker) {
         DAP_DELETE(l_token_ticker);
     }
+    if (l_token_ticker_cond) {
+        DAP_DELETE(l_token_ticker_cond);
+    }
     DAP_DELETE(l_tx_hash);
     return ret;
 }
@@ -1445,9 +1457,8 @@ static dap_chain_ledger_tx_item_t* tx_item_find_by_addr(dap_ledger_t *a_ledger,
             continue;
         }
         // Get 'out' items from transaction
-        dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT, NULL);
-        dap_list_t *l_list_tmp = l_list_out_items;
-        while(l_list_tmp) {
+        dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT, NULL);   
+        for(dap_list_t *l_list_tmp = l_list_out_items; l_list_tmp; l_list_tmp = dap_list_next(l_list_tmp)) {
             const dap_chain_tx_out_t *l_tx_out = (const dap_chain_tx_out_t*) l_list_tmp->data;
             assert(l_tx_out);
             // If a_token is setup we check if its not our token - miss it
@@ -1459,10 +1470,9 @@ static dap_chain_ledger_tx_item_t* tx_item_find_by_addr(dap_ledger_t *a_ledger,
                 memcpy(a_tx_first_hash, l_tx_hash, sizeof(dap_chain_hash_fast_t));
                 is_tx_found = true;
                 break;
-            }
-            l_list_tmp = dap_list_next(l_list_tmp);
+            }     
         }
-        dap_list_free(l_list_tmp);
+        dap_list_free(l_list_out_items);
         // already found transaction
         if(is_tx_found)
             break;
diff --git a/modules/common/dap_chain_datum_tx_items.c b/modules/common/dap_chain_datum_tx_items.c
index 570a2824a0..7d5b9c3b39 100644
--- a/modules/common/dap_chain_datum_tx_items.c
+++ b/modules/common/dap_chain_datum_tx_items.c
@@ -60,7 +60,7 @@ static size_t dap_chain_tx_out_get_size(const dap_chain_tx_out_t *a_item)
 
 static size_t dap_chain_tx_out_cond_get_size(const dap_chain_tx_out_cond_t *a_item)
 {
-    return sizeof (a_item->header) + sizeof (a_item->subtype) + a_item->params_size;
+    return sizeof(dap_chain_tx_out_cond_t) + a_item->params_size;
 }
 
 static size_t dap_chain_tx_pkey_get_size(const dap_chain_tx_pkey_t *a_item)
@@ -223,8 +223,7 @@ dap_chain_tx_out_cond_t* dap_chain_datum_tx_item_out_cond_create_srv_pay(dap_enc
     uint8_t *l_pub_key = dap_enc_key_serealize_pub_key(a_key, &l_pub_key_size);
 
 
-    dap_chain_tx_out_cond_t *l_item = DAP_NEW_Z_SIZE(dap_chain_tx_out_cond_t,
-            sizeof(l_item->header) + sizeof (l_item->subtype) + a_params_size);
+    dap_chain_tx_out_cond_t *l_item = DAP_NEW_Z_SIZE(dap_chain_tx_out_cond_t, sizeof(dap_chain_tx_out_cond_t) + a_params_size);
     l_item->header.item_type = TX_ITEM_TYPE_OUT_COND;
     l_item->header.value = a_value;
     l_item->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY; // By default creatre cond for service pay. Rework with smth more flexible
@@ -240,20 +239,19 @@ dap_chain_tx_out_cond_t* dap_chain_datum_tx_item_out_cond_create_srv_pay(dap_enc
 
 dap_chain_tx_out_cond_t* dap_chain_datum_tx_item_out_cond_create_srv_xchange(dap_chain_net_srv_uid_t a_srv_uid, dap_chain_net_id_t a_net_id,
                                                                              const char *a_token, uint64_t a_value,
-                                                                             const void *a_params, size_t a_params_size)
+                                                                             const void *a_params, uint32_t a_params_size)
 {
     if (!a_token) {
         return NULL;
     }
-    dap_chain_tx_out_cond_t *l_item = DAP_NEW_Z_SIZE(dap_chain_tx_out_cond_t,
-            sizeof(l_item->header) + sizeof (l_item->subtype) + a_params_size);
+    dap_chain_tx_out_cond_t *l_item = DAP_NEW_Z_SIZE(dap_chain_tx_out_cond_t, sizeof(dap_chain_tx_out_cond_t) + a_params_size);
     l_item->header.item_type = TX_ITEM_TYPE_OUT_COND;
     l_item->header.value = a_value;
     l_item->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE;
     l_item->subtype.srv_xchange.srv_uid = a_srv_uid;
     l_item->subtype.srv_xchange.net_id = a_net_id;
     strcpy(l_item->subtype.srv_xchange.token, a_token);
-    l_item->params_size = (uint32_t)a_params_size;
+    l_item->params_size = a_params_size;
     if (a_params_size) {
         memcpy(l_item->params, a_params, a_params_size);
     }
diff --git a/modules/common/include/dap_chain_datum_tx_items.h b/modules/common/include/dap_chain_datum_tx_items.h
index 1d7acfd76f..572117a504 100644
--- a/modules/common/include/dap_chain_datum_tx_items.h
+++ b/modules/common/include/dap_chain_datum_tx_items.h
@@ -94,7 +94,7 @@ dap_chain_tx_out_cond_t* dap_chain_datum_tx_item_out_cond_create_srv_pay(dap_enc
  */
 dap_chain_tx_out_cond_t* dap_chain_datum_tx_item_out_cond_create_srv_xchange(dap_chain_net_srv_uid_t a_srv_uid,
                                                                              dap_chain_net_id_t a_net_id, const char *a_token, uint64_t a_value,
-                                                                             const void *a_params, size_t a_params_size);
+                                                                             const void *a_params, uint32_t a_params_size);
 /**
  * Create item dap_chain_tx_sig_t
  *
diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c
index b691a6c781..7e02de5440 100644
--- a/modules/mempool/dap_chain_mempool.c
+++ b/modules/mempool/dap_chain_mempool.c
@@ -343,9 +343,10 @@ int dap_chain_mempool_tx_create_massive( dap_chain_t * a_chain, dap_enc_key_t *a
 }
 
 dap_chain_hash_fast_t* dap_chain_mempool_tx_create_cond_input(dap_chain_net_t * a_net,dap_chain_hash_fast_t *a_tx_prev_hash,
-
-        const dap_chain_addr_t* a_addr_to, dap_enc_key_t *l_key_tx_sign, dap_chain_datum_tx_receipt_t * l_receipt, size_t l_receipt_size)
+                                                              const dap_chain_addr_t* a_addr_to, dap_enc_key_t *l_key_tx_sign,
+                                                              dap_chain_datum_tx_receipt_t * l_receipt, size_t l_receipt_size)
 {
+    UNUSED(l_receipt_size);
     dap_ledger_t * l_ledger = a_net ? dap_chain_ledger_by_net_name( a_net->pub.name ) : NULL;
     if ( ! a_net || ! l_ledger || ! a_addr_to )
         return NULL;
@@ -360,9 +361,12 @@ dap_chain_hash_fast_t* dap_chain_mempool_tx_create_cond_input(dap_chain_net_t *
     uint16_t pos=0;
     dap_chain_datum_tx_add_item(&l_tx, (byte_t*) l_receipt);
     pos++;
+
     // add 'in_cond' items
-    // expected only one 'cond out' item, so it idx always should be zero
-    if (dap_chain_datum_tx_add_in_cond_item(&l_tx,a_tx_prev_hash,0,pos-1) != 0 ){
+    int l_prev_cond_idx = 0;
+    dap_chain_datum_tx_t *l_cond_tx = dap_chain_ledger_tx_find_by_hash(l_ledger, a_tx_prev_hash);
+    dap_chain_datum_tx_item_get(l_cond_tx, &l_prev_cond_idx, TX_ITEM_TYPE_OUT_COND, NULL);
+    if (dap_chain_datum_tx_add_in_cond_item(&l_tx, a_tx_prev_hash, l_prev_cond_idx, pos-1) != 0 ){
         dap_chain_datum_tx_delete(l_tx);
         log_it( L_ERROR, "Cant add tx cond input");
         return NULL;
diff --git a/modules/net/dap_chain_node.c b/modules/net/dap_chain_node.c
index 1c639f5094..38cf9d1933 100644
--- a/modules/net/dap_chain_node.c
+++ b/modules/net/dap_chain_node.c
@@ -251,7 +251,9 @@ int dap_chain_node_mempool_process(dap_chain_t *a_chain)
     if (l_objs_size) {
         for (size_t i = 0; i < l_objs_size; i++) {
             dap_chain_datum_t *l_datum = (dap_chain_datum_t *)l_objs[i].value;
-            if (l_datum->header.type_id != DAP_CHAIN_DATUM_TX) {
+            if (l_datum->header.type_id != DAP_CHAIN_DATUM_TX &&
+                l_datum->header.type_id != DAP_CHAIN_DATUM_TOKEN_EMISSION &&
+                l_datum->header.type_id != DAP_CHAIN_DATUM_TOKEN_DECL) {
                 continue;
             }
             if (a_chain->callback_datums_pool_proc(a_chain, &l_datum, 1) != 1) {
diff --git a/modules/net/srv/dap_chain_net_srv_order.c b/modules/net/srv/dap_chain_net_srv_order.c
index c88b08b506..4066893697 100644
--- a/modules/net/srv/dap_chain_net_srv_order.c
+++ b/modules/net/srv/dap_chain_net_srv_order.c
@@ -227,6 +227,7 @@ char * dap_chain_net_srv_order_create(
         if (a_ext_size) {
             l_order = (dap_chain_net_srv_order_t *)DAP_NEW_Z_SIZE(void, sizeof(dap_chain_net_srv_order_t) + a_ext_size);
             memcpy(l_order->ext, a_ext, a_ext_size);
+            l_order->ext_size = a_ext_size;
         }
         else {
             l_order = DAP_NEW_Z(dap_chain_net_srv_order_t);
diff --git a/modules/service/xchange/dap_chain_net_srv_xchange.c b/modules/service/xchange/dap_chain_net_srv_xchange.c
index 7d4668c517..3bf646077c 100644
--- a/modules/service/xchange/dap_chain_net_srv_xchange.c
+++ b/modules/service/xchange/dap_chain_net_srv_xchange.c
@@ -22,6 +22,7 @@
     along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include "dap_string.h"
 #include "dap_chain_common.h"
 #include "dap_chain_node_cli.h"
 #include "dap_chain_mempool.h"
@@ -91,7 +92,7 @@ static bool dap_chain_net_srv_xchange_verificator(dap_chain_tx_out_cond_t *a_con
 {
     /* Check only one of following conditions for verification success
      * 1. addr(a_cond.params).data.key == a_tx.sign.pkey -- for condition owner
-     * 2. a_cond.srv_xchange.value & token == a_tx.out.value & token -- for exchange
+     * 2. a_cond.srv_xchange.(value && token && addr) == a_tx.out.(value && token && addr) -- for exchange
      */
     dap_chain_addr_t *l_seller_addr = (dap_chain_addr_t *)a_cond->params;
     dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_SIG, NULL);
@@ -103,20 +104,21 @@ static bool dap_chain_net_srv_xchange_verificator(dap_chain_tx_out_cond_t *a_con
         return true;
     } else {
         dap_list_t *l_list_out = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_OUT, NULL);
-        dap_list_t *l_list_tmp = l_list_out;
+
         uint64_t l_out_val = 0;
-        while (l_list_tmp) {
+        for (dap_list_t *l_list_tmp = l_list_out;l_list_tmp;  l_list_tmp = l_list_tmp->next) {
             dap_chain_tx_out_t *l_tx_out = (dap_chain_tx_out_t *)l_list_tmp->data;
-            if (!strcmp(l_tx_out->token, a_cond->subtype.srv_xchange.token)) {
-                l_out_val += l_tx_out->header.value;
+            if (memcmp(&l_tx_out->addr, &a_cond->params, sizeof(dap_chain_addr_t)) ||
+                    strcmp(l_tx_out->token, a_cond->subtype.srv_xchange.token)) {
+                continue;
             }
-            l_list_tmp = l_list_tmp->next;
+            l_out_val += l_tx_out->header.value;
         }
-        if (l_out_val == a_cond->subtype.srv_xchange.value) {
-            return true;
+        if (l_out_val != a_cond->subtype.srv_xchange.value) {
+            return false;
         }
     }
-    return false;
+    return true;
 }
 
 static dap_chain_datum_tx_t *s_xchange_create_tx_request(dap_chain_net_srv_xchange_price_t *a_price)
@@ -143,7 +145,7 @@ static dap_chain_datum_tx_t *s_xchange_create_tx_request(dap_chain_net_srv_xchan
     // 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_sell) {
         dap_chain_datum_tx_delete(l_tx);
         log_it(L_ERROR, "Can't compose the transaction input");
         return NULL;
@@ -152,9 +154,9 @@ static dap_chain_datum_tx_t *s_xchange_create_tx_request(dap_chain_net_srv_xchan
     // add 'out_cond' & 'out' items
     {
         dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_XCHANGE_ID };
-        dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_xchange(l_uid, a_price->net_buy->pub.id,
-                                                                                                a_price->token_buy, a_price->datoshi_buy,
-                                                                                                (void *)l_seller_addr, sizeof (dap_chain_addr_t));
+        dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_xchange(l_uid, a_price->net_sell->pub.id,
+                                                                                                a_price->token_sell, a_price->datoshi_sell,
+                                                                                                (void *)l_seller_addr, sizeof(dap_chain_addr_t));
         if (!l_tx_out) {
             dap_chain_datum_tx_delete(l_tx);
             log_it(L_ERROR, "Can't compose the transaction conditional output");
@@ -205,23 +207,35 @@ static dap_chain_datum_tx_t *s_xchange_create_tx_exchange(dap_chain_net_srv_xcha
         return NULL;
     }
 
+    // create and add reciept
+    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);
+    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,
+                                                                                 l_ext, l_ext_size);
+    dap_chain_datum_tx_add_item(&l_tx, (byte_t *)l_receipt);
+    DAP_DELETE(l_receipt);
     // 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);
-    uint32_t l_next_in_idx = dap_list_length(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_sell) {
         dap_chain_datum_tx_delete(l_tx);
         log_it(L_ERROR, "Can't compose the transaction input");
         return NULL;
     }
     // add 'in' item to buy from conditional transaction
-    dap_chain_datum_tx_add_in_item(&l_tx, a_tx_cond_hash, l_next_in_idx);
+    int l_prev_cond_idx = 0;
+    dap_chain_datum_tx_t *l_cond_tx = dap_chain_ledger_tx_find_by_hash(l_ledger, a_tx_cond_hash);
+    dap_chain_tx_out_cond_t *l_tx_out_cond  = (dap_chain_tx_out_cond_t *)dap_chain_datum_tx_item_get(
+                                               l_cond_tx, &l_prev_cond_idx, TX_ITEM_TYPE_OUT_COND, NULL);
+    dap_chain_datum_tx_add_in_cond_item(&l_tx, a_tx_cond_hash, l_prev_cond_idx, 0);
 
     // add 'out' items
     {
         // transfer selling coins
-        dap_chain_datum_tx_t* l_cond_tx = dap_chain_ledger_tx_find_by_hash(l_ledger, a_tx_cond_hash);
-        dap_chain_tx_out_cond_t *l_tx_out_cond  = (dap_chain_tx_out_cond_t *)dap_chain_datum_tx_item_get(l_cond_tx, NULL, TX_ITEM_TYPE_OUT_COND, NULL);
         const dap_chain_addr_t *l_buyer_addr = (dap_chain_addr_t *)l_tx_out_cond->params;
         uint64_t l_buying_value = l_tx_out_cond->header.value;
         dap_chain_tx_out_t *l_tx_out = dap_chain_datum_tx_item_out_create(l_buyer_addr, a_price->datoshi_sell, a_price->token_sell);
@@ -279,7 +293,10 @@ static bool s_xchange_tx_put(dap_chain_datum_tx_t *a_tx, dap_chain_net_t *a_net)
     size_t l_tx_size = dap_chain_datum_tx_get_size(a_tx);
     dap_chain_datum_t *l_datum = dap_chain_datum_create(DAP_CHAIN_DATUM_TX, a_tx, l_tx_size);
     DAP_DELETE(a_tx);
-    dap_chain_t *l_chain = dap_chain_net_get_chain_by_chain_type(a_net, DAP_CHAIN_DATUM_TX);
+    dap_chain_t *l_chain = dap_chain_net_get_chain_by_chain_type(a_net, CHAIN_TYPE_TX);
+    if (!l_chain) {
+        return false;
+    }
     dap_chain_node_role_t l_role = dap_chain_net_get_role(a_net);
     size_t l_datums_number;
     switch (l_role.enums) {
@@ -391,6 +408,7 @@ static int s_cli_srv_xchange_price(int a_argc, char **a_argv, int a_arg_index, c
                 dap_chain_node_cli_set_reply_text(a_str_reply, "Format -datoshi_sell <unsigned long long>");
                 return -9;
             }
+            dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-datoshi_buy", &l_val_buy_str);
             if (!l_val_buy_str) {
                 dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'price create' required parameter -datoshi_buy");
                 return -8;
@@ -455,6 +473,7 @@ static int s_cli_srv_xchange_price(int a_argc, char **a_argv, int a_arg_index, c
                     DAP_DELETE(l_order_hash_str);
                     break;
                 }
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Successfully created order %s", l_order_hash_str);
                 DAP_DELETE(l_order_hash_str);
                 // Add active price to pricelist
                 HASH_ADD_KEYPTR(hh, s_srv_xchange->pricelist, l_price->key_ptr, strlen(l_price->key_ptr), l_price);
@@ -471,13 +490,12 @@ static int s_cli_srv_xchange_price(int a_argc, char **a_argv, int a_arg_index, c
                 if (l_cmd_num == CMD_REMOVE) {
                     HASH_DEL(s_srv_xchange->pricelist, l_price);
                     DAP_DELETE(l_price->key_ptr);
-                    DAP_DELETE(l_price);
+
                     dap_chain_wallet_close(l_price->wallet);
 
                     //TODO invalidate transaction
 
                     //TODO delete order (l_price->order);
-
                     DAP_DELETE(l_price);
                 } else {    // CMD_UPDATE
                     const char *l_val_sell_str = NULL, *l_val_buy_str = NULL, *l_wallet_str = NULL;
@@ -540,17 +558,19 @@ static int s_cli_srv_xchange_price(int a_argc, char **a_argv, int a_arg_index, c
         } break;
         case CMD_LIST: {
             dap_chain_net_srv_xchange_price_t *l_price = NULL, *l_tmp;
+            dap_string_t *l_reply_str = dap_string_new("");
             HASH_ITER(hh, s_srv_xchange->pricelist, l_price, l_tmp) {
-                *a_str_reply = dap_strdup_printf("%s\t%s\t%s\t%s\t%lu\t%lu\t%s\n", 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->datoshi_buy, l_price->wallet->name);
-            }
-            if (!l_price) {
-                 dap_chain_node_cli_set_reply_text(a_str_reply, "Pricelist is empty");
+                char *l_order_hash_str = dap_chain_hash_fast_to_str_new(&l_price->order_hash);
+                dap_string_append_printf(l_reply_str, "%s\t%s\t%s\t%s\t%lu\t%lu\t%s\t%s\n", 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->datoshi_buy, l_price->wallet->name, l_order_hash_str);
+                DAP_DELETE(l_order_hash_str);
             }
+            dap_chain_node_cli_set_reply_text(a_str_reply, *l_reply_str->str ? "Pricelist is empty" : l_reply_str->str);
+            dap_string_free(l_reply_str, true);
         } break;
         default: {
-            dap_chain_node_cli_set_reply_text(a_str_reply, "Subcommand %s not recognized", a_argv[a_arg_index + 1]);
+            dap_chain_node_cli_set_reply_text(a_str_reply, "Subcommand %s not recognized", a_argv[a_arg_index]);
             return -4;
         }
     }
@@ -579,7 +599,7 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, void *a_arg_func, char *
     }
     switch (l_cmd_num) {
         case CMD_PRICE:
-            return s_cli_srv_xchange_price(a_argc, a_argv, l_arg_index, a_str_reply);
+            return s_cli_srv_xchange_price(a_argc, a_argv, l_arg_index + 1, a_str_reply);
         case CMD_PURCHASE: {
             const char *l_net_str = NULL, *l_wallet_str = 0;
             dap_chain_node_cli_find_option_val(a_argv, ++l_arg_index + 1, a_argc, "-net", &l_net_str);
@@ -612,12 +632,17 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, void *a_arg_func, char *
                 l_price->net_sell = l_net;
                 strcpy(l_price->token_sell, (char *)&l_order->ext[sizeof(uint64_t)]);
                 l_price->datoshi_sell = dap_lendian_get64(l_order->ext);
+                l_price->wallet = l_wallet;
                 // Create conditional transaction
                 dap_chain_datum_tx_t *l_tx = s_xchange_create_tx_exchange(l_price, &l_order->tx_cond_hash);
                 if (l_tx) {
                     s_xchange_tx_put(l_tx, l_net);
                 }
                 DAP_DELETE(l_price);
+                // TODO delete the order
+                DAP_DELETE(l_order);
+                dap_chain_node_cli_set_reply_text(a_str_reply, l_tx ? "Exchange transaction has done" :
+                                                                      "Exchange transaction error");
             }
         } break;
         case CMD_ENABLE: {
-- 
GitLab