From a96de6d5c0203db9c1053b25a6eecbb5574381b8 Mon Sep 17 00:00:00 2001
From: "daniil.frolov" <daniil.frolov@demlabs.net>
Date: Wed, 20 Dec 2023 11:45:10 +0000
Subject: [PATCH] Hotfix 9430

---
 dap-sdk                                       |    2 +-
 modules/net/dap_chain_ledger.c                |    7 +-
 modules/net/dap_chain_net_tx.c                |  437 +++---
 modules/net/dap_chain_node_cli_cmd_tx.c       |    8 +-
 modules/net/include/dap_chain_ledger.h        |    2 +-
 modules/net/include/dap_chain_net_tx.h        |    6 +-
 .../xchange/dap_chain_net_srv_xchange.c       | 1173 ++++++++++-------
 7 files changed, 853 insertions(+), 782 deletions(-)

diff --git a/dap-sdk b/dap-sdk
index d6ff75b22f..417a8e53d8 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit d6ff75b22f70b79af1b54ee8d5da03252c8d599a
+Subproject commit 417a8e53d860dd74d80a257131402a5507be1f62
diff --git a/modules/net/dap_chain_ledger.c b/modules/net/dap_chain_ledger.c
index 366908e66e..cd2121711b 100644
--- a/modules/net/dap_chain_ledger.c
+++ b/modules/net/dap_chain_ledger.c
@@ -3193,14 +3193,13 @@ static dap_chain_datum_tx_t* s_find_datum_tx_by_hash(dap_ledger_t *a_ledger,
 
 dap_chain_datum_tx_t *dap_ledger_tx_find_by_hash(dap_ledger_t *a_ledger, dap_chain_hash_fast_t *a_tx_hash)
 {
-    return s_find_datum_tx_by_hash(a_ledger, a_tx_hash, NULL, true);
+    return s_find_datum_tx_by_hash(a_ledger, a_tx_hash, NULL, false);
 }
 
-dap_chain_datum_tx_t *dap_ledger_tx_spent_find_by_hash(dap_ledger_t *a_ledger, dap_chain_hash_fast_t *a_tx_hash)
+dap_chain_datum_tx_t *dap_ledger_tx_unspent_find_by_hash(dap_ledger_t *a_ledger, dap_chain_hash_fast_t *a_tx_hash)
 {
-    return s_find_datum_tx_by_hash(a_ledger, a_tx_hash, NULL, false);
+    return s_find_datum_tx_by_hash(a_ledger, a_tx_hash, NULL, true);
 }
-
 dap_hash_fast_t *dap_ledger_get_final_chain_tx_hash(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a_cond_type, dap_chain_hash_fast_t *a_tx_hash)
 {
     if (!a_ledger || !a_tx_hash || dap_hash_fast_is_blank(a_tx_hash))
diff --git a/modules/net/dap_chain_net_tx.c b/modules/net/dap_chain_net_tx.c
index ecc2fe7917..ab49811d50 100644
--- a/modules/net/dap_chain_net_tx.c
+++ b/modules/net/dap_chain_net_tx.c
@@ -33,6 +33,92 @@
 
 #define LOG_TAG "dap_chain_net_tx"
 
+typedef struct cond_all_with_spends_by_srv_uid_arg{
+    dap_chain_datum_tx_spends_items_t * ret;
+    dap_chain_net_srv_uid_t srv_uid;
+    dap_time_t time_from;
+    dap_time_t time_to;
+} cond_all_with_spends_by_srv_uid_arg_t;
+
+typedef struct cond_all_by_srv_uid_arg{
+    dap_list_t * ret;
+    dap_chain_net_srv_uid_t srv_uid;
+    dap_time_t time_from;
+    dap_time_t time_to;
+} cond_all_by_srv_uid_arg_t;
+
+static void s_tx_cond_all_with_spends_by_srv_uid_callback(dap_chain_net_t* a_net, dap_chain_datum_tx_t *a_tx, void *a_arg)
+{
+    cond_all_with_spends_by_srv_uid_arg_t *l_arg = (cond_all_with_spends_by_srv_uid_arg_t*)a_arg;
+    dap_chain_datum_tx_t *l_tx = a_tx;
+    dap_chain_datum_tx_spends_items_t * l_ret = l_arg->ret;
+
+    if(l_arg->time_from && l_tx->header.ts_created < l_arg->time_from)
+        return;
+
+    // Check for time to
+    if(l_arg->time_to && l_tx->header.ts_created > l_arg->time_to)
+        return;
+
+    // Go through all items
+    uint32_t l_tx_items_pos = 0, l_tx_items_size = l_tx->header.tx_items_size;
+    while (l_tx_items_pos < l_tx_items_size) {
+        uint8_t *l_item = l_tx->tx_items + l_tx_items_pos;
+        int l_item_size = dap_chain_datum_item_tx_get_size(l_item);
+        if(!l_item_size)
+            break;
+        // check type
+        dap_chain_tx_item_type_t l_item_type = dap_chain_datum_tx_item_get_type(l_item);
+        switch (l_item_type){
+        case TX_ITEM_TYPE_IN_COND:{
+            dap_chain_tx_in_cond_t * l_tx_in_cond = (dap_chain_tx_in_cond_t *) l_item;
+            dap_chain_datum_tx_spends_item_t  *l_tx_prev_out_item = NULL;
+            HASH_FIND(hh, l_ret->tx_outs, &l_tx_in_cond->header.tx_prev_hash,sizeof(l_tx_in_cond->header.tx_prev_hash), l_tx_prev_out_item);
+
+            if (l_tx_prev_out_item){ // we found previous out_cond with target srv_uid
+                dap_chain_datum_tx_spends_item_t *l_item_in = DAP_NEW_Z(dap_chain_datum_tx_spends_item_t);
+                if (!l_item_in) {
+                    log_it(L_CRITICAL, "Memory allocation error");
+                    return ;
+                }
+                size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx);
+                dap_chain_datum_tx_t * l_tx_dup = DAP_DUP_SIZE(l_tx,l_tx_size);
+                dap_hash_fast(l_tx_dup,l_tx_size, &l_item_in->tx_hash);
+
+                l_item_in->tx = l_tx_dup;
+                // Calc same offset from tx duplicate
+                l_item_in->in_cond = (dap_chain_tx_in_cond_t*) (l_tx_dup->tx_items + l_tx_items_pos);
+                HASH_ADD(hh,l_ret->tx_ins, tx_hash, sizeof(dap_chain_hash_fast_t), l_item_in);
+
+                // Link previous out with current in
+                l_tx_prev_out_item->tx_next = l_tx_dup;
+            }
+        }break;
+        case TX_ITEM_TYPE_OUT_COND:{
+            dap_chain_tx_out_cond_t * l_tx_out_cond = (dap_chain_tx_out_cond_t *)l_item;
+            if(l_tx_out_cond->header.srv_uid.uint64 == l_arg->srv_uid.uint64){
+                dap_chain_datum_tx_spends_item_t * l_item = DAP_NEW_Z(dap_chain_datum_tx_spends_item_t);
+                if (!l_item) {
+                    log_it(L_CRITICAL, "Memory allocation error");
+                    return ;
+                }
+                size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx);
+                dap_chain_datum_tx_t * l_tx_dup = DAP_DUP_SIZE(l_tx,l_tx_size);
+                dap_hash_fast(l_tx,l_tx_size, &l_item->tx_hash);
+                l_item->tx = l_tx_dup;
+                // Calc same offset from tx duplicate
+                l_item->out_cond = (dap_chain_tx_out_cond_t*) (l_tx_dup->tx_items + l_tx_items_pos);
+
+                HASH_ADD(hh,l_ret->tx_outs, tx_hash, sizeof(dap_chain_hash_fast_t), l_item);
+                break; // We're seaching only for one specified OUT_COND output per transaction
+            }
+        } break;
+        default:;
+        }
+        l_tx_items_pos += l_item_size;
+    }
+}
+
 /**
  * @brief For now it returns all COND_IN transactions
  * @param a_net
@@ -44,141 +130,25 @@ dap_chain_datum_tx_spends_items_t * dap_chain_net_get_tx_cond_all_with_spends_by
                                                       const dap_time_t a_time_from, const dap_time_t a_time_to,
                                                      const dap_chain_net_tx_search_type_t a_search_type)
 {
-    dap_ledger_t * l_ledger = a_net->pub.ledger;
-    dap_chain_datum_tx_spends_items_t * l_ret = DAP_NEW_Z(dap_chain_datum_tx_spends_items_t);
+    cond_all_with_spends_by_srv_uid_arg_t *l_ret = DAP_NEW_Z(cond_all_with_spends_by_srv_uid_arg_t);
     if (!l_ret) {
         log_it(L_CRITICAL, "Memory allocation error");
         return NULL;
     }
 
-    switch (a_search_type) {
-        case TX_SEARCH_TYPE_NET:
-        case TX_SEARCH_TYPE_CELL:
-        case TX_SEARCH_TYPE_LOCAL:
-        case TX_SEARCH_TYPE_CELL_SPENT:
-        case TX_SEARCH_TYPE_NET_UNSPENT:
-        case TX_SEARCH_TYPE_CELL_UNSPENT:
-        case TX_SEARCH_TYPE_NET_SPENT: {
-            // pass all chains
-            for ( dap_chain_t * l_chain = a_net->pub.chains; l_chain; l_chain = l_chain->next){
-                dap_chain_cell_t * l_cell, *l_cell_tmp;
-                // Go through all cells
-                HASH_ITER(hh,l_chain->cells,l_cell, l_cell_tmp){
-                    dap_chain_atom_iter_t * l_atom_iter = l_chain->callback_atom_iter_create(l_chain,l_cell->id, false  );
-                    // try to find transaction in chain ( inside shard )
-                    size_t l_atom_size = 0;
-                    dap_chain_atom_ptr_t l_atom = l_chain->callback_atom_iter_get_first(l_atom_iter, &l_atom_size);
-
-                    // Check atoms in chain
-                    while(l_atom && l_atom_size) {
-                        size_t l_datums_count = 0;
-                        dap_chain_datum_t **l_datums = l_chain->callback_atom_get_datums(l_atom, l_atom_size, &l_datums_count);
-                        // transaction
-                        dap_chain_datum_tx_t *l_tx = NULL;
-
-                        for (size_t i = 0; i < l_datums_count; i++) {
-                            // Check if its transaction
-                            if (l_datums && (l_datums[i]->header.type_id == DAP_CHAIN_DATUM_TX)) {
-                                l_tx = (dap_chain_datum_tx_t *)l_datums[i]->data;
-                            }
-
-                            // If found TX
-                            if (l_tx){
-                                // Check for time from
-                                if(a_time_from && l_tx->header.ts_created < a_time_from)
-                                        continue;
-
-                                // Check for time to
-                                if(a_time_to && l_tx->header.ts_created > a_time_to)
-                                        continue;
-
-                                if(a_search_type == TX_SEARCH_TYPE_CELL_SPENT || a_search_type == TX_SEARCH_TYPE_NET_SPENT ){
-                                    dap_hash_fast_t * l_tx_hash = dap_chain_node_datum_tx_calc_hash(l_tx);
-                                    bool l_is_spent = !!dap_ledger_tx_spent_find_by_hash(l_ledger,l_tx_hash);
-                                    DAP_DELETE(l_tx_hash);
-                                    if(!l_is_spent)
-                                        continue;
-                                }
-
-                                // Go through all items
-                                uint32_t l_tx_items_pos = 0, l_tx_items_size = l_tx->header.tx_items_size;
-                                int l_item_idx = 0;
-                                while (l_tx_items_pos < l_tx_items_size) {
-                                    uint8_t *l_item = l_tx->tx_items + l_tx_items_pos;
-                                    int l_item_size = dap_chain_datum_item_tx_get_size(l_item);
-                                    if(!l_item_size)
-                                        break;
-                                    // check type
-                                    dap_chain_tx_item_type_t l_item_type = dap_chain_datum_tx_item_get_type(l_item);
-                                    switch (l_item_type){
-                                        case TX_ITEM_TYPE_IN_COND:{
-                                            dap_chain_tx_in_cond_t * l_tx_in_cond = (dap_chain_tx_in_cond_t *) l_item;
-                                            dap_chain_datum_tx_spends_item_t  *l_tx_prev_out_item = NULL;
-                                            HASH_FIND(hh, l_ret->tx_outs, &l_tx_in_cond->header.tx_prev_hash,sizeof(l_tx_in_cond->header.tx_prev_hash), l_tx_prev_out_item);
-
-                                            if (l_tx_prev_out_item){ // we found previous out_cond with target srv_uid
-                                                dap_chain_datum_tx_spends_item_t *l_item_in = DAP_NEW_Z(dap_chain_datum_tx_spends_item_t);
-                                                if (!l_item_in) {
-                                                    log_it(L_CRITICAL, "Memory allocation error");
-                                                    DAP_DEL_Z(l_datums);
-                                                    DAP_DEL_Z(l_ret);
-                                                    return NULL;
-                                                }
-                                                size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx);
-                                                dap_chain_datum_tx_t * l_tx_dup = DAP_DUP_SIZE(l_tx,l_tx_size);
-                                                dap_hash_fast(l_tx_dup,l_tx_size, &l_item_in->tx_hash);
-
-                                                l_item_in->tx = l_tx_dup;
-                                                // Calc same offset from tx duplicate
-                                                l_item_in->in_cond = (dap_chain_tx_in_cond_t*) (l_tx_dup->tx_items + l_tx_items_pos);
-                                                HASH_ADD(hh,l_ret->tx_ins, tx_hash, sizeof(dap_chain_hash_fast_t), l_item_in);
-
-                                                // Link previous out with current in
-                                                l_tx_prev_out_item->tx_next = l_tx_dup;
-                                            }
-                                        }break;
-                                        case TX_ITEM_TYPE_OUT_COND:{
-                                            dap_chain_tx_out_cond_t * l_tx_out_cond = (dap_chain_tx_out_cond_t *)l_item;
-                                            if(l_tx_out_cond->header.srv_uid.uint64 == a_srv_uid.uint64){
-                                                dap_chain_datum_tx_spends_item_t * l_item = DAP_NEW_Z(dap_chain_datum_tx_spends_item_t);
-                                                if (!l_item) {
-                                                    log_it(L_CRITICAL, "Memory allocation error");
-                                                    DAP_DEL_Z(l_datums);
-                                                    DAP_DEL_Z(l_ret);
-                                                    return NULL;
-                                                }
-                                                size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx);
-                                                dap_chain_datum_tx_t * l_tx_dup = DAP_DUP_SIZE(l_tx,l_tx_size);
-                                                dap_hash_fast(l_tx,l_tx_size, &l_item->tx_hash);
-                                                l_item->tx = l_tx_dup;
-                                                // Calc same offset from tx duplicate
-                                                l_item->out_cond = (dap_chain_tx_out_cond_t*) (l_tx_dup->tx_items + l_tx_items_pos);
-
-                                                HASH_ADD(hh,l_ret->tx_outs, tx_hash, sizeof(dap_chain_hash_fast_t), l_item);
-                                                break; // We're seaching only for one specified OUT_COND output per transaction
-                                            }
-                                        } break;
-                                        default:;
-                                    }
-
-                                    l_tx_items_pos += l_item_size;
-                                    l_item_idx++;
-                                }
-                            }
-                        }
-                        DAP_DEL_Z(l_datums);
-                        // go to next atom
-                        l_atom = l_chain->callback_atom_iter_get_next(l_atom_iter, &l_atom_size);
-
-                    }
-                    l_chain->callback_atom_iter_delete(l_atom_iter);
-                }
-            }
-        } break;
-
+    l_ret->ret = DAP_NEW_Z(dap_chain_datum_tx_spends_items_t);
+    if (!l_ret->ret) {
+        DAP_DEL_Z(l_ret);
+        log_it(L_CRITICAL, "Memory allocation error");
+        return NULL;
     }
-    return l_ret;
+    l_ret->srv_uid = a_srv_uid;
+    l_ret->time_from = a_time_from;
+    l_ret->time_to = a_time_to;
+
+    dap_chain_net_get_tx_all(a_net, a_search_type, s_tx_cond_all_with_spends_by_srv_uid_callback, l_ret);
 
+    return l_ret->ret;
 }
 
 /**
@@ -218,13 +188,34 @@ void dap_chain_net_get_tx_all(dap_chain_net_t * a_net, dap_chain_net_tx_search_t
 {
     assert(a_tx_callback);
     switch (a_search_type) {
-        case TX_SEARCH_TYPE_NET_UNSPENT:
-        case TX_SEARCH_TYPE_CELL_UNSPENT:
+        case TX_SEARCH_TYPE_NET_UNSPENT:{
+            size_t l_tx_count = dap_ledger_count(a_net->pub.ledger);
+            dap_list_t *l_txs_list = dap_ledger_get_txs(a_net->pub.ledger, l_tx_count, 1, false, true);
+            dap_list_t *l_temp = l_txs_list;
+            while(l_temp){
+                    dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_temp->data;
+                    a_tx_callback(a_net, l_tx, a_arg);
+                    l_temp = dap_list_next(l_temp);
+            }
+            break;
+        }
         case TX_SEARCH_TYPE_NET:
-        case TX_SEARCH_TYPE_CELL:
-        case TX_SEARCH_TYPE_LOCAL:
+        case TX_SEARCH_TYPE_LOCAL:{
+            size_t l_tx_count = dap_ledger_count(a_net->pub.ledger);
+            dap_list_t *l_txs_list = dap_ledger_get_txs(a_net->pub.ledger, l_tx_count, 1, false, false);
+            dap_list_t *l_temp = l_txs_list;
+            while(l_temp){
+                dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_temp->data;
+                a_tx_callback(a_net, l_tx, a_arg);
+                l_temp = dap_list_next(l_temp);
+            }
+        break;
+        }
         case TX_SEARCH_TYPE_CELL_SPENT:
-        case TX_SEARCH_TYPE_NET_SPENT: {
+        case TX_SEARCH_TYPE_CELL_UNSPENT:
+        case TX_SEARCH_TYPE_CELL:
+            break;
+        case TX_SEARCH_TYPE_BLOCKCHAIN:{
             // pass all chains
             for ( dap_chain_t * l_chain = a_net->pub.chains; l_chain; l_chain = l_chain->next){
                 dap_chain_cell_t * l_cell, *l_cell_tmp;
@@ -251,7 +242,7 @@ void dap_chain_net_get_tx_all(dap_chain_net_t * a_net, dap_chain_net_tx_search_t
                             // If found TX
 
                             if ( l_tx ) {
-                                   a_tx_callback(a_net, l_tx, a_arg);
+                                a_tx_callback(a_net, l_tx, a_arg);
                             }
                         }
                         DAP_DEL_Z(l_datums);
@@ -262,7 +253,6 @@ void dap_chain_net_get_tx_all(dap_chain_net_t * a_net, dap_chain_net_tx_search_t
                 }
             }
         } break;
-
     }
 }
 
@@ -285,10 +275,10 @@ struct get_tx_cond_all_from_tx
  * @param a_tx
  * @param a_arg
  */
-static void s_get_tx_cond_chain_callback(dap_chain_net_t* a_net, dap_chain_datum_tx_t *a_tx, void *a_arg)
+static void s_get_tx_cond_chain_callback(dap_chain_net_t UNUSED_ARG *a_net, dap_chain_datum_tx_t *a_tx, void *a_arg)
 {
     struct get_tx_cond_all_from_tx * l_args = (struct get_tx_cond_all_from_tx* ) a_arg;
-    
+
     if( l_args->ret ){
         int l_item_idx = 0;
         byte_t *l_tx_item;
@@ -299,16 +289,16 @@ static void s_get_tx_cond_chain_callback(dap_chain_net_t* a_net, dap_chain_datum
             if(dap_hash_fast_compare(&l_in_cond->header.tx_prev_hash, &l_args->tx_last_hash) &&
                     (uint32_t)l_args->tx_last_cond_idx == l_in_cond->header.tx_out_prev_idx ){ // Found output
                 // We're the next tx in tx cond chain
+
                 l_args->ret = dap_list_append(l_args->ret, a_tx);
                 // Check cond output and update tx last hash and index
                 dap_chain_tx_out_cond_t * l_out_cond = NULL;
                 int l_out_item_idx = 0;
-                if ((l_out_cond = dap_chain_datum_tx_out_cond_get(a_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &l_out_item_idx))){
-                        if ( (l_out_cond->header.srv_uid.uint64 == l_args->srv_uid.uint64) ){ // We found output with target service uuid
-                        l_args->tx_last = a_tx; // Record current transaction as the last in tx chain
-                        memcpy(&l_args->tx_last_hash, l_tx_hash, sizeof(*l_tx_hash)); // Record current hash
-                        l_args->tx_last_cond_idx = l_out_item_idx;
-                    }
+                if ((l_out_cond = dap_chain_datum_tx_out_cond_get(a_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &l_out_item_idx)) &&
+                        l_out_cond->header.srv_uid.uint64 == l_args->srv_uid.uint64) { // We found output with target service uuid
+                    l_args->tx_last = a_tx; // Record current transaction as the last in tx chain
+                    memcpy(&l_args->tx_last_hash, l_tx_hash, sizeof(*l_tx_hash)); // Record current hash
+                    l_args->tx_last_cond_idx = l_out_item_idx;
                 }
                 break;
             }
@@ -417,7 +407,7 @@ static void s_get_tx_cond_all_for_addr_callback(dap_chain_net_t* a_net, dap_chai
         }
         l_item_idx++;
     }
-
+//dap_chain_datum_tx_out_cond_get(a_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &l_out_item_idx)
     // Get out items from transaction
     l_item_idx = 0;
     while ((l_tx_item = (dap_chain_datum_tx_item_t *) dap_chain_datum_tx_item_get(a_datum_tx, &l_item_idx, TX_ITEM_TYPE_OUT_ALL , NULL)) != NULL){
@@ -483,6 +473,31 @@ dap_list_t * dap_chain_net_get_tx_cond_all_for_addr(dap_chain_net_t * a_net, dap
     return l_ret;
 }
 
+static void s_tx_cond_all_by_srv_uid_callback(dap_chain_net_t* a_net, dap_chain_datum_tx_t *a_tx, void *a_arg){
+    cond_all_by_srv_uid_arg_t *l_ret = (cond_all_by_srv_uid_arg_t *)a_arg;
+    dap_chain_datum_tx_t *l_tx = a_tx;
+
+    // Check for time from
+    if(l_ret->time_from && l_tx->header.ts_created < l_ret->time_from)
+        return;
+
+    // Check for time to
+    if(l_ret->time_to && l_tx->header.ts_created > l_ret->time_to)
+        return;
+
+    // Check for OUT_COND items
+    dap_list_t *l_list_out_cond_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT_COND, NULL), *l_out_cond_item;
+    if(l_list_out_cond_items) {
+        DL_FOREACH(l_list_out_cond_items, l_out_cond_item) {
+                dap_chain_tx_out_cond_t *l_tx_out_cond = (dap_chain_tx_out_cond_t*)l_out_cond_item->data;
+                if (l_tx_out_cond && l_tx_out_cond->header.srv_uid.uint64 == l_ret->srv_uid.uint64) {
+                    l_ret->ret = dap_list_append(l_ret->ret, l_tx);
+                }
+        }
+        dap_list_free(l_list_out_cond_items);
+    }
+}
+
 /**
  * @brief dap_chain_net_get_tx_cond_all_by_srv_uid
  * @param a_net
@@ -494,122 +509,17 @@ dap_list_t * dap_chain_net_get_tx_cond_all_by_srv_uid(dap_chain_net_t * a_net, c
                                                       const dap_time_t a_time_from, const dap_time_t a_time_to,
                                                      const dap_chain_net_tx_search_type_t a_search_type)
 {
-    dap_ledger_t *l_ledger = a_net->pub.ledger;
-    dap_list_t *l_ret = NULL;
-
-    switch (a_search_type) {
-        case TX_SEARCH_TYPE_NET:
-        case TX_SEARCH_TYPE_CELL:
-        case TX_SEARCH_TYPE_LOCAL:
-        case TX_SEARCH_TYPE_CELL_SPENT:
-        case TX_SEARCH_TYPE_NET_SPENT: {
-            // pass all chains
-            for ( dap_chain_t * l_chain = a_net->pub.chains; l_chain; l_chain = l_chain->next){
-                dap_chain_cell_t * l_cell, *l_cell_tmp;
-                // Go through all cells
-                HASH_ITER(hh,l_chain->cells,l_cell, l_cell_tmp){
-                    dap_chain_atom_iter_t * l_atom_iter = l_chain->callback_atom_iter_create(l_chain,l_cell->id, false  );
-                    // try to find transaction in chain ( inside shard )
-                    size_t l_atom_size = 0;
-                    dap_chain_atom_ptr_t l_atom = l_chain->callback_atom_iter_get_first(l_atom_iter, &l_atom_size);
-
-                    // Check atoms in chain
-                    while(l_atom && l_atom_size) {
-                        size_t l_datums_count = 0;
-                        dap_chain_datum_t **l_datums = l_chain->callback_atom_get_datums(l_atom, l_atom_size, &l_datums_count);
-                        // transaction
-                        dap_chain_datum_tx_t *l_tx = NULL;
-
-                        for (size_t i = 0; i < l_datums_count; i++) {
-                            // Check if its transaction
-                            if (l_datums && (l_datums[i]->header.type_id == DAP_CHAIN_DATUM_TX)) {
-                                l_tx = (dap_chain_datum_tx_t *)l_datums[i]->data;
-                            }
-
-                            // If found TX
-                            if (l_tx){
-                                // Check for time from
-                                if(a_time_from && l_tx->header.ts_created < a_time_from)
-                                        continue;
-
-                                // Check for time to
-                                if(a_time_to && l_tx->header.ts_created > a_time_to)
-                                        continue;
-
-                                if(a_search_type == TX_SEARCH_TYPE_CELL_SPENT || a_search_type == TX_SEARCH_TYPE_NET_SPENT ){
-                                    dap_hash_fast_t *l_tx_hash = dap_chain_node_datum_tx_calc_hash(l_tx);
-                                    bool l_is_spent = !!dap_ledger_tx_spent_find_by_hash(l_ledger,l_tx_hash);
-                                    DAP_DELETE(l_tx_hash);
-                                    if(!l_is_spent)
-                                        continue;
-                                }
-                                // Check for OUT_COND items
-                                dap_list_t *l_list_out_cond_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT_COND, NULL), *l_out_cond_item;
-                                if(l_list_out_cond_items) {
-                                    DL_FOREACH(l_list_out_cond_items, l_out_cond_item) {
-                                        dap_chain_tx_out_cond_t *l_tx_out_cond = (dap_chain_tx_out_cond_t*)l_out_cond_item->data;
-                                        if (l_tx_out_cond && l_tx_out_cond->header.srv_uid.uint64 == a_srv_uid.uint64) {
-                                            l_ret = dap_list_append(l_ret, l_tx);
-                                        }
-                                    }
-                                    dap_list_free(l_list_out_cond_items);
-                                }
-                            }
-                        }
-                        DAP_DEL_Z(l_datums);
-                        // go to next atom
-                        l_atom = l_chain->callback_atom_iter_get_next(l_atom_iter, &l_atom_size);
-                    }
-                    l_chain->callback_atom_iter_delete(l_atom_iter);
-                }
-            }
-        } break;
+    cond_all_by_srv_uid_arg_t l_ret = {};
 
-        case TX_SEARCH_TYPE_NET_UNSPENT:
-        case TX_SEARCH_TYPE_CELL_UNSPENT:
-            l_ret = dap_ledger_tx_cache_find_out_cond_all(l_ledger, a_srv_uid);
-            break;
-    }
-    return l_ret;
-}
+    l_ret.srv_uid = a_srv_uid;
+    l_ret.time_from = a_time_from;
+    l_ret.time_to = a_time_to;
 
+    dap_chain_net_get_tx_all(a_net, a_search_type, s_tx_cond_all_by_srv_uid_callback, &l_ret);
 
-/**
- * @brief Summarize all tx inputs
- * @param a_net
- * @param a_tx
- * @return
- */
-uint256_t dap_chain_net_get_tx_total_value(dap_chain_net_t * a_net, dap_chain_datum_tx_t * a_tx)
-{
-    uint256_t l_ret = {0};
-    int l_item_idx = 0;
-    dap_chain_tx_in_t *l_in_item = NULL;
-    do {
-        l_in_item = (dap_chain_tx_in_t*) dap_chain_datum_tx_item_get(a_tx, &l_item_idx, TX_ITEM_TYPE_IN , NULL);
-        l_item_idx++;
-        if(l_in_item ) {
-            //const char *token = l_out_cond_item->subtype.srv_xchange.token;
-            dap_chain_datum_tx_t * l_tx_prev = dap_chain_net_get_tx_by_hash(a_net,&l_in_item->header.tx_prev_hash, TX_SEARCH_TYPE_NET_SPENT);
-            if(l_tx_prev){
-                int l_tx_prev_out_index = l_in_item->header.tx_out_prev_idx;
-                dap_chain_tx_out_t *  l_tx_prev_out =(dap_chain_tx_out_t *)
-                        dap_chain_datum_tx_item_get(l_tx_prev,&l_tx_prev_out_index, TX_ITEM_TYPE_OUT,NULL);
-                if ((uint32_t)l_tx_prev_out_index == l_in_item->header.tx_out_prev_idx && l_tx_prev_out) {
-                    uint256_t l_in_value = l_tx_prev_out->header.value;
-                    if(SUM_256_256(l_in_value,l_ret, &l_ret )!= 0)
-                        log_it(L_ERROR, "Overflow on inputs values calculation (summing)");
-                }else{
-                    log_it(L_WARNING, "Can't find item with index %d in prev tx hash", l_tx_prev_out_index);
-                }
-            }else
-                log_it(L_WARNING, "Can't find prev tx hash");
-        }
-    } while(l_in_item);
-    return l_ret;
+    return l_ret.ret;
 }
 
-
 /**
  * @brief dap_chain_net_tx_get_by_hash
  * @param a_net
@@ -623,10 +533,16 @@ dap_chain_datum_tx_t *dap_chain_net_get_tx_by_hash(dap_chain_net_t *a_net, dap_c
     dap_ledger_t *l_ledger = a_net->pub.ledger;
     switch (a_search_type) {
     case TX_SEARCH_TYPE_NET:
-    case TX_SEARCH_TYPE_CELL:
     case TX_SEARCH_TYPE_LOCAL:
+        return dap_ledger_tx_find_by_hash(l_ledger, a_tx_hash);
+    case TX_SEARCH_TYPE_NET_UNSPENT:
+        return dap_ledger_tx_unspent_find_by_hash(l_ledger, a_tx_hash);
+    case TX_SEARCH_TYPE_CELL:
     case TX_SEARCH_TYPE_CELL_SPENT:
-    case TX_SEARCH_TYPE_NET_SPENT:
+    case TX_SEARCH_TYPE_CELL_UNSPENT:
+        /* Will be implemented soon */
+        break;
+    case TX_SEARCH_TYPE_BLOCKCHAIN:
         // pass all chains
         for (dap_chain_t * l_chain = a_net->pub.chains; l_chain; l_chain = l_chain->next) {
             if (!l_chain->callback_datum_find_by_hash)
@@ -636,15 +552,8 @@ dap_chain_datum_tx_t *dap_chain_net_get_tx_by_hash(dap_chain_net_t *a_net, dap_c
             dap_chain_datum_t *l_datum = l_chain->callback_datum_find_by_hash(l_chain, a_tx_hash, NULL, &l_ret_code);
             if (!l_datum || l_datum->header.type_id != DAP_CHAIN_DATUM_TX)
                 continue;
-            if ((a_search_type == TX_SEARCH_TYPE_CELL_SPENT ||
-                    a_search_type == TX_SEARCH_TYPE_NET_SPENT) &&
-                    (!dap_ledger_tx_spent_find_by_hash(l_ledger, a_tx_hash)))
-                return NULL;
             return (dap_chain_datum_tx_t *)l_datum->data;
         }
-    case TX_SEARCH_TYPE_NET_UNSPENT:
-    case TX_SEARCH_TYPE_CELL_UNSPENT:
-        return dap_ledger_tx_find_by_hash(l_ledger, a_tx_hash);
     default: break;
     }
     return NULL;
diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c
index 3af9816613..4546edfea5 100644
--- a/modules/net/dap_chain_node_cli_cmd_tx.c
+++ b/modules/net/dap_chain_node_cli_cmd_tx.c
@@ -801,9 +801,11 @@ int com_ledger(int a_argc, char ** a_argv, char **a_str_reply)
                         l_str_out ? l_str_out : " empty");
                 DAP_DELETE(l_addr_str);
             } else if(l_tx_hash_str) {
-                dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(l_ledger, &l_tx_hash);
-                if (!l_tx && !l_unspent_flag) {
-                    l_tx = dap_ledger_tx_spent_find_by_hash(l_ledger, &l_tx_hash);
+                dap_chain_datum_tx_t *l_tx = NULL;
+                if (l_unspent_flag) {
+                    l_tx = dap_ledger_tx_unspent_find_by_hash(l_ledger, &l_tx_hash);
+                } else {
+                    l_tx = dap_ledger_tx_find_by_hash(l_ledger, &l_tx_hash);
                 }
                 if(l_tx) {
                     size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx);
diff --git a/modules/net/include/dap_chain_ledger.h b/modules/net/include/dap_chain_ledger.h
index 421c26e3d1..ddf614be57 100644
--- a/modules/net/include/dap_chain_ledger.h
+++ b/modules/net/include/dap_chain_ledger.h
@@ -303,7 +303,7 @@ uint256_t dap_ledger_calc_balance_full(dap_ledger_t *a_ledger, const dap_chain_a
  * return transaction, or NULL if transaction not found in the cache
  */
 dap_chain_datum_tx_t* dap_ledger_tx_find_by_hash(dap_ledger_t *a_ledger, dap_chain_hash_fast_t *a_tx_hash);
-dap_chain_datum_tx_t* dap_ledger_tx_spent_find_by_hash(dap_ledger_t *a_ledger, dap_chain_hash_fast_t *a_tx_hash);
+dap_chain_datum_tx_t* dap_ledger_tx_unspent_find_by_hash(dap_ledger_t *a_ledger, dap_chain_hash_fast_t *a_tx_hash);
 dap_hash_fast_t *dap_ledger_get_final_chain_tx_hash(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a_cond_type, dap_chain_hash_fast_t *a_tx_hash);
 
  // Get the transaction in the cache by the addr in out item
diff --git a/modules/net/include/dap_chain_net_tx.h b/modules/net/include/dap_chain_net_tx.h
index 74aa1d9aeb..f886a4b368 100644
--- a/modules/net/include/dap_chain_net_tx.h
+++ b/modules/net/include/dap_chain_net_tx.h
@@ -39,8 +39,8 @@ typedef enum dap_chain_net_tx_search_type {
     TX_SEARCH_TYPE_NET_UNSPENT,
     /// Do the request for spent txs in cell
     TX_SEARCH_TYPE_CELL_SPENT,
-    /// Do the search in whole
-    TX_SEARCH_TYPE_NET_SPENT
+    /// Do the search in blockchain
+    TX_SEARCH_TYPE_BLOCKCHAIN
 }dap_chain_net_tx_search_type_t;
 
 typedef struct dap_chain_datum_tx_spends_item{
@@ -67,8 +67,6 @@ dap_chain_datum_tx_t * dap_chain_net_get_tx_by_hash(dap_chain_net_t * a_net, dap
 
 dap_list_t * dap_chain_net_get_tx_cond_chain(dap_chain_net_t * a_net, dap_hash_fast_t * a_tx_hash, dap_chain_net_srv_uid_t a_srv_uid);
 
-uint256_t dap_chain_net_get_tx_total_value(dap_chain_net_t * a_net, dap_chain_datum_tx_t * a_tx );
-
 void dap_chain_net_get_tx_all(dap_chain_net_t * a_net, dap_chain_net_tx_search_type_t a_search_type ,dap_chain_net_tx_hash_callback_t a_tx_callback, void * a_arg);
 
 
diff --git a/modules/service/xchange/dap_chain_net_srv_xchange.c b/modules/service/xchange/dap_chain_net_srv_xchange.c
index 30344c5d64..70be7f4769 100644
--- a/modules/service/xchange/dap_chain_net_srv_xchange.c
+++ b/modules/service/xchange/dap_chain_net_srv_xchange.c
@@ -50,9 +50,18 @@
 
 #define LOG_TAG "dap_chain_net_srv_xchange"
 
-typedef struct order_find_list{
-    dap_list_t *tx_list;
-}order_find_list_t;
+typedef enum tx_opt_status {
+    TX_STATUS_ALL = 0,
+    TX_STATUS_ACTIVE,
+    TX_STATUS_INACTIVE
+} tx_opt_status_t;
+
+typedef enum xchange_tx_type {
+    TX_TYPE_UNDEFINED=0,
+    TX_TYPE_ORDER,
+    TX_TYPE_EXCHANGE,
+    TX_TYPE_INVALIDATE
+} xchange_tx_type_t;
 
 static dap_chain_net_srv_fee_item_t *s_service_fees = NULL; // Governance statements for networks
 static pthread_rwlock_t s_service_fees_rwlock = PTHREAD_RWLOCK_INITIALIZER;
@@ -69,8 +78,9 @@ static int s_callback_response_success(dap_chain_net_srv_t *a_srv, uint32_t a_us
 static int s_callback_response_error(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_remote_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_remote_t *a_srv_client, const void *a_data, size_t a_data_size);
 
+static xchange_tx_type_t s_xchange_tx_get_type (dap_chain_net_t * a_net, dap_chain_datum_tx_t * a_tx, dap_chain_tx_out_cond_t **a_out_cond_item, int *a_item_idx, dap_chain_tx_out_cond_t **a_out_prev_cond_item);
 static int s_tx_check_for_open_close(dap_chain_net_t * a_net, dap_chain_datum_tx_t * a_tx);
-static void s_string_append_tx_cond_info( dap_string_t * a_reply_str, dap_chain_net_t * a_net, dap_chain_datum_tx_t * a_tx );
+static bool s_string_append_tx_cond_info( dap_string_t * a_reply_str, dap_chain_net_t * a_net, dap_chain_datum_tx_t * a_tx, tx_opt_status_t a_filter_by_status, bool a_append_prev_hash, bool a_print_status,bool a_print_ts);
 static bool s_srv_xchange_get_fee(dap_chain_net_id_t a_net_id, uint256_t *a_fee, dap_chain_addr_t *a_addr, uint16_t *a_type);
 
 static dap_chain_net_srv_xchange_t *s_srv_xchange;
@@ -88,30 +98,30 @@ int dap_chain_net_srv_xchange_init()
     "srv_xchange order create -net <net_name> -token_sell <token_ticker> -token_buy <token_ticker> -w <wallet_name>"
                                             " -value <value> -rate <value> -fee <value>\n"
         "\tCreate a new order and tx with specified amount of datoshi to exchange with specified rate (buy / sell)\n"
-    "srv_xchange order remove -net <net_name> -order <order_hash> -w <wallet_name>\n"
+    "srv_xchange order remove -net <net_name> -order <order_hash> -w <wallet_name>\n -fee <value_datoshi>"
          "\tRemove order with specified order hash in specified net name\n"
     "srv_xchange order history -net <net_name> {-order <order_hash> | -addr <wallet_addr>}"
          "\tShows transaction history for the selected order\n"
     "srv_xchange order status -net <net_name> -order <order_hash>"
          "\tShows current amount of unselled coins from the selected order and percentage of its completion\n"
-    "srv_xchange orders -net <net_name>\n"
+    "srv_xchange orders -net <net_name> [-status {opened|closed|all}] [-token_from <token_ticker>] [-token_to <token_ticker>]\n"
          "\tGet the exchange orders list within specified net name\n"
 
     "srv_xchange purchase -order <order hash> -net <net_name> -w <wallet_name> -value <value> -fee <value>\n"
          "\tExchange tokens with specified order within specified net name. Specify how many datoshies to sell with rate specified by order\n"
 
-    "srv_xchange tx_list -net <net_name> [-time_from <yymmdd> -time_to <yymmdd>]"
-        "[[-addr <wallet_addr>  [-status closed | open] ]\n"                /* @RRL:  #6294  */
+    "srv_xchange tx_list -net <net_name> [-time_from <From time>] [-time_to <To time>]"
+        "[[-addr <wallet_addr>  [-status {inactive|active|all}] ]\n"                /* @RRL:  #6294  */
         "\tList of exchange transactions\n"
+        "\tAll times are in RFC822. For example: \"Thu, 7 Dec 2023 21:18:04\"\n"
 
     "srv_xchange token_pair -net <net_name> list all\n"
         "\tList of all token pairs\n"
-    "srv_xchange token_pair -net <net_name> price average -token_from <token_ticker> -token_to <token_ticker> [-time_from <From time>] [-time_to <To time>]  \n"
+    "srv_xchange token_pair -net <net_name> price average -token_from <token_ticker> -token_to <token_ticker>\n"
         "\tGet average rate for token pair <token from>:<token to> from <From time> to <To time> \n"
-        "\tAll times are in RFC822\n"
     "srv_xchange token_pair -net <net_name> price history -token_from <token_ticker> -token_to <token_ticker> [-time_from <From time>] [-time_to <To time>] \n"
         "\tPrint rate history for token pair <token from>:<token to> from <From time> to <To time>\n"
-        "\tAll times are in RFC822\n"
+        "\tAll times are in RFC822. For example: \"Thu, 7 Dec 2023 21:18:04\"\n"
 
     "srv_xchange enable\n"
          "\tEnable eXchange service\n"
@@ -137,6 +147,25 @@ int dap_chain_net_srv_xchange_init()
     s_srv_xchange->enabled = false;
     s_debug_more = dap_config_get_item_bool_default(g_config, "srv_xchange", "debug_more", s_debug_more);
 
+
+    /*************************/
+    /*int l_fee_type = dap_config_get_item_int64_default(g_config, "srv_xchange", "fee_type", (int)SERIVCE_FEE_NATIVE_PERCENT);
+    uint256_t l_fee_value = dap_chain_coins_to_balance(dap_config_get_item_str_default(g_config, "srv_xchange", "fee_value", "0.02"));
+    const char *l_wallet_addr = dap_config_get_item_str_default(g_config, "srv_xchange", "wallet_addr", NULL);
+    if(!l_wallet_addr){
+        log_it(L_CRITICAL, "Memory allocation error");
+        return -1;
+    }
+    const char *l_net_str = dap_config_get_item_str_default(g_config, "srv_xchange", "net", NULL);
+    ///
+    dap_chain_net_srv_fee_item_t *l_fee = NULL;
+    l_fee = DAP_NEW_Z(dap_chain_net_srv_fee_item_t);
+    l_fee->fee_type = l_fee_type;
+    l_fee->fee = l_fee_value;
+    l_fee->fee_addr = *dap_chain_addr_from_str(l_wallet_addr);
+    l_fee->net_id = dap_chain_net_by_name(l_net_str)->pub.id;
+    HASH_ADD(hh, s_service_fees, net_id, sizeof(l_fee->net_id), l_fee);*/
+
     return 0;
 }
 
@@ -416,11 +445,9 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_request(dap_chain_net_srv_xchan
     // add 'out_cond' & 'out' items
 
     {
-        uint256_t l_datoshi_buy = uint256_0;
-        MULT_256_COIN(a_price->datoshi_sell, a_price->rate, &l_datoshi_buy);
         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->pub.id, a_price->datoshi_sell,
-                                                                                                a_price->net->pub.id, a_price->token_buy, l_datoshi_buy,
+                                                                                                a_price->net->pub.id, a_price->token_buy, a_price->rate,
                                                                                                 l_seller_addr, NULL, 0);
         if (!l_tx_out) {
             dap_chain_datum_tx_delete(l_tx);
@@ -514,13 +541,13 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha
     if (l_service_fee_used) {
         switch (l_service_fee_type) {
         case SERIVCE_FEE_NATIVE_PERCENT:
-            MULT_256_COIN(l_service_fee, a_price->datoshi_buy, &l_service_fee);
+            MULT_256_COIN(l_service_fee, a_datoshi_buy, &l_service_fee);
         case SERVICE_FEE_NATIVE_FIXED:
             SUM_256_256(l_total_fee, l_service_fee, &l_total_fee);
             l_service_ticker = l_native_ticker;
             break;
         case SERVICE_FEE_OWN_PERCENT:
-            MULT_256_COIN(l_service_fee, a_price->datoshi_buy, &l_service_fee);
+            MULT_256_COIN(l_service_fee, a_datoshi_buy, &l_service_fee);
         case SERVICE_FEE_OWN_FIXED:
             SUM_256_256(l_value_need, l_service_fee, &l_value_need);
             l_service_ticker = a_price->token_buy;
@@ -635,7 +662,7 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha
         debug_if(s_debug_more, L_NOTICE, "l_datoshi_buy_again = %s", dap_chain_balance_to_coins(l_datoshi_buy_again));
         dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_xchange(
                     c_dap_chain_net_srv_xchange_uid, a_price->net->pub.id, l_value_back,
-                    a_price->net->pub.id, a_price->token_buy, l_datoshi_buy_again,
+                    a_price->net->pub.id, a_price->token_buy, a_price->rate,
                     l_seller_addr, NULL, 0);
         if (!l_tx_out) {
             dap_chain_datum_tx_delete(l_tx);
@@ -729,7 +756,7 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha
 
 
 // Put the transaction to mempool
-static bool s_xchange_tx_put(dap_chain_datum_tx_t *a_tx, dap_chain_net_t *a_net)
+static char*  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);
@@ -737,30 +764,27 @@ static bool s_xchange_tx_put(dap_chain_datum_tx_t *a_tx, dap_chain_net_t *a_net)
     dap_chain_t *l_chain = dap_chain_net_get_default_chain_by_chain_type(a_net, CHAIN_TYPE_TX);
     if (!l_chain) {
         DAP_DELETE(l_datum);
-        return false;
+        return NULL;
     }
     // Processing will be made according to autoprocess policy
     char *l_ret = dap_chain_mempool_datum_add(l_datum, l_chain, "hex");
 
     DAP_DELETE(l_datum);
 
-    if (  !l_ret )
-        return false;
-
-    DAP_DELETE(l_ret);
-
-    return true;
+    return l_ret;
 }
 
-static bool s_xchange_tx_invalidate(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet)
+static char* s_xchange_tx_invalidate(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet)
 {
+    char * l_ret = NULL;
+
     if (!a_price) {
         log_it(L_WARNING, "An a_price NULL argument was passed to the s_xchange_tx_invalidate() function.");
-        return false;
+        return l_ret;
     }
     if (!a_wallet) {
         log_it(L_WARNING, "An a_wallet NULL argument was passed to the s_xchange_tx_invalidate() function.");
-        return false;
+        return l_ret;
     }
     const char *l_native_ticker = a_price->net->pub.native_ticker;
     // create empty transaction
@@ -774,7 +798,7 @@ static bool s_xchange_tx_invalidate(dap_chain_net_srv_xchange_price_t *a_price,
     if (!l_receipt) {
         log_it(L_WARNING, "Can't create receipt");
         dap_chain_datum_tx_delete(l_tx);
-        return false;
+        return l_ret;
     }
     dap_chain_datum_tx_add_item(&l_tx, (byte_t *)l_receipt);
     DAP_DELETE(l_receipt);
@@ -784,26 +808,31 @@ static bool s_xchange_tx_invalidate(dap_chain_net_srv_xchange_price_t *a_price,
     if (!l_cond_tx) {
         log_it(L_WARNING, "Requested conditional transaction not found");
         dap_chain_datum_tx_delete(l_tx);
-        return false;
+        return l_ret;
     }
     const char *l_tx_ticker = dap_ledger_tx_get_token_ticker_by_hash(l_ledger, &a_price->tx_hash);
+    if(!l_tx_ticker){
+        log_it(L_WARNING, "Can't get ticker from tx");
+        dap_chain_datum_tx_delete(l_tx);
+        return l_ret;
+    }
     bool l_single_channel = !dap_strcmp(l_tx_ticker, l_native_ticker);
     int l_prev_cond_idx = 0;
     dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_cond_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE,
                                                                              &l_prev_cond_idx);
-    if (dap_ledger_tx_hash_is_used_out_item(l_ledger, &a_price->tx_hash, l_prev_cond_idx, NULL)) {
+    if (!l_tx_out_cond || dap_ledger_tx_hash_is_used_out_item(l_ledger, &a_price->tx_hash, l_prev_cond_idx, NULL)) {
         log_it(L_WARNING, "Requested conditional transaction is already used out");
         dap_chain_datum_tx_delete(l_tx);
-        return false;
+        return l_ret;
     }
     dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_price->tx_hash, l_prev_cond_idx, 0);
 
     // check 'out_cond' item
     dap_chain_addr_t *l_cond_addr = &l_tx_out_cond->subtype.srv_xchange.seller_addr;
-    if (dap_hash_fast_compare(&l_seller_addr->data.hash_fast, &l_cond_addr->data.hash_fast)) {
+    if (!dap_hash_fast_compare(&l_seller_addr->data.hash_fast, &l_cond_addr->data.hash_fast)) {
         log_it(L_WARNING, "Only owner can invalidate exchange transaction");
         dap_chain_datum_tx_delete(l_tx);
-        return false;
+        return l_ret;
     }
     uint256_t l_net_fee = {}, l_transfer_fee;
     dap_chain_addr_t l_addr_fee = {};
@@ -816,7 +845,7 @@ static bool s_xchange_tx_invalidate(dap_chain_net_srv_xchange_price_t *a_price,
     if(!l_list_used_out) {
         dap_chain_datum_tx_delete(l_tx);
         log_it(L_WARNING, "Nothing to pay for network fee (not enough funds)");
-        return false;
+        return l_ret;
     }
     // add 'in' items to net fee
     uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
@@ -824,55 +853,64 @@ static bool s_xchange_tx_invalidate(dap_chain_net_srv_xchange_price_t *a_price,
     if (!EQUAL_256(l_value_to_items, l_transfer_fee)) {
         dap_chain_datum_tx_delete(l_tx);
         log_it(L_ERROR, "Can't compose the transaction input");
-        return NULL;
+        return l_ret;
     }
 
     // return coins to owner
-    if (l_single_channel) {
-        if (dap_chain_datum_tx_add_out_item(&l_tx, l_seller_addr, l_tx_out_cond->header.value) == -1) {
-            dap_chain_datum_tx_delete(l_tx);
-            DAP_DELETE(l_seller_addr);
-            log_it(L_ERROR, "Cant add returning coins output");
-            return false;
-        }
-    } else {
-        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_seller_addr, l_tx_out_cond->header.value,
-                                                l_tx_ticker) == -1) {
-            dap_chain_datum_tx_delete(l_tx);
-            DAP_DELETE(l_seller_addr);
-            log_it(L_ERROR, "Cant add returning coins output");
-            return false;
-        }
+    if (dap_chain_datum_tx_add_out_item(&l_tx, l_seller_addr, l_tx_out_cond->header.value) == -1) {
+        dap_chain_datum_tx_delete(l_tx);
+        DAP_DELETE(l_seller_addr);
+        log_it(L_ERROR, "Cant add returning coins output");
+        return l_ret;
     }
 
     // Network fee
     if (l_net_fee_used) {
-        if (dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_fee, l_net_fee) != 1) {
-            dap_chain_datum_tx_delete(l_tx);
-            DAP_DELETE(l_seller_addr);
-            log_it(L_ERROR, "Cant add network fee output");
-            return NULL;
+        if (l_single_channel) {
+            if (dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_fee, l_net_fee) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                DAP_DELETE(l_seller_addr);
+                log_it(L_ERROR, "Cant add network fee output");
+                return l_ret;
+            }
+        } else {
+            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_fee, l_net_fee, l_native_ticker) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                DAP_DELETE(l_seller_addr);
+                log_it(L_ERROR, "Cant add network fee output");
+                return l_ret;
+            }
         }
     }
     // Validator's fee
     if (!IS_ZERO_256(a_price->fee)) {
-        if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) == 1) {
+        if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) == -1) {
             dap_chain_datum_tx_delete(l_tx);
             DAP_DELETE(l_seller_addr);
             log_it(L_ERROR, "Cant add validator's fee output");
-            return NULL;
+            return l_ret;
         }
     }
 
     // put the net fee cashback
     uint256_t l_fee_back = {};
     SUBTRACT_256_256(l_transfer_fee, l_total_fee, &l_fee_back);
-    if (!IS_ZERO_256(l_fee_back) &&
-            dap_chain_datum_tx_add_out_item(&l_tx, l_seller_addr, l_tx_out_cond->header.value) == -1) {
-        dap_chain_datum_tx_delete(l_tx);
-        DAP_DELETE(l_seller_addr);
-        log_it(L_ERROR, "Cant add fee cachback output");
-        return false;
+    if (!IS_ZERO_256(l_fee_back)){
+        if (l_single_channel) {
+            if ((dap_chain_datum_tx_add_out_item(&l_tx, l_seller_addr, l_fee_back) == -1)){
+                dap_chain_datum_tx_delete(l_tx);
+                DAP_DELETE(l_seller_addr);
+                log_it(L_ERROR, "Cant add fee cachback output");
+                return l_ret;
+              }
+        } else{
+            if ((dap_chain_datum_tx_add_out_ext_item(&l_tx, l_seller_addr, l_fee_back, l_native_ticker) == -1)){
+                dap_chain_datum_tx_delete(l_tx);
+                DAP_DELETE(l_seller_addr);
+                log_it(L_ERROR, "Cant add fee cachback output");
+                return l_ret;
+            }
+        }
     }
     DAP_DELETE(l_seller_addr);
 
@@ -885,10 +923,9 @@ static bool s_xchange_tx_invalidate(dap_chain_net_srv_xchange_price_t *a_price,
         return false;
     }
     dap_enc_key_delete(l_seller_key);
-    if (!s_xchange_tx_put(l_tx, a_price->net)) {
-        return false;
-    }
-    return true;
+    l_ret = s_xchange_tx_put(l_tx, a_price->net);
+
+    return l_ret;
 }
 
 /**
@@ -923,7 +960,7 @@ char *s_xchange_order_create(dap_chain_net_srv_xchange_price_t *a_price, dap_cha
  * @param a_order
  * @return
  */
-dap_chain_net_srv_xchange_price_t *s_xchange_price_from_order(dap_chain_net_t *a_net, dap_chain_datum_tx_t *a_order,  bool a_ret_is_invalid)
+dap_chain_net_srv_xchange_price_t *s_xchange_price_from_order(dap_chain_net_t *a_net, dap_chain_datum_tx_t *a_order, uint256_t *a_fee, bool a_ret_is_invalid)
 {
     if (!a_net || !a_order)
         return NULL;
@@ -932,17 +969,22 @@ dap_chain_net_srv_xchange_price_t *s_xchange_price_from_order(dap_chain_net_t *a
         log_it(L_CRITICAL, "Memory allocation error");
         return NULL;
     }
-
-     dap_chain_tx_out_cond_t *l_out_cond = dap_chain_datum_tx_out_cond_get(a_order, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE , NULL);
-
+    dap_chain_tx_out_cond_t *l_out_cond = dap_chain_datum_tx_out_cond_get(a_order, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE , NULL);
     strcpy(l_price->token_buy, l_out_cond->subtype.srv_xchange.buy_token);
-    MULT_256_256(l_out_cond->header.value, l_out_cond->subtype.srv_xchange.rate, &l_price->datoshi_buy);
+    MULT_256_COIN(l_out_cond->header.value, l_out_cond->subtype.srv_xchange.rate, &l_price->datoshi_buy);
 
     dap_hash_fast_t l_tx_hash = {};
     dap_hash_fast(a_order, dap_chain_datum_tx_get_size(a_order), &l_tx_hash);
     const char *l_token_sell = dap_ledger_tx_get_token_ticker_by_hash(a_net->pub.ledger, &l_tx_hash);
+    if (!l_token_sell){
+        log_it(L_CRITICAL, "Can't find tx token");
+        DAP_DELETE(l_price);
+        return NULL;
+    }
     strcpy(l_price->token_sell, l_token_sell);
 
+    if (a_fee)
+        l_price->fee = *a_fee;
 
     l_price->datoshi_sell = l_out_cond->header.value;
     l_price->net = a_net;
@@ -987,9 +1029,6 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
     else if(dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, dap_min(a_argc, a_arg_index + 1), "remove", NULL)) {
         l_cmd_num = CMD_REMOVE;
     }
-    else if(dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, dap_min(a_argc, a_arg_index + 1), "update", NULL)) {
-        l_cmd_num = CMD_UPDATE;
-    }
     else if(dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, dap_min(a_argc, a_arg_index + 1), "history", NULL)) {
         l_cmd_num = CMD_HISTORY;
     }
@@ -1123,43 +1162,16 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
             }
             dap_hash_fast_t l_tx_hash ={};
             dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_tx_hash);
-            if(!s_xchange_tx_put(l_tx, l_net)) {
+            char* l_ret = NULL;
+            if(!(l_ret = s_xchange_tx_put(l_tx, l_net))) {
                 dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nCan't put transaction to mempool", l_sign_str);
                 DAP_DELETE(l_price->wallet_str);
                 DAP_DELETE(l_price);
                 return -15;
             }
             // To avoid confusion, the term "order" will apply to the original conditional exchange offer transactions.
-            char *l_tx_hash_str = dap_hash_fast_str_new(&l_tx_hash, sizeof(l_tx_hash));
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nSuccessfully created order %s", l_sign_str, l_tx_hash_str);
-            DAP_DELETE(l_tx_hash_str);
-
-            // Note: Orders are transferred to conditional transactions, but it is necessary to leave
-            // the possibility of subsequent improvements with standard orders, so the next block of
-            // code will be commented out until better times.
-
-            // Create the order & put it to GDB
-//            l_price->wallet_key = dap_chain_wallet_get_key(l_wallet, 0);
-//            char *l_order_hash_str = s_xchange_order_create(l_price, l_tx);
-//            dap_chain_wallet_close(l_wallet);
-//            if (l_order_hash_str) {
-//                dap_chain_hash_fast_from_str(l_order_hash_str, &l_price->order_hash);
-//                if(!s_xchange_tx_put(l_tx, l_net)) {
-//                    dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nCan't put transaction to mempool", l_sign_str);
-//                    dap_chain_net_srv_order_delete_by_hash_str_sync(l_net, l_order_hash_str);
-//                    DAP_DELETE(l_order_hash_str);
-//                    DAP_DELETE(l_price->wallet_str);
-//                    DAP_DELETE(l_price);
-//                    return -15;
-//                }
-//                dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nSuccessfully created order %s", l_sign_str, l_order_hash_str);
-//                DAP_DELETE(l_order_hash_str);
-//            } else {
-//                dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nCan't compose the order", l_sign_str);
-//                DAP_DELETE(l_price->wallet_str);
-//                DAP_DELETE(l_price);
-//                return -18;
-//            }
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nSuccessfully created order %s", l_sign_str, l_ret);
+            DAP_DELETE(l_ret);
         } break;
 
         case CMD_HISTORY:{
@@ -1200,9 +1212,10 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
 
                 if (l_tx_list){
                     dap_list_t *l_tx_list_temp = l_tx_list;
+                    dap_string_append_printf(l_str_reply, "Wallet %s hisrory:\n\n", l_addr_hash_str);
                     while(l_tx_list_temp ){
                     dap_chain_datum_tx_t * l_tx_cur = (dap_chain_datum_tx_t*) l_tx_list_temp->data;
-                    s_string_append_tx_cond_info(l_str_reply, l_net, l_tx_cur );
+                    s_string_append_tx_cond_info(l_str_reply, l_net, l_tx_cur, TX_STATUS_ALL, true, true, false);
                     l_tx_list_temp = l_tx_list_temp->next;
                     }
                     dap_list_free(l_tx_list);
@@ -1214,12 +1227,6 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
             }
 
             if(l_order_hash_str){
-//                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_cli_server_cmd_set_reply_text(a_str_reply, "Specified order not found");
-//                    return -13;
-//                }
-
                 dap_hash_fast_t l_order_tx_hash = {};
                 dap_chain_hash_fast_from_str(l_order_hash_str, &l_order_tx_hash);
                 dap_chain_datum_tx_t * l_tx = dap_chain_net_get_tx_by_hash(l_net, &l_order_tx_hash, TX_SEARCH_TYPE_NET);
@@ -1228,23 +1235,18 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
                     char *l_tx_hash = dap_chain_hash_fast_to_str_new(&l_order_tx_hash);
                     if(l_rc == 0){
                         dap_cli_server_cmd_set_reply_text(a_str_reply, "WRONG TX %s", l_tx_hash);
-                    }else if(l_rc == 1){
-                        dap_string_t * l_str_reply = dap_string_new("");
-                        s_string_append_tx_cond_info(l_str_reply, l_net, l_tx);
-                        *a_str_reply = dap_string_free(l_str_reply, false);
-                    }else if(l_rc == 2){
+                    }else{
                         dap_string_t * l_str_reply = dap_string_new("");
+                        dap_string_append_printf(l_str_reply, "Order %s hisrory:\n\n", l_order_hash_str);
                         dap_list_t *l_tx_list = dap_chain_net_get_tx_cond_chain(l_net, &l_order_tx_hash, c_dap_chain_net_srv_xchange_uid );
                         dap_list_t *l_tx_list_temp = l_tx_list;
                         while(l_tx_list_temp ){
                             dap_chain_datum_tx_t * l_tx_cur = (dap_chain_datum_tx_t*) l_tx_list_temp->data;
-                            s_string_append_tx_cond_info(l_str_reply, l_net, l_tx_cur );
+                            s_string_append_tx_cond_info(l_str_reply, l_net, l_tx_cur, TX_STATUS_ALL, true, true, false);
                             l_tx_list_temp = l_tx_list_temp->next;
                         }
                         dap_list_free(l_tx_list);
                         *a_str_reply = dap_string_free(l_str_reply, false);
-                    }else{
-                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Internal error!");
                     }
                 }else{
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "No history");
@@ -1255,6 +1257,7 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
         case CMD_REMOVE:
         {
             const char * l_order_hash_str = NULL;
+            const char * l_fee_str = NULL;
             dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
             if (!l_net_str) {
                 dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'price %s' requires parameter -net",
@@ -1268,7 +1271,7 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
             }
             dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str);
             if (!l_wallet_str) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'price %s' requires parameter -w",
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order %s' requires parameter -w",
                                                                 l_cmd_num == CMD_REMOVE ? "remove" : "update");
                 return -10;
             }
@@ -1282,12 +1285,21 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
             }
             dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-order", &l_order_hash_str);
             if (!l_order_hash_str) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'price %s' requires parameter -order",
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order %s' requires parameter -order",
                                                                 l_cmd_num == CMD_REMOVE ? "remove" : "update");
                 return -12;
             }
-//            dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_find_by_hash_str(l_net, l_order_hash_str);
-
+            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str);
+            if (!l_fee_str) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order %s' requires parameter -fee",
+                                                  l_cmd_num == CMD_REMOVE ? "remove" : "update");
+                return -12;
+            }
+            uint256_t l_fee = dap_chain_balance_scan(l_fee_str);
+            if(IS_ZERO_256(l_fee)){
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't get fee value.");
+                return -13;
+            }
             dap_hash_fast_t l_tx_hash = {};
             dap_chain_hash_fast_from_str(l_order_hash_str, &l_tx_hash);
             dap_chain_datum_tx_t *l_cond_tx = dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_tx_hash);
@@ -1295,7 +1307,7 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
                 dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nSpecified order not found", l_sign_str);
                 return -13;
             }
-            dap_chain_net_srv_xchange_price_t *l_price = s_xchange_price_from_order(l_net, l_cond_tx, false);
+            dap_chain_net_srv_xchange_price_t *l_price = s_xchange_price_from_order(l_net, l_cond_tx, &l_fee, false);
             if (!l_price) {
                 dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nCan't create price object from order", l_sign_str);
                 return -13;
@@ -1303,7 +1315,7 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
 
             if (l_cmd_num == CMD_REMOVE) {
                 dap_string_t *l_str_reply = dap_string_new(l_sign_str);
-                bool l_ret = s_xchange_tx_invalidate(l_price, l_wallet);
+                char*  l_ret = s_xchange_tx_invalidate(l_price, l_wallet);
                 dap_chain_wallet_close(l_wallet);
                 if (!l_ret) {
                     if (!l_price) {
@@ -1313,11 +1325,10 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
                         dap_string_append_printf(l_str_reply, "Can't invalidate transaction %s\n", l_tx_hash_str);
                         DAP_DELETE(l_tx_hash_str);
                     }
-                }
+                } else
+                    dap_string_append_printf(l_str_reply, "Price successfully removed. Created inactivate tx with hash %s", l_ret);
                 DAP_DELETE(l_price);
-                if (!l_str_reply->len) {
-                    dap_string_append(l_str_reply, "Price successfully removed");
-                }
+                DAP_DEL_Z(l_ret);
                 *a_str_reply = dap_string_free(l_str_reply, false);
             }
         } break;
@@ -1339,50 +1350,105 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
                 dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order history' requires parameter -order or -addr" );
                 return -12;
             }
-            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_cli_server_cmd_set_reply_text(a_str_reply, "Specified order not found");
-                return -13;
+            dap_hash_fast_t l_order_tx_hash = {};
+            dap_chain_hash_fast_from_str(l_order_hash_str, &l_order_tx_hash);
+            dap_chain_datum_tx_t * l_tx = dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_order_tx_hash);
+            if (!l_tx){
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't find order %s", l_order_hash_str);
+                return -18;
             }
-            dap_hash_fast_t *l_final_hash = dap_ledger_get_final_chain_tx_hash(l_net->pub.ledger,
-                                                 DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &l_order->tx_cond_hash);
-            if (!l_final_hash) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order have no active tx (copmleted)");
-                DAP_DELETE(l_order);
+
+            dap_chain_tx_out_cond_t *l_out_cond = dap_chain_datum_tx_out_cond_get(l_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE , NULL);
+            if (!l_out_cond || l_out_cond->header.srv_uid.uint64 != DAP_CHAIN_NET_SRV_XCHANGE_ID){
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "It's not an order");
                 return -18;
             }
-            dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(l_net->pub.ledger, l_final_hash);
-            if (!l_tx) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Internal error");
-                DAP_DELETE(l_order);
-                return -19;
-            }
-            dap_chain_tx_out_cond_t *l_out_cond = dap_chain_datum_tx_out_cond_get(l_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE,
-                                                                                  NULL);
-            if (!l_out_cond) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order have no active conditional tx (copmleted)");
-                DAP_DELETE(l_order);
-                return -20;
+
+            // TODO add filters to list (tokens, network, etc.)
+            dap_chain_net_srv_xchange_price_t * l_price = NULL;
+            l_price = s_xchange_price_from_order(l_net, l_tx, NULL, true);
+            if( !l_price ){
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't get price from order");
+                return -18;
             }
-            uint256_t l_filled, l_filled_percent, l_rate;
-            dap_srv_xchange_order_ext_t *l_ext = (dap_srv_xchange_order_ext_t *)l_order->ext_n_sign;
-            char *l_amount_str = dap_chain_balance_to_coins(l_order->price);
-            char *l_current_str = dap_chain_balance_to_coins(l_out_cond->header.value);
-            SUBTRACT_256_256(l_order->price, l_out_cond->header.value, &l_filled);
-            DIV_256_COIN(l_filled, l_out_cond->header.value, &l_filled_percent);
-            MULT_256_256(l_filled_percent, dap_chain_uint256_from(100), &l_filled_percent);
-            char *l_filled_str = dap_chain_balance_to_coins(l_filled_percent);
-            DIV_256_COIN(l_ext->datoshi_buy, l_order->price, &l_rate);
-            char *l_rate_str = dap_chain_balance_to_coins(l_rate);
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "tokenSell: %s, tokenBuy: %s, amount: %s, current %s, filled: %s%% rate(buy/sell): %s\n",
-                                                            l_order->price_ticker, l_ext->token_buy,
-                                                            l_amount_str, l_current_str,
-                                                            l_filled_str, l_rate_str);
-            DAP_DEL_Z(l_amount_str);
-            DAP_DEL_Z(l_current_str);
-            DAP_DEL_Z(l_filled_str);
-            DAP_DEL_Z(l_rate_str);
-            DAP_DELETE(l_order);
+
+            dap_ledger_t * l_ledger = dap_ledger_by_net_name(l_net->pub.name);
+            char *l_cp_rate;
+            char* l_status_order = NULL;
+            dap_hash_fast_t * l_last_tx_hash = dap_ledger_get_final_chain_tx_hash(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &l_price->tx_hash);
+            if(!l_last_tx_hash){
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't get last tx cond hash from order");
+                return -18;
+            }
+
+            dap_chain_datum_tx_t * l_last_tx = dap_ledger_tx_find_by_hash(l_ledger, l_last_tx_hash);
+            if(!l_last_tx_hash){
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't find last tx");
+                return -18;
+            }
+
+            dap_chain_tx_out_cond_t *l_out_cond_last_tx = dap_chain_datum_tx_out_cond_get(l_last_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE , NULL);
+            if (!l_out_cond_last_tx || IS_ZERO_256(l_out_cond_last_tx->header.value)){
+                l_status_order  = "CLOSED";
+            } else {
+                l_status_order = "OPENED";
+            }
+
+            dap_hash_fast_t l_tx_hash = {};
+            dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_tx_hash);
+            char *l_tx_hash_str = dap_chain_hash_fast_to_str_new(&l_tx_hash);
+
+            char *l_amount_coins_str = l_out_cond_last_tx ? dap_chain_balance_to_coins(l_out_cond_last_tx->header.value) : NULL;
+            char *l_amount_datoshi_str = l_out_cond_last_tx ? dap_chain_balance_print(l_out_cond_last_tx->header.value) : NULL;
+            char *l_percent_completed_str = NULL;
+
+            uint256_t l_percent_completed = {};
+            if(l_out_cond_last_tx){
+
+                SUBTRACT_256_256(l_out_cond->header.value, l_out_cond_last_tx->header.value, &l_percent_completed);
+                DIV_256_COIN(l_percent_completed, l_out_cond->header.value, &l_percent_completed);
+                MULT_256_COIN(l_percent_completed, dap_chain_coins_to_balance("100.0"), &l_percent_completed);
+            } else {
+                dap_chain_tx_out_cond_t *l_out_prev_cond_item = NULL;
+                xchange_tx_type_t tx_type = s_xchange_tx_get_type(l_net, l_last_tx, NULL, NULL, &l_out_prev_cond_item);
+                if (tx_type == TX_TYPE_EXCHANGE){
+                    SUBTRACT_256_256(l_out_cond->header.value, uint256_0, &l_percent_completed);
+                    DIV_256_COIN(l_percent_completed, l_out_cond->header.value, &l_percent_completed);
+                    MULT_256_COIN(l_percent_completed, dap_chain_coins_to_balance("100.0"), &l_percent_completed);
+                } else if (tx_type == TX_TYPE_INVALIDATE){
+                    SUBTRACT_256_256(l_out_cond->header.value, l_out_prev_cond_item->header.value, &l_percent_completed);
+                    DIV_256_COIN(l_percent_completed, l_out_cond->header.value, &l_percent_completed);
+                    MULT_256_COIN(l_percent_completed, dap_chain_coins_to_balance("100.0"), &l_percent_completed);
+                }
+            }
+
+            l_percent_completed_str = dap_chain_balance_to_coins(l_percent_completed);
+            size_t l_str_len = strlen(l_percent_completed_str);
+            char*  l_dot_pos = strstr(l_percent_completed_str, ".");
+            if (l_dot_pos && (l_str_len - (l_dot_pos - l_percent_completed_str)) > 2){
+                *(char*)(l_dot_pos + 3) = '\0';
+            }
+
+            char l_tmp_buf[70] = {};
+            dap_time_t l_ts_create = (dap_time_t)l_tx->header.ts_created;
+            dap_ctime_r(&l_ts_create, l_tmp_buf);
+            l_tmp_buf[strlen(l_tmp_buf) - 1] = '\0';
+
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "orderHash: %s\n ts_created: %s (%"DAP_UINT64_FORMAT_U")\n Status: %s, amount: %s (%s) %s, filled: %s%%, rate (%s/%s): %s, net: %s\n\n", l_tx_hash_str,
+                                     l_tmp_buf, l_ts_create, l_status_order,
+                                     l_amount_coins_str ? l_amount_coins_str : "0.0",
+                                     l_amount_datoshi_str ? l_amount_datoshi_str : "0",
+                                     l_price->token_sell, l_percent_completed_str,
+                                     l_price->token_buy, l_price->token_sell,
+                                     l_cp_rate = dap_chain_balance_to_coins(l_price->rate),
+                                     l_price->net->pub.name);
+
+            DAP_DEL_Z(l_tx_hash_str);
+            DAP_DEL_Z(l_percent_completed_str);
+            DAP_DEL_Z(l_amount_coins_str);
+            DAP_DEL_Z(l_amount_datoshi_str);
+            DAP_DEL_Z(l_cp_rate);
+            DAP_DEL_Z(l_price);
         } break;
 
         default: {
@@ -1396,7 +1462,6 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
 // Filter for find tx with DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE
 static bool s_filter_tx_list(dap_chain_datum_t *a_datum, dap_chain_t *a_chain, void *a_filter_func_param)
 {
-    UNUSED(a_chain);
     // Datum type filter -> only tx
     if(!a_datum || a_datum->header.type_id != DAP_CHAIN_DATUM_TX)
         return false;
@@ -1409,24 +1474,82 @@ static bool s_filter_tx_list(dap_chain_datum_t *a_datum, dap_chain_t *a_chain, v
         l_time_begin = l_time_mass[0];
         l_time_end = l_time_mass[1];
     }
+    dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
     // Time filter
     if(l_time_begin && l_datum_tx->header.ts_created < l_time_begin)
         return false;
     if(l_time_end && l_datum_tx->header.ts_created > l_time_end)
         return false;
-    // Item filter -> if present tx_out_cond with subtype == SRV_XCHANGE
-    dap_chain_tx_out_cond_t *l_out_cond_item = NULL;
+    // Find SRV_XCHANGE out_cond item
+    int l_cond_idx = 0;
+    dap_chain_tx_out_cond_t *l_out_cond_item = dap_chain_datum_tx_out_cond_get(l_datum_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE,
+                                                                               &l_cond_idx);
+    if (l_out_cond_item)
+        return true;
+    // Find SRV_XCHANGE in_cond item
+    int l_item_idx = 0;
+    dap_chain_tx_in_cond_t * l_in_cond = (dap_chain_tx_in_cond_t *)dap_chain_datum_tx_item_get(l_datum_tx, &l_item_idx, TX_ITEM_TYPE_IN_COND , NULL);
+    int l_prev_cond_idx = 0;
+    dap_chain_datum_tx_t * l_prev_tx = l_in_cond ? dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_in_cond->header.tx_prev_hash) : NULL;
+    dap_chain_tx_out_cond_t *l_out_prev_cond_item = l_prev_tx ? dap_chain_datum_tx_out_cond_get(l_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE,
+                                                                                                &l_prev_cond_idx) : NULL;
+    if(l_out_prev_cond_item)
+        return true;
+    return false;
+}
+
+static xchange_tx_type_t s_xchange_tx_get_type (dap_chain_net_t * a_net, dap_chain_datum_tx_t * a_tx, dap_chain_tx_out_cond_t **a_out_cond_item, int *a_item_idx, dap_chain_tx_out_cond_t **a_out_prev_cond_item)
+{
+    int l_tx_type = TX_TYPE_UNDEFINED;
+
+    // Find SRV_XCHANGE out_cond item
+    int l_cond_idx = 0;
+    dap_chain_tx_out_cond_t *l_out_cond_item = dap_chain_datum_tx_out_cond_get(a_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE,
+                                                                               &l_cond_idx);
+    // Find SRV_XCHANGE in_cond item
     int l_item_idx = 0;
-    do {
-        l_out_cond_item = (dap_chain_tx_out_cond_t*) dap_chain_datum_tx_item_get(l_datum_tx, &l_item_idx, TX_ITEM_TYPE_OUT_COND, NULL);
-        l_item_idx++;
-        if(l_out_cond_item && l_out_cond_item->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE) {
-            return true;
+    byte_t *l_tx_item = dap_chain_datum_tx_item_get(a_tx, &l_item_idx, TX_ITEM_TYPE_IN_COND , NULL);
+    dap_chain_tx_in_cond_t * l_in_cond = l_tx_item ? (dap_chain_tx_in_cond_t *) l_tx_item : NULL;
+    int l_prev_cond_idx = 0;
+    dap_chain_datum_tx_t * l_prev_tx = l_in_cond ? dap_ledger_tx_find_by_hash(a_net->pub.ledger, &l_in_cond->header.tx_prev_hash) : NULL;
+    dap_chain_tx_out_cond_t *l_out_prev_cond_item = l_prev_tx ? dap_chain_datum_tx_out_cond_get(l_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE,
+                                                                                                &l_prev_cond_idx) : NULL;
+
+    if(l_out_prev_cond_item && l_out_prev_cond_item->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE)
+        return l_tx_type;
+
+    if (l_out_cond_item && !l_out_prev_cond_item)
+        l_tx_type = TX_TYPE_ORDER;
+    else if (l_out_cond_item && l_out_prev_cond_item)
+        l_tx_type = TX_TYPE_EXCHANGE;
+    else if (!l_out_cond_item && l_out_prev_cond_item){
+        dap_chain_datum_tx_t * l_prev_tx_temp = a_tx;
+        byte_t *l_tx_item_temp = NULL;
+        while((l_tx_item_temp = dap_chain_datum_tx_item_get(l_prev_tx_temp, &l_item_idx, TX_ITEM_TYPE_IN_COND , NULL)) != NULL){
+                dap_chain_tx_in_cond_t * l_in_cond_temp = (dap_chain_tx_in_cond_t *) l_tx_item_temp;
+                l_prev_tx_temp = dap_ledger_tx_find_by_hash(a_net->pub.ledger, &l_in_cond_temp->header.tx_prev_hash);
         }
 
+        dap_chain_tx_sig_t *l_tx_prev_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(l_prev_tx_temp, NULL, TX_ITEM_TYPE_SIG, NULL);
+        dap_sign_t *l_prev_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t *)l_tx_prev_sig);
+        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);
+        dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t *)l_tx_sig);
+
+        bool l_owner = false;
+        l_owner = dap_sign_match_pkey_signs(l_prev_sign,l_sign);
+        if (l_owner)
+                l_tx_type = TX_TYPE_INVALIDATE;
+        else
+                l_tx_type = TX_TYPE_EXCHANGE;
     }
-    while(l_out_cond_item);
-    return false;
+
+    if(a_out_cond_item)
+        *a_out_cond_item = l_out_cond_item;
+    if(a_out_prev_cond_item)
+        *a_out_prev_cond_item = l_out_prev_cond_item;
+    if (a_item_idx)
+        *a_item_idx = l_cond_idx;
+    return l_tx_type;
 }
 
 /**
@@ -1437,17 +1560,27 @@ static bool s_filter_tx_list(dap_chain_datum_t *a_datum, dap_chain_t *a_chain, v
  */
 static int s_tx_check_for_open_close(dap_chain_net_t * a_net, dap_chain_datum_tx_t * a_tx)
 {
-    int l_cond_idx = 0;
-    dap_hash_fast_t l_tx_hash = {0};
-    size_t l_tx_size = dap_chain_datum_tx_get_size(a_tx);
-    dap_hash_fast(a_tx, l_tx_size, &l_tx_hash);
-    dap_chain_tx_out_cond_t *l_out_cond_item = dap_chain_datum_tx_out_cond_get(a_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE,
-                                                                               &l_cond_idx);
-    if (l_out_cond_item) {
-        if(dap_ledger_tx_hash_is_used_out_item(a_net->pub.ledger, &l_tx_hash, l_cond_idx, NULL))
-            return 2; // If its SRV_XCHANGE and spent its closed
-        else
-            return 1; // If its SRV_XCHANGE and not spent its open
+    dap_ledger_t * l_ledger = dap_ledger_by_net_name(a_net->pub.name);
+
+    dap_hash_fast_t l_tx_hash = {};
+    dap_hash_fast(a_tx, dap_chain_datum_tx_get_size(a_tx), &l_tx_hash);
+    dap_hash_fast_t * l_last_tx_hash = dap_ledger_get_final_chain_tx_hash(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &l_tx_hash);
+    if(!l_last_tx_hash){
+        log_it(L_WARNING,"Can't get last tx cond hash from order");
+        return 0;
+    }
+
+    dap_chain_datum_tx_t * l_last_tx = dap_ledger_tx_find_by_hash(l_ledger, l_last_tx_hash);
+    if(!l_last_tx_hash){
+        log_it(L_WARNING,"Can't find last tx");
+        return 0;
+    }
+
+    dap_chain_tx_out_cond_t *l_out_cond_last_tx = dap_chain_datum_tx_out_cond_get(l_last_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE , NULL);
+    if (!l_out_cond_last_tx || IS_ZERO_256(l_out_cond_last_tx->header.value)){
+        return 1;
+    } else {
+        return 2;
     }
     return 0;
 }
@@ -1458,8 +1591,13 @@ static int s_tx_check_for_open_close(dap_chain_net_t * a_net, dap_chain_datum_tx
  * @param a_net
  * @param a_tx
  */
-static void s_string_append_tx_cond_info( dap_string_t * a_reply_str, dap_chain_net_t * a_net, dap_chain_datum_tx_t * a_tx )
+static bool s_string_append_tx_cond_info( dap_string_t * a_reply_str,
+                                         dap_chain_net_t * a_net,
+                                         dap_chain_datum_tx_t * a_tx,
+                                         tx_opt_status_t a_filter_by_status,
+                                         bool a_print_prev_hash, bool a_print_status, bool a_print_ts)
 {
+    enum{TX_TYPE_NONE, TX_TYPE_ORDER, TX_TYPE_EXCHANGE, TX_TYPE_INVALIDATE};
     size_t l_tx_size = dap_chain_datum_tx_get_size(a_tx);
 
     dap_hash_fast_t l_tx_hash = {0};
@@ -1467,55 +1605,125 @@ static void s_string_append_tx_cond_info( dap_string_t * a_reply_str, dap_chain_
 
     dap_hash_fast(a_tx, l_tx_size, &l_tx_hash);
     dap_chain_hash_fast_to_str(&l_tx_hash, l_tx_hash_str, DAP_CHAIN_HASH_FAST_STR_SIZE + 1);
-//                    dap_string_append_printf(l_reply_str, "Hash: %s\n", l_hash_str);
 
     // Get input token ticker
     const char * l_tx_input_ticker = dap_ledger_tx_get_token_ticker_by_hash(
                 a_net->pub.ledger, &l_tx_hash);
-
-    // Find SRV_XCHANGE out_cond item
+    if(!l_tx_input_ticker){
+        log_it(L_WARNING, "Can't get ticker from tx");
+        return false;
+    }
+    dap_chain_tx_out_cond_t *l_out_prev_cond_item = NULL;
+    dap_chain_tx_out_cond_t *l_out_cond_item = NULL;
     int l_cond_idx = 0;
-    dap_chain_tx_out_cond_t *l_out_cond_item = dap_chain_datum_tx_out_cond_get(a_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE,
-                                                                               &l_cond_idx);
-    bool l_is_cond_out = false;
-    if ( l_out_cond_item && (l_out_cond_item->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE) )
-    {
-        bool l_is_closed = dap_ledger_tx_hash_is_used_out_item(a_net->pub.ledger, &l_tx_hash, l_cond_idx, NULL);
 
-        uint256_t l_value_from = l_out_cond_item->header.value;
-        uint256_t l_rate = l_out_cond_item->subtype.srv_xchange.rate;
-        char *l_rate_str = dap_chain_balance_to_coins(l_rate);
-        char *l_value_from_str = dap_chain_balance_to_coins(l_value_from);
+    xchange_tx_type_t l_tx_type = s_xchange_tx_get_type(a_net, a_tx, &l_out_cond_item, &l_cond_idx, &l_out_prev_cond_item);
+
+    bool l_is_closed = dap_ledger_tx_hash_is_used_out_item(a_net->pub.ledger, &l_tx_hash, l_cond_idx, NULL);
+    if ((a_filter_by_status == TX_STATUS_ACTIVE && l_is_closed) || (a_filter_by_status == TX_STATUS_INACTIVE && !l_is_closed))
+        return false;
 
-        dap_string_append_printf(a_reply_str, "Hash: %s", l_tx_hash_str);
-        dap_string_append_printf(a_reply_str, "  Status: %s", l_is_closed ? "closed" : "open");
-        dap_string_append_printf(a_reply_str, "  From: %s %s", l_value_from_str, l_tx_input_ticker);
-        dap_string_append_printf(a_reply_str, "  Rate: %s Buy token: %s", l_rate_str, l_out_cond_item->subtype.srv_xchange.buy_token);
+    if(l_out_prev_cond_item && l_out_prev_cond_item->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE)
+        return false;
 
-        DAP_DELETE(l_value_from_str);
-        DAP_DELETE(l_rate_str);
-        l_is_cond_out = true;
-    }
-    else {
-        dap_string_append_printf(a_reply_str, "Hash: %s", l_tx_hash_str);
-        dap_string_append_printf(a_reply_str, "  Status: closed");
-        dap_string_append_printf(a_reply_str, "  Order is used out");
-        l_is_cond_out = true;
-    }
-    if(l_is_cond_out){
-        // Get IN_COND items from transaction
-        int l_item_idx = 0;
-        byte_t *l_tx_item;
-        while ((l_tx_item = dap_chain_datum_tx_item_get(a_tx, &l_item_idx, TX_ITEM_TYPE_IN_COND , NULL)) != NULL){
-            dap_chain_tx_in_cond_t * l_in_cond = (dap_chain_tx_in_cond_t *) l_tx_item;
+    switch(l_tx_type){
+        case TX_TYPE_ORDER:{
+            uint256_t l_value_from = l_out_cond_item->header.value;
+            uint256_t l_rate = l_out_cond_item->subtype.srv_xchange.rate;
+            char *l_rate_str = dap_chain_balance_to_coins(l_rate);
+            char *l_amount_str = dap_chain_balance_to_coins(l_value_from);
+            char *l_amount_datoshi_str = dap_chain_balance_print(l_value_from);
+
+            dap_string_append_printf(a_reply_str, "Hash: %s\n", l_tx_hash_str);
+            if(a_print_ts){
+                char l_tmp_buf[70];
+                dap_time_t l_ts_create = (dap_time_t)a_tx->header.ts_created;
+                dap_string_append_printf(a_reply_str, "  ts_created: %s", dap_ctime_r(&l_ts_create, l_tmp_buf));
+            }
+            if( a_print_status)
+                dap_string_append_printf(a_reply_str, "  Status: %s,", l_is_closed ? "inactive" : "active");
+            dap_string_append_printf(a_reply_str, "  proposed %s (%s) %s for exchange to %s,", l_amount_str, l_amount_datoshi_str, l_tx_input_ticker, l_out_cond_item->subtype.srv_xchange.buy_token);
+            dap_string_append_printf(a_reply_str, "  rate (%s/%s): %s, net: %s", l_out_cond_item->subtype.srv_xchange.buy_token, l_tx_input_ticker, l_rate_str, a_net->pub.name);
+
+            DAP_DELETE(l_amount_str);
+            DAP_DELETE(l_rate_str);
+            DAP_DELETE(l_amount_datoshi_str);
+        } break;
+        case TX_TYPE_EXCHANGE:{
+            dap_chain_tx_in_cond_t * l_in_cond = (dap_chain_tx_in_cond_t *)dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_IN_COND , NULL);
             char l_tx_prev_cond_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
             dap_hash_fast_to_str(&l_in_cond->header.tx_prev_hash,l_tx_prev_cond_hash_str, sizeof(l_tx_prev_cond_hash_str));
-            dap_string_append_printf(a_reply_str, "  Prev cond: %s", l_tx_prev_cond_hash_str);
-            l_item_idx++;
-        }
-        dap_string_append_printf(a_reply_str, "\n");
+
+            uint256_t l_rate = l_out_cond_item ? l_out_cond_item->subtype.srv_xchange.rate : l_out_prev_cond_item->subtype.srv_xchange.rate;
+            uint256_t l_value_from = {};
+            uint256_t l_value_to = {};
+            if (l_out_cond_item)
+                SUBTRACT_256_256(l_out_prev_cond_item->header.value, l_out_cond_item->header.value, &l_value_from);
+            else
+                l_value_from = l_out_prev_cond_item->header.value;
+            MULT_256_COIN(l_value_from, l_rate, &l_value_to);
+
+            char *l_value_from_str = dap_chain_balance_to_coins(l_value_from);
+            char *l_value_from_datoshi_str = dap_chain_balance_print(l_value_from);
+            char *l_value_to_str = dap_chain_balance_to_coins(l_value_to);
+            char *l_value_to_datoshi_str = dap_chain_balance_print(l_value_to);
+
+
+            char *l_rate_str = dap_chain_balance_to_coins(l_rate);
+            char *l_amount_str = l_out_cond_item ? dap_chain_balance_to_coins(l_out_cond_item->header.value) : dap_chain_balance_to_coins(uint256_0);
+            char *l_amount_datoshi_str = l_out_cond_item ? dap_chain_balance_print(l_out_cond_item->header.value) : dap_chain_balance_print(uint256_0);
+            char *l_buy_ticker = l_out_cond_item ? l_out_cond_item->subtype.srv_xchange.buy_token : l_out_prev_cond_item->subtype.srv_xchange.buy_token;
+
+            dap_string_append_printf(a_reply_str, "Hash: %s\n", l_tx_hash_str);
+            if(a_print_ts){
+                char l_tmp_buf[70];
+                dap_time_t l_ts_create = (dap_time_t)a_tx->header.ts_created;
+                dap_string_append_printf(a_reply_str, "  ts_created: %s", dap_ctime_r(&l_ts_create, l_tmp_buf));
+            }
+            if(a_print_status)
+                dap_string_append_printf(a_reply_str, "  Status: %s,", l_is_closed ? "inactive" : "active");
+            dap_string_append_printf(a_reply_str, "  changed %s (%s) %s for %s (%s) %s,", l_value_from_str, l_value_from_datoshi_str, l_tx_input_ticker, l_value_to_str, l_value_to_datoshi_str, l_buy_ticker);
+            dap_string_append_printf(a_reply_str, "  rate (%s/%s): %s,", l_buy_ticker, l_tx_input_ticker, l_rate_str);
+            dap_string_append_printf(a_reply_str, "  remain amount %s (%s) %s, net: %s", l_amount_str, l_amount_datoshi_str, l_tx_input_ticker, a_net->pub.name);
+            if(a_print_prev_hash)
+                dap_string_append_printf(a_reply_str, "\n  Prev cond: %s", l_tx_prev_cond_hash_str);
+
+            DAP_DELETE(l_value_from_str);
+            DAP_DELETE(l_value_from_datoshi_str);
+            DAP_DELETE(l_value_to_str);
+            DAP_DELETE(l_value_to_datoshi_str);
+            DAP_DELETE(l_amount_str);
+            DAP_DELETE(l_rate_str);
+            DAP_DELETE(l_amount_datoshi_str);
+        } break;
+        case TX_TYPE_INVALIDATE:{
+            dap_chain_tx_in_cond_t * l_in_cond = (dap_chain_tx_in_cond_t *)dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_IN_COND , NULL);
+            char l_tx_prev_cond_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
+            dap_hash_fast_to_str(&l_in_cond->header.tx_prev_hash,l_tx_prev_cond_hash_str, sizeof(l_tx_prev_cond_hash_str));
+
+            char *l_value_from_str = dap_chain_balance_to_coins(l_out_prev_cond_item->header.value);
+            char *l_value_from_datoshi_str = dap_chain_balance_print(l_out_prev_cond_item->header.value);
+
+            dap_string_append_printf(a_reply_str, "Hash: %s\n", l_tx_hash_str);
+            if(a_print_ts){
+                char l_tmp_buf[70];
+                dap_time_t l_ts_create = (dap_time_t)a_tx->header.ts_created;
+                dap_string_append_printf(a_reply_str, "  ts_created: %s", dap_ctime_r(&l_ts_create, l_tmp_buf));
+            }
+            if (a_print_status)
+                dap_string_append_printf(a_reply_str, "  Status: inactive,");
+            dap_string_append_printf(a_reply_str, "  returned %s(%s) %s to owner", l_value_from_str, l_value_from_datoshi_str, l_tx_input_ticker);
+            if(a_print_prev_hash)
+                dap_string_append_printf(a_reply_str, "\n  Prev cond: %s", l_tx_prev_cond_hash_str);
+
+            DAP_DELETE(l_value_from_str);
+            DAP_DELETE(l_value_from_datoshi_str);
+        } break;
+        default: return false;
     }
 
+    dap_string_append_printf(a_reply_str, "\n\n");
+    return true;
 }
 
 
@@ -1528,19 +1736,13 @@ static int s_cli_srv_xchange_tx_list_addr (
                                 char    **a_str_reply
                                           )
 {
-char l_hash_str [DAP_CHAIN_HASH_FAST_STR_SIZE + 8] = {0};
 dap_chain_hash_fast_t l_tx_first_hash = {0};
 dap_chain_datum_tx_t    *l_datum_tx;
-size_t  l_datum_tx_size, l_tx_total;
-int l_item_idx;
-bool l_rc = false;
 dap_string_t *l_reply_str;
-dap_hash_fast_t l_hash;
-dap_chain_tx_out_cond_t *l_out_cond_item;
-
+size_t l_tx_total;
 
     if ( !(l_reply_str = dap_string_new("")) )                              /* Prepare output string discriptor*/
-        return  log_it(L_CRITICAL, "Memory allocation error in %s, line %d", __PRETTY_FUNCTION__, __LINE__), -ENOMEM;
+        return  log_it(L_CRITICAL, "Memory allocation error"), -ENOMEM;
 
     memset(&l_tx_first_hash, 0, sizeof(dap_chain_hash_fast_t));             /* Initial hash == zero */
 
@@ -1550,87 +1752,25 @@ dap_chain_tx_out_cond_t *l_out_cond_item;
                 l_tx_total++)
     {
         /* Check time range (if need ) */
-        if ( !(l_datum_tx->header.ts_created > a_after) )
+        if ( a_after && !(l_datum_tx->header.ts_created > a_after) )
             continue;
 
         if ( a_before && (l_datum_tx->header.ts_created > a_before) )
             continue;
 
-
-        /* TX hash */
-        l_datum_tx_size = dap_chain_datum_tx_get_size(l_datum_tx);
-
-        if ( !dap_hash_fast(l_datum_tx, l_datum_tx_size, &l_hash) )
-        {                                                                   /* Never must be happend, but ... */
-            log_it(L_ERROR, "dap_hash_fast(..., %zu octets) return error", l_datum_tx_size);
-            dump_it("l_datum_tx", l_datum_tx, l_datum_tx_size);
-            continue;
-        }
-
-
-        /* Find SRV_XCHANGE out_cond item */
-        for (l_out_cond_item = NULL, l_item_idx = 0;
-            (l_out_cond_item = (dap_chain_tx_out_cond_t *) dap_chain_datum_tx_item_get(l_datum_tx, &l_item_idx, TX_ITEM_TYPE_OUT_COND, NULL));
-                l_item_idx++)
-        {
-            if ( l_out_cond_item->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE )
-                continue;
-
-            if (a_opt_status)                                                   /* 1 - closed, 2 - open  */
-            {
-                l_rc = dap_ledger_tx_hash_is_used_out_item(a_net->pub.ledger, &l_hash, l_item_idx, NULL);
-
-                if ( a_opt_status )
-                {
-                    if ( (a_opt_status == 1) && l_rc )              /* Select close only */
-                        {;}
-                    else if ( (a_opt_status == 2) &&  (!l_rc) )     /* Select open only */
-                        {;}
-                    else continue;
-                }
-            }
-            dap_chain_hash_fast_to_str(&l_hash, l_hash_str, DAP_CHAIN_HASH_FAST_STR_SIZE + 1);
-            dap_string_append_printf(l_reply_str, "Hash: %s\n", l_hash_str);
-
-
-            const char *l_tx_input_ticker = dap_ledger_tx_get_token_ticker_by_hash(a_net->pub.ledger, &l_hash);
-
-            uint256_t l_rate = l_out_cond_item->subtype.srv_xchange.rate;
-            uint256_t l_tx_input_values = dap_chain_net_get_tx_total_value(a_net, l_datum_tx);
-
-            char *l_tx_input_values_str = dap_chain_balance_to_coins(l_tx_input_values);
-            char *l_value_from_str = dap_chain_balance_to_coins(l_tx_input_values);
-            char *l_rate_str = dap_chain_balance_to_coins(l_rate);
-
-            dap_string_append_printf(l_reply_str, "  Status: %s,", l_rc ? "closed" : "open");
-            dap_string_append_printf(l_reply_str, "  From: %s %s,", l_tx_input_values_str, l_tx_input_ticker);
-            dap_string_append_printf(l_reply_str, "  Rate: %s Buy token: %s\n", l_rate_str, l_out_cond_item->subtype.srv_xchange.buy_token);
-
-            DAP_DELETE(l_value_from_str);
-            DAP_DELETE(l_rate_str);
-            dap_string_append(l_reply_str, "\n");
-        }
-
+        s_string_append_tx_cond_info(l_reply_str, a_net, l_datum_tx, a_opt_status, false, true, false);
     }
-
-
     *a_str_reply = dap_string_free(l_reply_str, false);                     /* Free string descriptor, but keep ASCIZ buffer itself */
     return  0;
 }
 
-
-void s_tx_is_order_check (dap_chain_net_t* a_net, dap_chain_datum_tx_t *a_tx, void *a_arg)
+void s_tx_is_order_check(dap_chain_net_t *a_net, dap_chain_datum_tx_t *a_tx, void *a_arg)
 {
     UNUSED(a_net);
-
-    order_find_list_t *l_arg = (order_find_list_t*)a_arg;
-
+    dap_list_t **l_tx_list_ptr = a_arg;
     if (dap_chain_datum_tx_out_cond_get(a_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE , NULL) &&
-        !dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_IN_COND, NULL))
-    {
-        l_arg->tx_list = dap_list_append(l_arg->tx_list, a_tx);
-    }
-
+            !dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_IN_COND, NULL))
+       *l_tx_list_ptr = dap_list_append(*l_tx_list_ptr, a_tx);
 }
 
 static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
@@ -1667,6 +1807,7 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
             return s_cli_srv_xchange_order(a_argc, a_argv, l_arg_index + 1, a_str_reply);
         case CMD_ORDERS: {
             const char *l_net_str = NULL;
+            const char *l_status_str = NULL;
             l_arg_index++;
             dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
             if (!l_net_str) {
@@ -1678,76 +1819,153 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
                 dap_cli_server_cmd_set_reply_text(a_str_reply, "Network %s not found", l_net_str);
                 return -3;
             }
+            dap_string_t *l_reply_str = dap_string_new("");
+            // Iterate blockchain, find txs with xchange cond out and without cond input
+            dap_list_t *l_tx_list = NULL;
+            dap_chain_net_get_tx_all(l_net,TX_SEARCH_TYPE_NET, s_tx_is_order_check, &l_tx_list);
 
-//            char * l_gdb_group_str = dap_chain_net_srv_order_get_gdb_group(l_net);
+            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-status", &l_status_str);
 
-//            size_t l_orders_count = 0;
-//            dap_global_db_obj_t * l_orders = dap_global_db_get_all_sync(l_gdb_group_str, &l_orders_count);
-//            dap_chain_net_srv_xchange_price_t *l_price;
-            dap_string_t *l_reply_str = dap_string_new("");
+            /* Validate input arguments ... */
+            int l_opt_status = 0;   /* 0 - all */
 
-            // Iterate blockchain, find txs with xchange cond out and without cond input
-            order_find_list_t l_arg = {};
-            dap_chain_net_get_tx_all(l_net,TX_SEARCH_TYPE_NET, s_tx_is_order_check, &l_arg);
+            if ( l_status_str )
+            {
+                /* 1 - closed, 2 - open  */
+                if ( dap_strcmp (l_status_str, "opened") == 0 )
+                    l_opt_status = 1;
+                else if ( dap_strcmp (l_status_str, "closed") == 0 )
+                    l_opt_status = 2;
+                else if ( dap_strcmp (l_status_str, "all") == 0 )
+                    l_opt_status = 0;
+                else  {
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Unrecognized '-status %s'", l_status_str);
+                    return -3;
+                }
+            }
+
+            const char * l_token_from_str = NULL;
+            const char * l_token_to_str = NULL;
+            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-token_from", &l_token_from_str);
+            if(l_token_from_str){
+                dap_chain_datum_token_t * l_token_from_datum = dap_ledger_token_ticker_check( l_net->pub.ledger, l_token_from_str);
+                if(!l_token_from_datum){
+                    dap_cli_server_cmd_set_reply_text(a_str_reply,"Can't find \"%s\" token in network \"%s\" for argument '-token_from' ", l_token_from_str, l_net->pub.name);
+                    return -6;
+                }
+            }
 
+            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-token_to", &l_token_to_str);
+            if(l_token_to_str){
+                dap_chain_datum_token_t * l_token_to_datum = dap_ledger_token_ticker_check( l_net->pub.ledger, l_token_to_str);
+                if(!l_token_to_datum){
+                    dap_cli_server_cmd_set_reply_text(a_str_reply,"Can't find \"%s\" token in network \"%s\" for argument '-token_to' ", l_token_to_str, l_net->pub.name);
+                    return -6;
+                }
+            }
 
             // Print all txs
-            dap_list_t *l_temp = l_arg.tx_list;
-            while(l_temp)
-            {
-//                dap_chain_net_srv_order_t *l_order = (dap_chain_net_srv_order_t *)l_orders[i].value;
-                dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_temp->data;
+            for (dap_list_t *it = l_tx_list; it; it = it->next) {
+                dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)it->data;
                 dap_chain_tx_out_cond_t *l_out_cond = dap_chain_datum_tx_out_cond_get(l_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE , NULL);
-                if (!l_out_cond || l_out_cond->header.srv_uid.uint64 != DAP_CHAIN_NET_SRV_XCHANGE_ID){
-                    l_temp = l_temp->next;
+                if (!l_out_cond || l_out_cond->header.srv_uid.uint64 != DAP_CHAIN_NET_SRV_XCHANGE_ID)
                     continue;
-                }
 
                 // TODO add filters to list (tokens, network, etc.)
                 dap_chain_net_srv_xchange_price_t * l_price = NULL;
-                l_price = s_xchange_price_from_order(l_net, l_tx, true);
+                l_price = s_xchange_price_from_order(l_net, l_tx, NULL, true);
                 if( !l_price ){
                     log_it(L_WARNING,"Can't create price from order");
-                    l_temp = l_temp->next;
                     continue;
                 }
+                if (l_token_from_str && strcmp(l_price->token_sell, l_token_from_str))
+                    continue
 
-                uint256_t l_datoshi_buy;
-                char *l_cp_buy_coins, *l_cp_buy_datoshi, *l_cp_sell_coins, *l_cp_sell_datoshi, *l_cp_rate;
-                char* l_status_order;
-                dap_hash_fast_t l_hash_fast_ref = {0};
-                if (dap_hash_fast_compare(&l_price->tx_hash, &l_hash_fast_ref))
-                    l_status_order  = "INVALID";
-                else
-                    l_status_order = "OPEN";
+                if (l_token_to_str && strcmp(l_price->token_buy, l_token_to_str))
+                    continue;
 
-                MULT_256_COIN(l_price->datoshi_sell, l_price->rate, &l_datoshi_buy);  /* sell/buy computation */
+                dap_ledger_t * l_ledger = dap_ledger_by_net_name(l_net->pub.name);
+                char *l_cp_rate;
+                char* l_status_order = NULL;
+                dap_hash_fast_t * l_last_tx_hash = dap_ledger_get_final_chain_tx_hash(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &l_price->tx_hash);
+                if(!l_last_tx_hash){
+                    log_it(L_WARNING,"Can't get last tx cond hash from order");
+                    continue;
+                }
+
+                dap_chain_datum_tx_t * l_last_tx = dap_ledger_tx_find_by_hash(l_ledger, l_last_tx_hash);
+                if(!l_last_tx_hash){
+                    log_it(L_WARNING,"Can't find last tx");
+                    continue;
+                }
+
+                dap_chain_tx_out_cond_t *l_out_cond_last_tx = dap_chain_datum_tx_out_cond_get(l_last_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE , NULL);
+                if (!l_out_cond_last_tx || IS_ZERO_256(l_out_cond_last_tx->header.value)){
+                    if (l_opt_status == 1)
+                        continue;
+                    l_status_order  = "CLOSED";
+                } else {
+                    if (l_opt_status == 2)
+                        continue;
+                    l_status_order = "OPENED";
+                }
 
                 dap_hash_fast_t l_tx_hash = {};
                 dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_tx_hash);
                 char *l_tx_hash_str = dap_chain_hash_fast_to_str_new(&l_tx_hash);
 
-                dap_string_append_printf(l_reply_str, "orderHash: %s (%s) tokSel: %s, net: %s, tokBuy: %s, sell: %s (%s), buy: %s (%s) buy/sell: %s\n", l_tx_hash_str,
-                                         l_status_order, l_price->token_sell, l_price->net->pub.name,
-                                         l_price->token_buy,
-                                         l_cp_sell_coins = dap_chain_balance_to_coins(l_price->datoshi_sell),
-                                         l_cp_sell_datoshi = dap_chain_balance_print(l_price->datoshi_sell),
-                                         l_cp_buy_coins = dap_chain_balance_to_coins(l_price->datoshi_buy),
-                                         l_cp_buy_datoshi = dap_chain_balance_print(l_datoshi_buy),
-                                         l_cp_rate = dap_chain_balance_to_coins(l_price->rate));
+                char *l_amount_coins_str = l_out_cond_last_tx ? dap_chain_balance_to_coins(l_out_cond_last_tx->header.value) : NULL;
+                char *l_amount_datoshi_str = l_out_cond_last_tx ? dap_chain_balance_print(l_out_cond_last_tx->header.value) : NULL;
+                char *l_percent_completed_str = NULL;
+
+                uint256_t l_percent_completed = {};
+                if(l_out_cond_last_tx){
+
+                    SUBTRACT_256_256(l_out_cond->header.value, l_out_cond_last_tx->header.value, &l_percent_completed);
+                    DIV_256_COIN(l_percent_completed, l_out_cond->header.value, &l_percent_completed);
+                    MULT_256_COIN(l_percent_completed, dap_chain_coins_to_balance("100.0"), &l_percent_completed);
+                } else {
+                    dap_chain_tx_out_cond_t *l_out_prev_cond_item = NULL;
+                    xchange_tx_type_t tx_type = s_xchange_tx_get_type(l_net, l_last_tx, NULL, NULL, &l_out_prev_cond_item);
+                    if (tx_type == TX_TYPE_EXCHANGE){
+                        SUBTRACT_256_256(l_out_cond->header.value, uint256_0, &l_percent_completed);
+                        DIV_256_COIN(l_percent_completed, l_out_cond->header.value, &l_percent_completed);
+                        MULT_256_COIN(l_percent_completed, dap_chain_coins_to_balance("100.0"), &l_percent_completed);
+                    } else if (tx_type == TX_TYPE_INVALIDATE){
+                        SUBTRACT_256_256(l_out_cond->header.value, l_out_prev_cond_item->header.value, &l_percent_completed);
+                        DIV_256_COIN(l_percent_completed, l_out_cond->header.value, &l_percent_completed);
+                        MULT_256_COIN(l_percent_completed, dap_chain_coins_to_balance("100.0"), &l_percent_completed);
+                    }
+                }
+
+                l_percent_completed_str = dap_chain_balance_to_coins(l_percent_completed);
+                size_t l_str_len = strlen(l_percent_completed_str);
+                char*  l_dot_pos = strstr(l_percent_completed_str, ".");
+                if (l_dot_pos && (l_str_len - (l_dot_pos - l_percent_completed_str)) > 2){
+                    *(char*)(l_dot_pos + 3) = '\0';
+                }
+
+                char l_tmp_buf[70] = {};
+                dap_time_t l_ts_create = (dap_time_t)l_tx->header.ts_created;
+                dap_ctime_r(&l_ts_create, l_tmp_buf);
+                l_tmp_buf[strlen(l_tmp_buf) - 1] = '\0';
+
+                dap_string_append_printf(l_reply_str, "orderHash: %s\n ts_created: %s (%"DAP_UINT64_FORMAT_U")\n Status: %s, amount: %s (%s) %s, filled: %s%%, rate (%s/%s): %s, net: %s\n\n", l_tx_hash_str,
+                                         l_tmp_buf, l_ts_create, l_status_order,
+                                         l_amount_coins_str ? l_amount_coins_str : "0.0",
+                                         l_amount_datoshi_str ? l_amount_datoshi_str : "0",
+                                         l_price->token_sell, l_percent_completed_str,
+                                         l_price->token_buy, l_price->token_sell,
+                                         l_cp_rate = dap_chain_balance_to_coins(l_price->rate),
+                                         l_price->net->pub.name);
 
                 DAP_DEL_Z(l_tx_hash_str);
-                DAP_DEL_Z(l_cp_buy_coins);
-                DAP_DEL_Z(l_cp_buy_datoshi);
-                DAP_DEL_Z(l_cp_sell_coins);
-                DAP_DEL_Z(l_cp_sell_datoshi);
+                DAP_DEL_Z(l_amount_coins_str);
+                DAP_DEL_Z(l_amount_datoshi_str);
                 DAP_DEL_Z(l_cp_rate);
                 DAP_DEL_Z(l_price);
-                l_temp = l_temp->next;
             }
-//            dap_global_db_objs_delete(l_orders, l_orders_count);
-//            DAP_DELETE( l_gdb_group_str);
-            dap_list_free(l_arg.tx_list);
+            dap_list_free(l_tx_list);
             if (!l_reply_str->len) {
                 dap_string_append(l_reply_str, "No orders found");
             }
@@ -1803,26 +2021,30 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
                 dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -fee <unsigned int256>");
                 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);
             dap_hash_fast_t l_tx_hash = {};
             dap_chain_hash_fast_from_str(l_order_hash_str, &l_tx_hash);
             dap_chain_datum_tx_t *l_cond_tx = dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_tx_hash);
 
             if (l_cond_tx) {
-                dap_chain_net_srv_xchange_price_t *l_price = s_xchange_price_from_order(l_net, l_cond_tx, false);
+                dap_chain_net_srv_xchange_price_t *l_price = s_xchange_price_from_order(l_net, l_cond_tx, &l_datoshi_fee, false);
                 if(!l_price){
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't create price from order");
                     return -13;
                 }
                 // Create conditional transaction
                 dap_chain_hash_fast_from_str(l_order_hash_str, &l_price->order_hash);
+                char *l_ret = NULL;
                 dap_chain_datum_tx_t *l_tx = s_xchange_tx_create_exchange(l_price, l_wallet, l_datoshi_buy, l_datoshi_fee);
-                if (l_tx && s_xchange_tx_put(l_tx, l_net) &&
+                if (l_tx && (l_ret = s_xchange_tx_put(l_tx, l_net)) &&
                         dap_hash_fast_is_blank(&l_price->order_hash))
                     dap_chain_net_srv_order_delete_by_hash_str_sync(l_price->net, l_order_hash_str);
                 DAP_DELETE(l_price);
-                dap_cli_server_cmd_set_reply_text(a_str_reply, l_tx ? "Exchange transaction has done" :
-                                                                      "Exchange transaction error");
+                if (l_tx && l_ret){
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Exchange transaction has done. tx hash: %s", l_ret);
+                } else
+                    dap_cli_server_cmd_set_reply_text(a_str_reply,  "Exchange transaction error");
+
+                DAP_DEL_Z(l_ret);
             } else {
                 dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order not found");
                 return -13;
@@ -1854,24 +2076,23 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
 
 
             /* Validate input arguments ... */
-            l_opt_status = 0;   /* 0 - all */
+            l_opt_status = TX_STATUS_ALL;   /* 0 - all */
 
             if ( l_status_str )
             {
                 /* 1 - closed, 2 - open  */
-                if ( dap_strcmp (l_status_str, "close") == 0 )
-                    l_opt_status = 1;
-                else if ( dap_strcmp (l_status_str, "open") == 0 )
-                    l_opt_status = 2;
+                if ( dap_strcmp (l_status_str, "inactive") == 0 )
+                    l_opt_status = TX_STATUS_INACTIVE;
+                else if ( dap_strcmp (l_status_str, "active") == 0 )
+                    l_opt_status = TX_STATUS_ACTIVE;
                 else if ( dap_strcmp (l_status_str, "all") == 0 )
-                    l_opt_status = 0;
+                    l_opt_status = TX_STATUS_ALL;
                 else  {
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "Unrecognized '-status %s'", l_status_str);
                     return -3;
                 }
             }
 
-
             if(!l_net_str) {
                 dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'tx_list' requires parameter -net");
                 return -3;
@@ -1886,7 +2107,6 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
             l_time[0] = dap_time_from_str_rfc822(l_time_begin_str);
             l_time[1] = dap_time_from_str_rfc822(l_time_end_str);
 
-
             /* Dispatch request processing to ... */
             if ( l_addr_str )
             {
@@ -1896,7 +2116,6 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
                 return  s_cli_srv_xchange_tx_list_addr (l_net, l_time[0], l_time[1], l_addr, l_opt_status, a_str_reply);
             }
 
-
             // Prepare output string
             dap_string_t *l_reply_str = dap_string_new("");
 
@@ -1904,72 +2123,14 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
             dap_list_t *l_datum_list0 = dap_chain_datum_list(l_net, NULL, s_filter_tx_list, l_time);
             size_t l_datum_num = dap_list_length(l_datum_list0);
 
-            if(l_datum_num > 0) {
-                //dap_string_append_printf(l_reply_str, "Found %zu transactions:\n", l_datum_num);
+            if (l_datum_num > 0) {
                 log_it(L_DEBUG,  "Found %zu transactions:\n", l_datum_num);
-
                 dap_list_t *l_datum_list = l_datum_list0;
-                char l_hash_str [DAP_CHAIN_HASH_FAST_STR_SIZE + 8] = {0};
-
                 while(l_datum_list) {
-#if 0
-                    {/* @RRL */
-                    dap_chain_datum_t *p1 = (dap_chain_datum_t *) l_datum_list->data;
-                    log_it(L_CRITICAL, "l_datum: %p, [ver: %d, typ: %d, size: %d, ts: %llu]",
-                        p1, p1->header.version_id, p1->header.type_id, p1->header.data_size, p1->header.ts_create);
-
-                    dap_chain_datum_tx_t *p2 = (dap_chain_datum_tx_t*) p1->data;
-                    log_it(L_CRITICAL, "l_datum_tx: %p, [ts_created: %llu, size: %d]",
-                        p2, p2->header.ts_created, p2->header.tx_items_size);
-                    }
-#endif
 
                     dap_chain_datum_tx_t *l_datum_tx = (dap_chain_datum_tx_t*) ((dap_chain_datum_t*) l_datum_list->data)->data;
-                    size_t l_datum_tx_size = dap_chain_datum_tx_get_size(l_datum_tx);
-
-                    // Delimiter between tx
-//                    if(l_datum_list != l_datum_list0) {
-//                        dap_string_append(l_reply_str, "\n\n");
-//                    }
-
-                    // Tx hash
-                    dap_hash_fast_t l_tx_hash = {0};
-
-                    dap_hash_fast(l_datum_tx, l_datum_tx_size, &l_tx_hash);
-                    dap_chain_hash_fast_to_str(&l_tx_hash, l_hash_str, DAP_CHAIN_HASH_FAST_STR_SIZE + 1);
-//                    dap_string_append_printf(l_reply_str, "Hash: %s\n", l_hash_str);
-
-                    // Get input token ticker
-                    const char * l_tx_input_ticker = dap_ledger_tx_get_token_ticker_by_hash(
-                                l_net->pub.ledger, &l_tx_hash);
-
-                    // Find SRV_XCHANGE out_cond item
-                    int l_prev_cond_idx = 0;
-                    dap_chain_tx_out_cond_t *l_out_cond_item = dap_chain_datum_tx_out_cond_get(l_datum_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE,
-                                                                                               &l_prev_cond_idx);
-                    if (l_out_cond_item) {
-                        uint256_t l_value_from = l_out_cond_item->header.value;
-                        uint256_t l_rate = l_out_cond_item->subtype.srv_xchange.rate;
-                        char *l_rate_str = dap_chain_balance_to_coins(l_rate);
-                        char *l_value_from_str = dap_chain_balance_to_coins(l_value_from);
-
-                        l_rc = dap_ledger_tx_hash_is_used_out_item(l_net->pub.ledger, &l_tx_hash, l_prev_cond_idx, NULL);
-
-                        if ((l_opt_status == 1 && !l_rc) ||       /* Select close only */
-                                (l_opt_status == 2 &&  l_rc))     /* Select open only */
-                            continue;
-
+                    if (s_string_append_tx_cond_info(l_reply_str, l_net, l_datum_tx, l_opt_status, false, true, false))
                         l_show_tx_nr++;
-
-                        dap_string_append_printf(l_reply_str, "Hash: %s,", l_hash_str);
-                        dap_string_append_printf(l_reply_str, "  Status: %s,", l_rc ? "closed" : "open");
-                        dap_string_append_printf(l_reply_str, "  From: %s %s,", l_value_from_str, l_tx_input_ticker);
-                        dap_string_append_printf(l_reply_str, "  Rate: %s Buy token: %s\n", l_rate_str, l_out_cond_item->subtype.srv_xchange.buy_token);
-
-                        DAP_DELETE(l_value_from_str);
-                        DAP_DELETE(l_rate_str);
-                    }
-
                     l_datum_list = dap_list_next(l_datum_list);
                 }
                 dap_string_append_printf(l_reply_str, "Found %d transactions", l_show_tx_nr);
@@ -1996,16 +2157,13 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
                 return -4;
             }
 
-
             // Select subcommands
 
             // check for price subcommand
             const char * l_price_subcommand = NULL;
             dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "price", &l_price_subcommand);
-
-            // check for get subcommand
             if ( l_price_subcommand ){
-                // Check for token1
+                // Check for token_from
                 const char * l_token_from_str = NULL;
                 dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-token_from", &l_token_from_str);
                 if(!l_token_from_str){
@@ -2018,7 +2176,7 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
                     return -6;
                 }
 
-                // Check for token2
+                // Check for token_to
                 const char * l_token_to_str = NULL;
                 dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-token_to", &l_token_to_str);
                 if(!l_token_to_str){
@@ -2027,7 +2185,7 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
                 }
                 dap_chain_datum_token_t * l_token_to_datum = dap_ledger_token_ticker_check( l_net->pub.ledger, l_token_to_str);
                 if(!l_token_to_datum){
-                    dap_cli_server_cmd_set_reply_text(a_str_reply,"Can't find \"%s\" token in network \"%s\" for argument '-token2' ", l_token_to_str, l_net->pub.name);
+                    dap_cli_server_cmd_set_reply_text(a_str_reply,"Can't find \"%s\" token in network \"%s\" for argument '-token_to' ", l_token_to_str, l_net->pub.name);
                     return -6;
                 }
 
@@ -2048,7 +2206,7 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
                     dap_string_t *l_reply_str = dap_string_new("");
 
                     dap_list_t *l_tx_cond_list = dap_chain_net_get_tx_cond_all_by_srv_uid(l_net, c_dap_chain_net_srv_xchange_uid,
-                                                                                          l_time_from,l_time_to,TX_SEARCH_TYPE_NET );
+                                                                                          0,0,TX_SEARCH_TYPE_NET );
                     dap_list_t * l_cur = l_tx_cond_list;
                     uint256_t l_total_rates = {0};
                     uint256_t l_total_rates_count = {0};
@@ -2056,24 +2214,44 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
                     while(l_cur){
                         dap_chain_datum_tx_t * l_tx =(dap_chain_datum_tx_t *) l_cur->data;
                         if(l_tx){
-                            // TODO find another way to get current tx hash
-                            dap_hash_fast_t * l_tx_hash = dap_chain_node_datum_tx_calc_hash(l_tx);
+                             // TODO find another way to get current tx hash
+                            dap_hash_fast_t l_tx_hash = {};
+                            dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_tx_hash);
+
                             int l_cond_idx = 0;
-                            dap_chain_tx_out_cond_t *l_out_cond_item = dap_chain_datum_tx_out_cond_get(l_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE,
-                                                                                                    &l_cond_idx);
-                            if (l_out_cond_item &&
-                                    dap_ledger_tx_hash_is_used_out_item(l_net->pub.ledger, l_tx_hash, l_cond_idx, NULL)) {
-                                uint256_t l_value_sell = l_out_cond_item->header.value;
-                                l_rate = l_out_cond_item->subtype.srv_xchange.rate;
-                                    if (!IS_ZERO_256(l_value_sell)) {
-                                        if(SUM_256_256(l_rate, l_total_rates, &l_total_rates )!= 0)
-                                            log_it(L_ERROR, "Overflow on avarage price calculation (summing)");
-                                        INCR_256(&l_total_rates_count);
-                                    }else{
-                                        log_it(L_ERROR, "Sell value is 0 in avarage price calculation (summing)");
-                                    }
+                            dap_chain_tx_out_cond_t *l_out_cond_item = NULL;
+
+                            if (s_xchange_tx_get_type(l_net, l_tx, &l_out_cond_item, &l_cond_idx, NULL) != TX_TYPE_ORDER){
+                                l_cur = dap_list_next(l_cur);
+                                continue;
+                            }
+
+                            const char * l_tx_input_ticker = dap_ledger_tx_get_token_ticker_by_hash(l_net->pub.ledger, &l_tx_hash);
+
+                            if (!l_tx_input_ticker || strcmp(l_tx_input_ticker, l_token_from_str)){
+                                l_cur = dap_list_next(l_cur);
+                                continue;
+                            }
+
+                            if (strcmp(l_out_cond_item->subtype.srv_xchange.buy_token, l_token_to_str)){
+                                l_cur = dap_list_next(l_cur);
+                                continue;
+                            }
+
+                            if (s_tx_check_for_open_close(l_net, l_tx) != 2){
+                                l_cur = dap_list_next(l_cur);
+                                continue;
                             }
-                            DAP_DEL_Z(l_tx_hash);
+
+                            uint256_t l_value_sell = l_out_cond_item->header.value;
+                            l_rate = l_out_cond_item->subtype.srv_xchange.rate;
+                                if (!IS_ZERO_256(l_value_sell)) {
+                                    if(SUM_256_256(l_rate, l_total_rates, &l_total_rates )!= 0)
+                                        log_it(L_ERROR, "Overflow on average price calculation (summing)");
+                                    INCR_256(&l_total_rates_count);
+                                }else{
+                                    log_it(L_ERROR, "Sell value is 0 in avarage price calculation (summing)");
+                                }
                         }
                         l_cur = dap_list_next(l_cur);
                     }
@@ -2092,72 +2270,57 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
                 }else if (strcmp(l_price_subcommand,"history") == 0){
 
                     dap_string_t *l_reply_str = dap_string_new("");
+                    dap_time_t l_time[2];
+                    l_time[0] = l_time_from;
+                    l_time[1] = l_time_to;
 
-                    dap_chain_datum_tx_spends_items_t * l_tx_spends = dap_chain_net_get_tx_cond_all_with_spends_by_srv_uid(l_net, c_dap_chain_net_srv_xchange_uid,
-                            l_time_from,l_time_to,TX_SEARCH_TYPE_NET);
+                    // Find transactions using filter function s_filter_tx_list()
+                    dap_list_t *l_datum_list0 = dap_chain_datum_list(l_net, NULL, s_filter_tx_list, l_time);
+                    size_t l_datum_num = dap_list_length(l_datum_list0);
 
+                    if (l_datum_num == 0){
+                        dap_cli_server_cmd_set_reply_text(a_str_reply,"Can't find transactions");
+                        return -6;
+                    }
 
-                    dap_chain_datum_tx_spends_item_t * l_cur = NULL, *l_tmp = NULL;
-                    HASH_ITER(hh, l_tx_spends->tx_outs, l_cur,l_tmp) {
-                        dap_chain_datum_tx_t * l_tx =l_cur->tx;
+                    dap_list_t * l_cur = l_datum_list0;
+                    while(l_cur){
+                        dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t*) ((dap_chain_datum_t*) l_cur->data)->data;
                         if(l_tx){
-                            dap_hash_fast_t * l_tx_hash = &l_cur->tx_hash;
-
-                            // Get input token ticker
-                            const char * l_tx_input_ticker = dap_ledger_tx_get_token_ticker_by_hash(
-                                        l_net->pub.ledger, l_tx_hash);
-
-                            // Check if output is spent
-                            dap_chain_tx_out_cond_t *l_out_cond_item = l_cur->out_cond;
-                            if(l_out_cond_item && l_cur->tx_next) {
-
-                                // Print tx_hash
-                                char * l_tx_hash_str = dap_chain_hash_fast_to_str_new(l_tx_hash);
-                                dap_string_append_printf(l_reply_str,"Tx hash: %s\n", l_tx_hash_str ? l_tx_hash_str : "(null)");
-                                DAP_DEL_Z(l_tx_hash_str);
-
-                                // Print tx_created
-                                char l_tx_ts_str[92] = {0};
-                                struct tm l_tm={0};                                             /* Convert ts to  Sat May 17 01:17:08 2014 */
-                                uint64_t l_ts = l_tx->header.ts_created; // We take the next tx in chain to print close time, not the open one
-                                if ( (localtime_r((time_t *) &l_ts, &l_tm )) )
-                                    asctime_r (&l_tm, l_tx_ts_str);
-
-                                dap_string_append_printf(l_reply_str,"\tts_created: %s", l_tx_ts_str);
-
-                                // Print tx_closed
-                                memset(l_tx_ts_str,0,sizeof(l_tx_ts_str));
-                                memset(&l_tm,0,sizeof(l_tm));                                             /* Convert ts to  Sat May 17 01:17:08 2014 */
-                                l_ts = l_cur->tx_next->header.ts_created; // We take the next tx in chain to print close time, not the open one
-                                if ( (localtime_r((time_t *) &l_ts, &l_tm )) )
-                                    asctime_r (&l_tm, l_tx_ts_str);
-
-                                dap_string_append_printf(l_reply_str,"\tts_closed: %s", l_tx_ts_str);
-
-                                // Print value_from/value_to
-
-                                uint256_t l_value_from = l_out_cond_item->header.value;
-                                uint256_t l_rate = l_out_cond_item->subtype.srv_xchange.rate;
-                                uint256_t l_value_to = {};
-                                MULT_256_COIN(l_value_from, l_rate, &l_value_to);
-
-                                char * l_value_from_str = dap_chain_balance_to_coins(l_value_from);
-                                char * l_value_to_str = dap_chain_balance_to_coins(l_value_to);
-                                char *l_rate_str = dap_chain_balance_to_coins(l_rate);
-
-                                dap_string_append_printf(l_reply_str, "  From: %s %s   ", l_value_from_str, l_tx_input_ticker);
-                                dap_string_append_printf(l_reply_str, "  To: %s %s   ", l_value_to_str, l_out_cond_item->subtype.srv_xchange.buy_token );
-                                dap_string_append_printf(l_reply_str, "  Price: %s", l_rate_str);
-                                DAP_DELETE(l_value_from_str);
-                                DAP_DELETE(l_value_to_str);
-                                DAP_DELETE(l_rate_str);
-                                // Delimiter between tx
-                                dap_string_append_printf(l_reply_str,"\n\n");
+                            dap_hash_fast_t l_tx_hash = {};
+                            dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_tx_hash);
+
+                            const char * l_tx_input_ticker = dap_ledger_tx_get_token_ticker_by_hash(l_net->pub.ledger, &l_tx_hash);
+
+                            if (!l_tx_input_ticker || strcmp(l_tx_input_ticker, l_token_from_str)){
+                                l_cur = dap_list_next(l_cur);
+                                continue;
                             }
 
+                            dap_chain_tx_out_cond_t *l_out_cond_item = dap_chain_datum_tx_out_cond_get(l_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE,
+                                                                                                       NULL);
+                            if(!l_out_cond_item){
+                                int l_item_idx = 0;
+                                byte_t *l_tx_item = dap_chain_datum_tx_item_get(l_tx, &l_item_idx, TX_ITEM_TYPE_IN_COND , NULL);
+                                dap_chain_tx_in_cond_t * l_in_cond = l_tx_item ? (dap_chain_tx_in_cond_t *) l_tx_item : NULL;
+                                int l_prev_cond_idx = 0;
+                                dap_chain_datum_tx_t * l_prev_tx = l_in_cond ? dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_in_cond->header.tx_prev_hash) : NULL;
+                                dap_chain_tx_out_cond_t *l_out_prev_cond_item = l_prev_tx ? dap_chain_datum_tx_out_cond_get(l_prev_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE,
+                                                                                                                            &l_prev_cond_idx) : NULL;
+
+                                if (!l_out_prev_cond_item || strcmp(l_out_prev_cond_item->subtype.srv_xchange.buy_token, l_token_to_str)){
+                                    l_cur = dap_list_next(l_cur);
+                                    continue;
+                                }
+                            } else if (strcmp(l_out_cond_item->subtype.srv_xchange.buy_token, l_token_to_str)){
+                                l_cur = dap_list_next(l_cur);
+                                continue;
+                            }
+
+                            s_string_append_tx_cond_info(l_reply_str, l_net, l_tx, TX_STATUS_ALL, false, false, true);
                         }
+                        l_cur = dap_list_next(l_cur);
                     }
-                    dap_chain_datum_tx_spends_items_free(l_tx_spends);
 
                     *a_str_reply = dap_string_free(l_reply_str, false);
                     break;
-- 
GitLab