From 7f8ec89e3ba33cf96772872445664a0aa89e4c40 Mon Sep 17 00:00:00 2001
From: "daniil.frolov" <daniil.frolov@demlabs.net>
Date: Thu, 21 Mar 2024 19:21:28 +0000
Subject: [PATCH] hotfix_10684_port_to_rc

---
 .../dap_stream_ch_chain_net_srv.c             | 851 +++++++++---------
 .../dap_stream_ch_chain_net_srv.h             |  60 --
 .../include/dap_stream_ch_chain_net_srv.h     |  69 +-
 .../chain-net/dap_stream_ch_chain_net.c       |  24 +-
 modules/common/dap_chain_datum.c              |   1 -
 modules/common/include/dap_chain_common.h     |  24 +-
 modules/net/dap_chain_ledger.c                |   6 +-
 modules/net/dap_chain_net.c                   |   4 +-
 modules/net/dap_chain_net_voting.c            |  42 +-
 modules/net/dap_chain_node_cli_cmd.c          |   2 +-
 modules/net/include/dap_chain_ledger.h        |   1 -
 modules/net/include/dap_chain_net_voting.h    |   4 +-
 .../net/include/dap_chain_node_cli_cmd_tx.h   |   2 +-
 modules/net/srv/dap_chain_net_srv.c           | 767 +++++++---------
 modules/net/srv/dap_chain_net_srv_order.c     |  12 +-
 .../srv/dap_chain_net_srv_stream_session.c    |   2 +-
 modules/net/srv/include/dap_chain_net_srv.h   |  44 +-
 .../net/srv/include/dap_chain_net_srv_order.h |   3 +-
 .../dap_chain_net_srv_stream_session.h        |   3 +-
 .../service/datum/dap_chain_net_srv_datum.c   |  13 +-
 modules/service/vpn/dap_chain_net_srv_vpn.c   | 164 ++--
 .../service/vpn/dap_chain_net_vpn_client.c    |   9 +-
 .../xchange/dap_chain_net_srv_xchange.c       |  46 -
 23 files changed, 982 insertions(+), 1171 deletions(-)
 delete mode 100644 modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.h

diff --git a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c
index b1d9e9998f..f27ac58f68 100644
--- a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c
+++ b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c
@@ -30,7 +30,6 @@ along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/lic
 #include "dap_hash.h"
 #include "rand/dap_rand.h"
 
-#include "dap_chain_net_srv.h"
 #include "dap_chain_net_srv_stream_session.h"
 
 #include "dap_stream.h"
@@ -43,12 +42,38 @@ along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/lic
 
 #define LOG_TAG "dap_stream_ch_chain_net_srv"
 #define SRV_PAY_GDB_GROUP "local.srv_pay"
-
-typedef struct usages_in_grace{
-    dap_hash_fast_t tx_cond_hash;
-    dap_chain_net_srv_grace_t *grace;
-    UT_hash_handle hh;
-} usages_in_grace_t;
+#define SRV_STATISTIC_GDB_GROUP "local.srv_statistic"
+#define SRV_RECEIPTS_GDB_GROUP "local.receipts"
+
+// client statistic key struct
+typedef struct client_statistic_key{
+    char  key[18 + DAP_CHAIN_HASH_FAST_STR_SIZE];
+} client_statistic_key_t;
+
+// client statistic value struct
+typedef struct client_statistic_value{
+    struct {
+        uint64_t using_time;
+        uint256_t datoshi_value;
+        uint64_t bytes_received;
+        uint64_t bytes_sent;
+        uint64_t units;
+    } payed;
+    struct {
+        uint64_t using_time;
+        uint64_t bytes_received;
+        uint64_t bytes_sent;
+        uint64_t units;
+    } free;
+    struct {
+        uint64_t using_time;
+        uint256_t datoshi_value;
+        uint64_t bytes_received;
+        uint64_t bytes_sent;
+        uint64_t units;
+        uint64_t using_count;
+    } grace;
+} client_statistic_value_t;
 
 static void s_stream_ch_new(dap_stream_ch_t* ch , void* arg);
 static void s_stream_ch_delete(dap_stream_ch_t* ch , void* arg);
@@ -57,9 +82,11 @@ static bool s_stream_ch_packet_out(dap_stream_ch_t* ch , void* arg);
 
 static bool s_unban_client(dap_chain_net_srv_banlist_item_t *a_item);
 
-static void s_service_start(dap_stream_ch_t* a_ch , dap_stream_ch_chain_net_srv_pkt_request_t * a_request, size_t a_request_size);
-static void s_grace_period_start(dap_chain_net_srv_grace_t *a_grace);
-static bool s_grace_period_finish(usages_in_grace_t *a_grace);
+static bool s_service_start(dap_stream_ch_t* a_ch , dap_stream_ch_chain_net_srv_pkt_request_t * a_request, size_t a_request_size);
+static bool s_grace_period_start(dap_chain_net_srv_grace_t *a_grace);
+static bool s_grace_period_finish(dap_chain_net_srv_grace_usage_t *a_grace);
+static void s_set_usage_data_to_gdb(const dap_chain_net_srv_usage_t *a_usage);
+static uint256_t s_calc_datoshi(const dap_chain_net_srv_usage_t *a_usage, uint256_t *a_prev);
 
 static inline void s_grace_error(dap_chain_net_srv_grace_t *a_grace, dap_stream_ch_chain_net_srv_pkt_error_t a_err){
 
@@ -69,8 +96,8 @@ static inline void s_grace_error(dap_chain_net_srv_grace_t *a_grace, dap_stream_
                                         (dap_chain_net_srv_stream_session_t *)l_ch->stream->session->_inheritor : NULL;
 
     if (!l_srv_session){
-        DAP_DELETE(a_grace->request);
-        DAP_DELETE(a_grace);
+        DAP_DEL_Z(a_grace->request);
+        DAP_DEL_Z(a_grace);
         return;
     }
 
@@ -79,8 +106,8 @@ static inline void s_grace_error(dap_chain_net_srv_grace_t *a_grace, dap_stream_
         log_it( L_WARNING, "Next receipt is rejected. Waiting until current limits is over.");
         DAP_DEL_Z(a_grace->usage->receipt_next);
         memset(&a_grace->usage->tx_cond_hash, 0, sizeof(a_grace->usage->tx_cond_hash));
-        DAP_DELETE(a_grace->request);
-        DAP_DELETE(a_grace);
+        DAP_DEL_Z(a_grace->request);
+        DAP_DEL_Z(a_grace);
         return;
     }
 
@@ -103,8 +130,8 @@ static inline void s_grace_error(dap_chain_net_srv_grace_t *a_grace, dap_stream_
                 l_item = DAP_NEW_Z(dap_chain_net_srv_banlist_item_t);
                 if (!l_item) {
                     log_it(L_CRITICAL, "Memory allocation error");
-                    DAP_DELETE(a_grace->request);
-                    DAP_DELETE(a_grace);
+                    DAP_DEL_Z(a_grace->request);
+                    DAP_DEL_Z(a_grace);
                     return;
                 }
                 log_it(L_DEBUG, "Add client to banlist");
@@ -119,22 +146,20 @@ static inline void s_grace_error(dap_chain_net_srv_grace_t *a_grace, dap_stream_
 
     } else if (l_srv_session->usage_active)
         dap_chain_net_srv_usage_delete(l_srv_session);
-    DAP_DELETE(a_grace->request);
-    DAP_DELETE(a_grace);
+    DAP_DEL_Z(a_grace->request);
+    DAP_DEL_Z(a_grace);
 }
 
-// TODO: move this to net_srv
-static usages_in_grace_t * s_grace_table = NULL;
-static pthread_mutex_t s_ht_grace_table_mutex;
 /**
  * @brief dap_stream_ch_chain_net_init
+ * @param a_srv - inited service
  * @return
  */
-int dap_stream_ch_chain_net_srv_init(void)
+int dap_stream_ch_chain_net_srv_init(dap_chain_net_srv_t *a_srv)
 {
     log_it(L_NOTICE,"Chain network services channel initialized");
     dap_stream_ch_proc_add(DAP_STREAM_CH_NET_SRV_ID, s_stream_ch_new,s_stream_ch_delete,s_stream_ch_packet_in,s_stream_ch_packet_out);
-    pthread_mutex_init(&s_ht_grace_table_mutex, NULL);
+    pthread_mutex_init(&a_srv->grace_mutex, NULL);
 
     return 0;
 }
@@ -175,17 +200,21 @@ void s_stream_ch_new(dap_stream_ch_t* a_ch , void* arg)
  * @param ch
  * @param arg
  */
-void s_stream_ch_delete(dap_stream_ch_t* a_ch , void* a_arg)
+void s_stream_ch_delete(dap_stream_ch_t* a_ch , UNUSED_ARG void *a_arg)
 {
-    (void) a_ch;
-    (void) a_arg;
+// sanity check
+    dap_return_if_pass(!a_ch);
+// func work
     log_it(L_DEBUG, "Stream ch chain net srv delete");
 
     dap_chain_net_srv_stream_session_t * l_srv_session = a_ch && a_ch->stream && a_ch->stream->session ? (dap_chain_net_srv_stream_session_t *) a_ch->stream->session->_inheritor : NULL;
     dap_chain_net_srv_t * l_srv = l_srv_session && l_srv_session->usage_active ? dap_chain_net_srv_get(l_srv_session->usage_active->service->uid) : NULL;
 
-    if (l_srv)
+    if (l_srv) {
+        dap_chain_net_srv_usage_t *l_usage = dap_chain_net_srv_usage_find_unsafe(l_srv_session, l_srv_session->usage_active->id);
+        s_set_usage_data_to_gdb(l_usage);
         l_srv->callbacks.save_remain_service(l_srv, l_srv_session->usage_active->id, l_srv_session->usage_active->client);
+    }
 
     dap_chain_net_srv_call_closed_all(a_ch);
     if (a_ch->stream->session && a_ch->stream->session->_inheritor)
@@ -195,6 +224,9 @@ void s_stream_ch_delete(dap_stream_ch_t* a_ch , void* a_arg)
 
 static bool s_unban_client(dap_chain_net_srv_banlist_item_t *a_item)
 {
+// sanity check
+    dap_return_val_if_pass(!a_item, false);
+// func work
     log_it(L_DEBUG, "Unban client");
     pthread_mutex_lock(a_item->ht_mutex);
     HASH_DEL(*(a_item->ht_head), a_item);
@@ -203,33 +235,84 @@ static bool s_unban_client(dap_chain_net_srv_banlist_item_t *a_item)
     return false;
 }
 
-void dap_stream_ch_chain_net_srv_tx_cond_added_cb(void *a_arg, dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
+/**
+ * @brief create string with usage service statistic
+ * @return string with staticstic
+ */
+char *dap_stream_ch_chain_net_srv_create_statistic_report()
+{
+    size_t l_store_obj_count = 0;
+    dap_string_t *l_ret = dap_string_new("Service report:\n");
+    dap_store_obj_t *l_store_obj = dap_global_db_get_all_raw_sync(SRV_STATISTIC_GDB_GROUP, &l_store_obj_count);
+    for (size_t i = 0; i < l_store_obj_count; ++i) {
+        if(l_store_obj[i].value_len != sizeof(client_statistic_value_t)) {
+            log_it(L_ERROR, "Error size check statistic in %zu raw of %zu, expected value len %zu received %zu", i + 1, l_store_obj_count, sizeof(client_statistic_value_t), l_store_obj[i].value_len);
+            DAP_DEL_Z(l_store_obj[i].group);
+            DAP_DEL_Z(l_store_obj[i].key);
+            DAP_DEL_Z(l_store_obj[i].value);
+            continue;
+        }
+        client_statistic_value_t *l_value = (client_statistic_value_t *)l_store_obj[i].value;
+        char *l_payed_datoshi = dap_chain_balance_print(l_value->payed.datoshi_value);
+        char *l_grace_datoshi = dap_chain_balance_print(l_value->grace.datoshi_value);
+        dap_string_append_printf(
+            l_ret, "SRV UID: %.18s\nClient pkey hash: %s\n " \
+            "\tpayed:\n\t\tusing time:\t\t%"DAP_UINT64_FORMAT_U"\n\t\tbytes sent:\t\t%"DAP_UINT64_FORMAT_U"\n\t\tbytes received:\t\t%"DAP_UINT64_FORMAT_U"\n\t\tunits used:\t\t%"DAP_UINT64_FORMAT_U"\n\t\tdatoshi value:\t\t%s\n" \
+            "\tgrace:\n\t\tusing time:\t\t%"DAP_UINT64_FORMAT_U"\n\t\tbytes sent:\t\t%"DAP_UINT64_FORMAT_U"\n\t\tbytes received:\t\t%"DAP_UINT64_FORMAT_U"\n\t\tunits used:\t\t%"DAP_UINT64_FORMAT_U"\n\t\tdatoshi value:\t\t%s\n" \
+            "\tfree:\n\t\tusing time:\t\t%"DAP_UINT64_FORMAT_U"\n\t\tbytes sent:\t\t%"DAP_UINT64_FORMAT_U"\n\t\tbytes received:\t\t%"DAP_UINT64_FORMAT_U"\n\t\tunits used:\t\t%"DAP_UINT64_FORMAT_U"\n",
+            l_store_obj[i].key, l_store_obj[i].key + 18,
+            l_value->payed.using_time, l_value->payed.bytes_sent, l_value->payed.bytes_received, l_value->payed.units, l_payed_datoshi,
+            l_value->grace.using_time, l_value->grace.bytes_sent, l_value->grace.bytes_received, l_value->grace.units, l_grace_datoshi,
+            l_value->free.using_time, l_value->free.bytes_sent, l_value->free.bytes_received, l_value->free.units
+        );
+        DAP_DEL_Z(l_store_obj[i].group);
+        DAP_DEL_Z(l_store_obj[i].key);
+        DAP_DEL_Z(l_store_obj[i].value);
+        DAP_DEL_Z(l_payed_datoshi);
+        DAP_DEL_Z(l_grace_datoshi);
+    }
+    DAP_DEL_Z(l_store_obj);
+    return dap_string_free(l_ret, false);
+}
+
+void dap_stream_ch_chain_net_srv_tx_cond_added_cb(UNUSED_ARG void *a_arg, UNUSED_ARG dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
 {
-    UNUSED(a_ledger);
-    UNUSED(a_arg);
-    // TODO: 1. Get net_srv by srv_uid from tx_cond
-    // 2. Get usages in grace HT from service
-    usages_in_grace_t *l_item = NULL;
-    dap_hash_fast_t tx_cond_hash = {};
-    dap_hash_fast((void*)a_tx, dap_chain_datum_tx_get_size(a_tx), &tx_cond_hash);
-    pthread_mutex_lock(&s_ht_grace_table_mutex);
-    HASH_FIND(hh, s_grace_table, &tx_cond_hash, sizeof(dap_hash_fast_t), l_item);
-    pthread_mutex_unlock(&s_ht_grace_table_mutex);
+// sanity check
+    dap_return_if_pass(!a_tx);
+// func work
+    dap_chain_net_srv_grace_usage_t *l_item = NULL;
+    dap_hash_fast_t l_tx_cond_hash = {0};
+    dap_chain_tx_out_cond_t *l_out_cond = dap_chain_datum_tx_out_cond_get(a_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY, NULL);
+    if (!l_out_cond) {
+        log_it(L_ERROR, "Can't find dap_chain_tx_out_cond_t in dap_chain_datum_tx_t");
+        return;
+    }
+    dap_chain_net_srv_t *l_net_srv = dap_chain_net_srv_get(l_out_cond->header.srv_uid);
+    if (!l_net_srv) {
+        log_it(L_ERROR, "Can't find dap_chain_net_srv_t uid 0x%016"DAP_UINT64_FORMAT_X"", l_out_cond->header.srv_uid.uint64);
+        return;
+    }
+    dap_hash_fast((void*)a_tx, dap_chain_datum_tx_get_size(a_tx), &l_tx_cond_hash);
+    pthread_mutex_lock(&l_net_srv->grace_mutex);
+    HASH_FIND(hh, l_net_srv->grace_hash_tab, &l_tx_cond_hash, sizeof(dap_hash_fast_t), l_item);
+    pthread_mutex_unlock(&l_net_srv->grace_mutex);
     if (l_item){
         log_it(L_INFO, "Found tx in ledger by notify. Finish grace.");
         // Stop timer
-        dap_timerfd_delete_mt(l_item->grace->stream_worker->worker, l_item->grace->timer_es_uuid);
+        dap_timerfd_delete_mt(l_item->grace->timer->worker, l_item->grace->timer->esocket_uuid);
         // finish grace
+        if(!l_item->grace->usage->service)
+            HASH_DEL(l_net_srv->grace_hash_tab, l_item);
         s_grace_period_finish(l_item);
     }
 }
 
-static void s_service_start(dap_stream_ch_t* a_ch , dap_stream_ch_chain_net_srv_pkt_request_t * a_request, size_t a_request_size)
+static bool s_service_start(dap_stream_ch_t* a_ch , dap_stream_ch_chain_net_srv_pkt_request_t * a_request, size_t a_request_size)
 {
     assert(a_ch);
     dap_stream_ch_chain_net_srv_pkt_error_t l_err;
     memset(&l_err, 0, sizeof(l_err));
-    dap_chain_net_srv_t * l_srv = NULL;
+    dap_chain_net_srv_t *l_srv = NULL;
 
     dap_chain_net_srv_stream_session_t *l_srv_session = a_ch->stream && a_ch->stream->session ?
                                                         (dap_chain_net_srv_stream_session_t *)a_ch->stream->session->_inheritor : NULL;
@@ -239,15 +322,25 @@ static void s_service_start(dap_stream_ch_t* a_ch , dap_stream_ch_chain_net_srv_
     l_err.net_id.uint64 = a_request->hdr.net_id.uint64;
     l_err.srv_uid.uint64 = a_request->hdr.srv_uid.uint64;
 
+    if (dap_hash_fast_is_blank(&a_request->hdr.order_hash)){
+        log_it( L_ERROR, "No order hash in request.");
+        l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_PRICE_NOT_FOUND;
+        if(a_ch)
+            dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err));
+        if (l_srv && l_srv->callbacks.response_error)
+            l_srv->callbacks.response_error(l_srv, 0, NULL, &l_err, sizeof(l_err));
+        return false;
+    }
+
     if ( ! l_net ) {
         // Network not found
-        log_it( L_WARNING, "Can't find net with id 0x%016"DAP_UINT64_FORMAT_x"", a_request->hdr.srv_uid.uint64);
+        log_it( L_ERROR, "Can't find net with id 0x%016"DAP_UINT64_FORMAT_x"", a_request->hdr.srv_uid.uint64);
         l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_NETWORK_NOT_FOUND;
         if(a_ch)
             dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err));
         if (l_srv && l_srv->callbacks.response_error)
             l_srv->callbacks.response_error(l_srv, 0, NULL, &l_err, sizeof(l_err));
-        return;
+        return false;
     }
 
     bool l_check_role = dap_chain_net_get_role(l_net).enums > NODE_ROLE_MASTER;  // check role
@@ -264,7 +357,7 @@ static void s_service_start(dap_stream_ch_t* a_ch , dap_stream_ch_chain_net_srv_
             dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err));
         if (l_srv && l_srv->callbacks.response_error)
             l_srv->callbacks.response_error(l_srv, 0, NULL, &l_err, sizeof(l_err));
-        return;
+        return false;
     }
 
     dap_chain_net_srv_usage_t *l_usage = NULL;
@@ -276,7 +369,7 @@ static void s_service_start(dap_stream_ch_t* a_ch , dap_stream_ch_chain_net_srv_
             dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err));
         if (l_srv && l_srv->callbacks.response_error)
             l_srv->callbacks.response_error(l_srv, 0, NULL, &l_err, sizeof(l_err));
-        return;
+        return false;
     }
 
     l_err.usage_id = l_usage->id;
@@ -290,7 +383,7 @@ static void s_service_start(dap_stream_ch_t* a_ch , dap_stream_ch_chain_net_srv_
         if (l_srv && l_srv->callbacks.response_error)
             l_srv->callbacks.response_error(l_srv, 0, NULL, &l_err, sizeof(l_err));
         dap_chain_net_srv_usage_delete(l_srv_session);
-        return;
+        return false;
     }
     l_usage->client->stream_worker = a_ch->stream_worker;
     l_usage->client->ch = a_ch;
@@ -302,8 +395,28 @@ static void s_service_start(dap_stream_ch_t* a_ch , dap_stream_ch_chain_net_srv_
     l_usage->service = l_srv;
     l_usage->client_pkey_hash = a_request->hdr.client_pkey_hash;
 
+    dap_chain_net_srv_price_t * l_price = NULL;
+    bool l_specific_order_free = false;
+    l_price = dap_chain_net_srv_get_price_from_order(l_srv, "srv_vpn", &a_request->hdr.order_hash);
+    if (!l_price){
+        log_it(L_ERROR, "Can't get price from order!");
+            l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_PRICE_NOT_FOUND;
+            if(a_ch)
+                dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err));
+            if (l_srv && l_srv->callbacks.response_error)
+                l_srv->callbacks.response_error(l_srv, 0, NULL, &l_err, sizeof(l_err));
+            DAP_DEL_Z(l_usage->client);
+            DAP_DEL_Z(l_usage);
+            return false;
+    }
 
-    if (l_srv->pricelist || !dap_hash_fast_is_blank(&a_request->hdr.order_hash)){
+    if (IS_ZERO_256(l_price->value_datoshi)){
+        l_specific_order_free = true;
+    }
+
+    l_usage->price = l_price;
+
+    if (!l_specific_order_free){
         // not free service
         log_it( L_INFO, "Valid pricelist is founded. Start service in pay mode.");
 
@@ -315,11 +428,10 @@ static void s_service_start(dap_stream_ch_t* a_ch , dap_stream_ch_chain_net_srv_
             if (l_srv && l_srv->callbacks.response_error)
                 l_srv->callbacks.response_error(l_srv, 0, NULL, &l_err, sizeof(l_err));
             dap_chain_net_srv_usage_delete(l_srv_session);
-            return;
+            return false;
         }
 
-        if (!dap_hash_fast_is_blank(&a_request->hdr.order_hash))
-            l_usage->static_order_hash = a_request->hdr.order_hash;
+        l_usage->static_order_hash = a_request->hdr.order_hash;
 
         dap_chain_net_srv_grace_t *l_grace = DAP_NEW_Z(dap_chain_net_srv_grace_t);
         if (!l_grace) {
@@ -331,7 +443,7 @@ static void s_service_start(dap_stream_ch_t* a_ch , dap_stream_ch_chain_net_srv_
                 l_srv->callbacks.response_error(l_srv, 0, NULL, &l_err, sizeof(l_err));
             DAP_DEL_Z(l_usage->client);
             DAP_DEL_Z(l_usage);
-            return;
+            return false;
         }
         l_grace->request = DAP_DUP_SIZE(a_request, a_request_size);
         if (!l_grace->request) {
@@ -344,14 +456,15 @@ static void s_service_start(dap_stream_ch_t* a_ch , dap_stream_ch_chain_net_srv_
             DAP_DEL_Z(l_usage->client);
             DAP_DEL_Z(l_usage);
             DAP_DEL_Z(l_grace);
-            return;
+            return false;
         }
         l_grace->request_size   = a_request_size;
         l_grace->ch_uuid        = a_ch->uuid;
         l_grace->stream_worker  = a_ch->stream_worker;
         l_grace->usage          = l_usage;
-        s_grace_period_start(l_grace);
-    } else if (l_srv->allow_free_srv){
+        if (!s_grace_period_start(l_grace))
+            return false;
+    } else if (l_specific_order_free && l_srv->allow_free_srv){
         // Start service for free
         log_it( L_INFO, "Can't find a valid pricelist. Service provide for free");
         l_usage->is_free = true;
@@ -367,7 +480,7 @@ static void s_service_start(dap_stream_ch_t* a_ch , dap_stream_ch_chain_net_srv_
                 l_srv->callbacks.response_error(l_srv, 0, NULL, &l_err, sizeof(l_err));
             DAP_DEL_Z(l_usage->client);
             DAP_DEL_Z(l_usage);
-            return;
+            return false;
         }
         l_success->hdr.usage_id = l_usage->id;
         l_success->hdr.net_id.uint64 = l_usage->net->pub.id.uint64;
@@ -377,23 +490,25 @@ static void s_service_start(dap_stream_ch_t* a_ch , dap_stream_ch_chain_net_srv_
             l_usage->service->callbacks.response_success(l_usage->service, l_usage->id,  l_usage->client, NULL, 0);
         DAP_DELETE(l_success);
     }else {
-        log_it( L_INFO, "No pricelists. Free service sharing is not allowed. Service stop.");
+        log_it( L_INFO, "Free service sharing is not allowed. Service stop. If you want to share service for free switch on this function in configuration file.");
         dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof(l_err));
         if (l_srv && l_srv->callbacks.response_error)
             l_srv->callbacks.response_error(l_srv, 0, NULL, &l_err, sizeof(l_err));
     }
-    return;
+    return true;
 }
 
-static void s_grace_period_start(dap_chain_net_srv_grace_t *a_grace)
+static bool s_grace_period_start(dap_chain_net_srv_grace_t *a_grace)
 {
-    assert(a_grace);
+// sanity check
+    dap_return_val_if_pass(!a_grace, false);
+// func work
     dap_stream_ch_chain_net_srv_pkt_error_t l_err = { };
     dap_stream_ch_t *l_ch = dap_stream_ch_find_by_uuid_unsafe(a_grace->stream_worker, a_grace->ch_uuid);
 
     if (!l_ch){
         s_grace_error(a_grace, l_err);
-        return;
+        return false;
     }
 
     dap_chain_net_t * l_net = a_grace->usage->net;
@@ -409,7 +524,7 @@ static void s_grace_period_start(dap_chain_net_srv_grace_t *a_grace)
         log_it( L_WARNING, "No Ledger");
         l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_NETWORK_NO_LEDGER ;
         s_grace_error(a_grace, l_err);
-        return;
+        return false;
     }
 
     l_tx = a_grace->usage->is_waiting_new_tx_cond ? NULL : dap_ledger_tx_find_by_hash(l_ledger, &a_grace->usage->tx_cond_hash);
@@ -423,84 +538,45 @@ static void s_grace_period_start(dap_chain_net_srv_grace_t *a_grace)
                 log_it(L_INFO, "Client pkey is banned!");
                 l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_RECEIPT_BANNED_PKEY_HASH ;
                 s_grace_error(a_grace, l_err);;
-                return;
+                return false;
             }
         }
 
         a_grace->usage->is_grace = true;
 
         if (a_grace->usage->receipt){ // If it is repeated grace
-            if (dap_hash_fast_is_blank(&a_grace->usage->static_order_hash)){
-                log_it(L_MSG, "Get price from list.");
-                DL_FOREACH(a_grace->usage->service->pricelist, l_price) {
-                    switch (l_price->units_uid.enm) {
-                    case SERV_UNIT_MB:
-                    case SERV_UNIT_SEC:
-                    case SERV_UNIT_DAY:
-                    case SERV_UNIT_KB:
-                    case SERV_UNIT_B:
-                        log_it(L_MSG, "Proper unit type %s found among available prices",
-                               dap_chain_srv_unit_enum_to_str(l_price->units_uid.enm));
-                        break;
-                    default:
-                        continue;
-                    }
-                    break; // proper price found, thus we exit from the loop
-                }
-
-                if (!l_price) {
-                    log_it(L_ERROR, "Price with proper unit type not found, check available orders and/or pricelists");
-                    l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_CANT_ADD_USAGE;
-                    s_grace_error(a_grace, l_err);
-                    return;
-                }
-                a_grace->usage->price = l_price;
-            } else {
-                log_it(L_MSG, "Get price from order %s.",
-                    dap_chain_hash_fast_to_str_static(&a_grace->usage->static_order_hash));
-                if ((l_price = dap_chain_net_srv_get_price_from_order(a_grace->usage->service, "srv_vpn", &a_grace->usage->static_order_hash))){
-                    switch (l_price->units_uid.enm) {
-                    case SERV_UNIT_MB:
-                    case SERV_UNIT_SEC:
-                    case SERV_UNIT_DAY:
-                    case SERV_UNIT_KB:
-                    case SERV_UNIT_B:
-                        log_it(L_MSG, "Proper unit type %s found among available prices",
-                               dap_chain_srv_unit_enum_to_str(l_price->units_uid.enm));
-                        a_grace->usage->price = l_price;
-                    default:
-                        DAP_DEL_Z(l_price);
-                    }
-                }
-            }
+            char *l_order_hash_str = dap_chain_hash_fast_to_str_new(&a_grace->usage->static_order_hash);
+            log_it(L_MSG, "Using price from order %s.", l_order_hash_str);
+            DAP_DELETE(l_order_hash_str);
+            l_price = a_grace->usage->price;
 
             if (!l_price) {
                 log_it(L_ERROR, "Price with proper unit type not found, check available orders and/or pricelists");
                 l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_CANT_ADD_USAGE;
                 s_grace_error(a_grace, l_err);
-                return;
+                return false;
             }
-            usages_in_grace_t *l_item = DAP_NEW_Z_SIZE(usages_in_grace_t, sizeof(usages_in_grace_t));
+            dap_chain_net_srv_grace_usage_t *l_item = DAP_NEW_Z(dap_chain_net_srv_grace_usage_t);
             if (!l_item) {
                 log_it(L_CRITICAL, "Memory allocation error");
                 s_grace_error(a_grace, l_err);
-                return;
+                return false;
             }
             l_item->grace = a_grace;
             l_item->tx_cond_hash = a_grace->usage->tx_cond_hash;
 
-            pthread_mutex_lock(&s_ht_grace_table_mutex);
-            HASH_ADD(hh, s_grace_table, tx_cond_hash, sizeof(dap_hash_fast_t), l_item);
-            pthread_mutex_unlock(&s_ht_grace_table_mutex);
-            a_grace->timer_es_uuid = dap_timerfd_start_on_worker(a_grace->stream_worker->worker, a_grace->usage->service->grace_period * 1000,
-                                                                 (dap_timerfd_callback_t)s_grace_period_finish, l_item)->esocket_uuid;
-            log_it(L_INFO, "Start grace timer %s.", a_grace->timer_es_uuid ? "successfuly." : "failed." );
+            pthread_mutex_lock(&a_grace->usage->service->grace_mutex);
+            HASH_ADD(hh, a_grace->usage->service->grace_hash_tab, tx_cond_hash, sizeof(dap_hash_fast_t), l_item);
+            pthread_mutex_unlock(&a_grace->usage->service->grace_mutex);
+            a_grace->timer = dap_timerfd_start_on_worker(a_grace->stream_worker->worker, a_grace->usage->service->grace_period * 1000,
+                                                                 (dap_timerfd_callback_t)s_grace_period_finish, l_item);
+            log_it(L_INFO, "Start grace timer %s.", a_grace->timer ? "successfuly." : "failed." );
         } else { // Else if first grace at service start
-            usages_in_grace_t *l_item = DAP_NEW_Z_SIZE(usages_in_grace_t, sizeof(usages_in_grace_t));
+            dap_chain_net_srv_grace_usage_t *l_item = DAP_NEW_Z(dap_chain_net_srv_grace_usage_t);
             if (!l_item) {
                 log_it(L_CRITICAL, "Memory allocation error");
                 s_grace_error(a_grace, l_err);
-                return;
+                return false;
             }
             l_item->grace = a_grace;
             l_item->tx_cond_hash = a_grace->usage->tx_cond_hash;
@@ -510,7 +586,7 @@ static void s_grace_period_start(dap_chain_net_srv_grace_t *a_grace)
             dap_stream_ch_chain_net_srv_pkt_success_t *l_success = DAP_NEW_Z_SIZE(dap_stream_ch_chain_net_srv_pkt_success_t,
                                                                                   l_success_size);
             if(!l_success) {
-                log_it(L_ERROR, "Memory allocation error in %s, line %d", __PRETTY_FUNCTION__, __LINE__);
+                log_it(L_CRITICAL, "Memory allocation error");
                 l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_ALLOC_MEMORY_ERROR;
                 if(l_ch)
                     dap_stream_ch_pkt_write_unsafe(l_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err));
@@ -531,12 +607,12 @@ static void s_grace_period_start(dap_chain_net_srv_grace_t *a_grace)
                     a_grace->usage->service->callbacks.response_success(a_grace->usage->service, a_grace->usage->id,
                                                                         a_grace->usage->client, NULL, 0);
                 DAP_DELETE(l_success);
-                pthread_mutex_lock(&s_ht_grace_table_mutex);
-                HASH_ADD(hh, s_grace_table, tx_cond_hash, sizeof(dap_hash_fast_t), l_item);
-                pthread_mutex_unlock(&s_ht_grace_table_mutex);
-                a_grace->timer_es_uuid = dap_timerfd_start_on_worker(a_grace->stream_worker->worker, a_grace->usage->service->grace_period * 1000,
-                                                                     (dap_timerfd_callback_t)s_grace_period_finish, l_item)->esocket_uuid;
-                log_it(L_INFO, "Start grace timer %s.", a_grace->timer_es_uuid ? "successfuly." : "failed." );
+                pthread_mutex_lock(&a_grace->usage->service->grace_mutex);
+                HASH_ADD(hh, a_grace->usage->service->grace_hash_tab, tx_cond_hash, sizeof(dap_hash_fast_t), l_item);
+                pthread_mutex_unlock(&a_grace->usage->service->grace_mutex);
+                a_grace->timer = dap_timerfd_start_on_worker(a_grace->stream_worker->worker, a_grace->usage->service->grace_period * 1000,
+                                                                     (dap_timerfd_callback_t)s_grace_period_finish, l_item);
+                log_it(L_INFO, "Start grace timer %s.", a_grace->timer ? "successfuly." : "failed." );
             }
         }
 
@@ -545,7 +621,7 @@ static void s_grace_period_start(dap_chain_net_srv_grace_t *a_grace)
             log_it(L_ERROR, "Can't pay service because net %s is offline.", l_net->pub.name);
             l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_NETWORK_IS_OFFLINE;
             s_grace_error(a_grace, l_err);
-            return;
+            return false;
         }
 
         a_grace->usage->tx_cond = l_tx;
@@ -556,7 +632,7 @@ static void s_grace_period_start(dap_chain_net_srv_grace_t *a_grace)
             log_it( L_WARNING, "No conditioned output");
             l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NO_COND_OUT ;
             s_grace_error(a_grace, l_err);
-            return;
+            return false;
         }
 
         // Check cond output if it equesl or not to request
@@ -565,7 +641,7 @@ static void s_grace_period_start(dap_chain_net_srv_grace_t *a_grace)
                     l_tx_out_cond->header.srv_uid.uint64 );
             l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_WRONG_SRV_UID  ;
             s_grace_error(a_grace, l_err);
-            return;
+            return false;
         }
 
         const char *l_ticker = dap_ledger_tx_get_token_ticker_by_hash(l_ledger, &a_grace->usage->tx_cond_hash);
@@ -575,109 +651,69 @@ static void s_grace_period_start(dap_chain_net_srv_grace_t *a_grace)
             log_it( L_ERROR, "Token ticker not found for tx cond hash %s", l_hash_str);
             l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_FOUND;
             s_grace_error(a_grace, l_err);
-            return;
+            return false;
         }
         dap_stpcpy(a_grace->usage->token_ticker, l_ticker);
 
-
-        if (dap_hash_fast_is_blank(&a_grace->usage->static_order_hash)){
-            dap_chain_net_srv_price_t *l_price_tmp;
-            DL_FOREACH(a_grace->usage->service->pricelist, l_price_tmp) {
-                if (!l_price_tmp){
-                    continue;
-                }
-
-                if (l_price_tmp->net->pub.id.uint64  != a_grace->usage->net->pub.id.uint64){
-                    log_it( L_WARNING, "Pricelist is not for net %s.", a_grace->usage->net->pub.name);
-                    continue;
-                }
-
-                if (dap_strcmp(l_price_tmp->token, l_ticker) != 0){
-                    log_it( L_WARNING, "Token ticker in the pricelist and tx do not match");
-                    continue;
-                }
-
-                if (l_price_tmp->units_uid.enm != l_tx_out_cond->subtype.srv_pay.unit.enm){
-                    log_it( L_WARNING, "Unit ID in the pricelist and tx do not match");
-                    continue;
-                }
-
-                uint256_t l_unit_price = {};
-                if (l_price_tmp->units != 0){
-                    DIV_256(l_price_tmp->value_datoshi, GET_256_FROM_64(l_price_tmp->units), &l_unit_price);
-                } else {
-                    log_it( L_WARNING, "Units in pricelist is zero. ");
-                    continue;
-                }
-
-                if(IS_ZERO_256(l_tx_out_cond->subtype.srv_pay.unit_price_max_datoshi) ||
-                    compare256(l_unit_price, l_tx_out_cond->subtype.srv_pay.unit_price_max_datoshi) <= 0){
-                    l_price = l_price_tmp;
-                    break;
-                } else {
-                    log_it( L_WARNING, "Unit price in pricelist is greater than max allowable.");
-                }
+        char *l_order_hash_str = dap_chain_hash_fast_to_str_new(&a_grace->usage->static_order_hash);
+        log_it(L_MSG, "Using price from order %s.", l_order_hash_str);
+        DAP_DELETE(l_order_hash_str);
+        if ((l_price = a_grace->usage->price)){
+            if (l_price->net->pub.id.uint64  != a_grace->usage->net->pub.id.uint64){
+                log_it( L_WARNING, "Pricelist is not for net %s.", a_grace->usage->net->pub.name);
+                l_err.code =DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN;
+                s_grace_error(a_grace, l_err);
+                return false;
             }
-        } else {
-            log_it(L_MSG, "Get price from order %s.",
-                dap_chain_hash_fast_to_str_static(&a_grace->usage->static_order_hash));
-            if ((l_price = dap_chain_net_srv_get_price_from_order(a_grace->usage->service, "srv_vpn", &a_grace->usage->static_order_hash))){
-                if (l_price->net->pub.id.uint64  != a_grace->usage->net->pub.id.uint64){
-                    log_it( L_WARNING, "Pricelist is not for net %s.", a_grace->usage->net->pub.name);
-                    l_err.code =DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN;
-                    s_grace_error(a_grace, l_err);
-                    return;
-                }
 
-                if (dap_strcmp(l_price->token, l_ticker) != 0){
-                    log_it( L_WARNING, "Token ticker in the pricelist and tx do not match");
-                    l_err.code =DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN;
-                    s_grace_error(a_grace, l_err);
-                    return;
-                }
+            if (dap_strcmp(l_price->token, l_ticker) != 0){
+                log_it( L_WARNING, "Token ticker in the pricelist and tx do not match");
+                l_err.code =DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN;
+                s_grace_error(a_grace, l_err);
+                return false;
+            }
 
-                if (l_price->units_uid.enm != l_tx_out_cond->subtype.srv_pay.unit.enm){
-                    log_it( L_WARNING, "Unit ID in the pricelist and tx do not match");
-                    l_err.code =DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN;
-                    s_grace_error(a_grace, l_err);
-                    return;
-                }
+            if (l_price->units_uid.enm != l_tx_out_cond->subtype.srv_pay.unit.enm){
+                log_it( L_WARNING, "Unit ID in the pricelist and tx do not match");
+                l_err.code =DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN;
+                s_grace_error(a_grace, l_err);
+                return false;
+            }
 
-                uint256_t l_unit_price = {};
-                if (l_price->units != 0){
-                    DIV_256(l_price->value_datoshi, GET_256_FROM_64(l_price->units), &l_unit_price);
-                } else {
-                    log_it( L_WARNING, "Units in pricelist is zero. ");
-                    l_err.code =DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN;
-                    s_grace_error(a_grace, l_err);
-                    return;
-                }
+            uint256_t l_unit_price = {};
+            if (l_price->units != 0){
+                DIV_256(l_price->value_datoshi, GET_256_FROM_64(l_price->units), &l_unit_price);
+            } else {
+                log_it( L_WARNING, "Units in pricelist is zero. ");
+                l_err.code =DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN;
+                s_grace_error(a_grace, l_err);
+                return false;
+            }
 
-                if(IS_ZERO_256(l_tx_out_cond->subtype.srv_pay.unit_price_max_datoshi) ||
-                    compare256(l_unit_price, l_tx_out_cond->subtype.srv_pay.unit_price_max_datoshi) <= 0){
-                } else {
-                    log_it( L_WARNING, "Unit price in pricelist is greater than max allowable.");
-                    l_err.code =DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN;
-                    s_grace_error(a_grace, l_err);
-                    return;
-                }
+            if(IS_ZERO_256(l_tx_out_cond->subtype.srv_pay.unit_price_max_datoshi) ||
+                compare256(l_unit_price, l_tx_out_cond->subtype.srv_pay.unit_price_max_datoshi) <= 0){
+            } else {
+                log_it( L_WARNING, "Unit price in pricelist is greater than max allowable.");
+                l_err.code =DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN;
+                s_grace_error(a_grace, l_err);
+                return false;
             }
         }
 
+
         if ( !l_price ) {
             log_it( L_WARNING, "Request can't be processed because no acceptable price in pricelist for token %s in network %s",
                     l_ticker, l_net->pub.name );
             l_err.code =DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN;
             s_grace_error(a_grace, l_err);
-            return;
+            return false;
         }
-        a_grace->usage->price = l_price;
         int ret;
         if ((ret = a_grace->usage->service->callbacks.requested(a_grace->usage->service, a_grace->usage->id, a_grace->usage->client, a_grace->request, a_grace->request_size)) != 0) {
             log_it( L_WARNING, "Request canceled by service callback, return code %d", ret);
             l_err.code = (uint32_t) ret ;
             s_grace_error(a_grace, l_err);
-            return;
+            return false;
         }
 
 //        memcpy(&a_grace->usage->client_pkey_hash, &l_tx_out_cond->subtype.srv_pay.pkey_hash, sizeof(dap_chain_hash_fast_t));
@@ -686,36 +722,20 @@ static void s_grace_period_start(dap_chain_net_srv_grace_t *a_grace)
             dap_stream_ch_chain_net_srv_remain_service_store_t* l_remain_service = NULL;
             l_remain_service = a_grace->usage->service->callbacks.get_remain_service(a_grace->usage->service, a_grace->usage->id, a_grace->usage->client);
             if (l_remain_service && !a_grace->usage->is_active &&
-                (l_remain_service->limits_ts || l_remain_service->limits_bytes) &&
-                l_remain_service->remain_units_type.enm == l_tx_out_cond->subtype.srv_pay.unit.enm){
+                ((l_remain_service->limits_ts && l_tx_out_cond->subtype.srv_pay.unit.enm == SERV_UNIT_SEC)  || 
+                (l_remain_service->limits_bytes && l_tx_out_cond->subtype.srv_pay.unit.enm == SERV_UNIT_B))){
                 // Accept connection, set limits and start service
                 dap_chain_net_srv_stream_session_t * l_srv_session = (dap_chain_net_srv_stream_session_t *) a_grace->usage->client->ch->stream->session->_inheritor;
-                char *l_unit_type_str = NULL;
-                switch(l_remain_service->remain_units_type.enm){
+                switch(l_tx_out_cond->subtype.srv_pay.unit.enm){
                     case SERV_UNIT_SEC:
-                        l_unit_type_str = dap_strdup_printf( "SEC");
-                        l_srv_session->limits_ts = l_remain_service->limits_ts;
-                        break;
-                    case SERV_UNIT_DAY:
-                        l_unit_type_str = dap_strdup_printf( "DAY");
                         l_srv_session->limits_ts = l_remain_service->limits_ts;
                         break;
-                    case SERV_UNIT_MB:
-                        l_unit_type_str = dap_strdup_printf( "MB");
-                        l_srv_session->limits_bytes = l_remain_service->limits_bytes;
-                        break;
-                    case SERV_UNIT_KB:
-                        l_unit_type_str = dap_strdup_printf( "KB");
-                        l_srv_session->limits_bytes = l_remain_service->limits_bytes;
-                        break;
                     case SERV_UNIT_B:
-                        l_unit_type_str = dap_strdup_printf( "B");
                         l_srv_session->limits_bytes = l_remain_service->limits_bytes;
                         break;
                 }
 
-                log_it(L_INFO, "User has %ld %s remain service. Start service without paying.", l_remain_service->limits_ts ? l_remain_service->limits_ts : l_remain_service->limits_bytes, l_unit_type_str);
-                DAP_DELETE(l_unit_type_str);
+                log_it(L_INFO, "User has %ld %s remain service. Start service without paying.", l_remain_service->limits_ts ? l_remain_service->limits_ts : l_remain_service->limits_bytes, dap_chain_srv_unit_enum_to_str(l_tx_out_cond->subtype.srv_pay.unit.enm));
 
                 size_t l_success_size = sizeof (dap_stream_ch_chain_net_srv_pkt_success_hdr_t );
                 dap_stream_ch_chain_net_srv_pkt_success_t *l_success = DAP_NEW_Z_SIZE(dap_stream_ch_chain_net_srv_pkt_success_t,
@@ -746,7 +766,7 @@ static void s_grace_period_start(dap_chain_net_srv_grace_t *a_grace)
                 DAP_DELETE(a_grace->request);
                 DAP_DELETE(a_grace);
                 DAP_DELETE(l_remain_service);
-                return;
+                return false;
             }
         }
 
@@ -762,32 +782,126 @@ static void s_grace_period_start(dap_chain_net_srv_grace_t *a_grace)
         DAP_DELETE(a_grace);
 
     }
+
+    return true;
+}
+
+/**
+ * @brief calculating used datoshi price by pricelist
+ * @param a_usage - usage data
+ * @param a_prev - prev value, calced add to prev
+ */
+uint256_t s_calc_datoshi(const dap_chain_net_srv_usage_t *a_usage, uint256_t *a_prev)
+{
+    uint256_t l_ret = {0}, l_prev = {0}, l_datosi_used = {0};
+    uint64_t l_used = 0;
+    if (a_prev)
+        l_prev = *a_prev;
+    dap_return_val_if_pass(!a_usage, l_prev);
+    switch(a_usage->price->units_uid.enm){
+        case SERV_UNIT_SEC:
+            l_used = dap_time_now() - a_usage->ts_created;
+            break;
+        case SERV_UNIT_B:
+            l_used = a_usage->client->bytes_received + a_usage->client->bytes_sent;
+            break;
+    }
+    MULT_256_256(a_usage->price->value_datoshi, GET_256_FROM_64(l_used), &l_ret);
+    DIV_256(l_ret, GET_256_FROM_64(a_usage->price->units), &l_datosi_used);
+    SUM_256_256(l_prev, l_datosi_used, &l_ret);
+    return l_ret;
+}
+
+/**
+ * @brief set usage data to local GDB group
+ * @param a_usage - usage data
+ */
+void s_set_usage_data_to_gdb(const dap_chain_net_srv_usage_t *a_usage)
+{
+// sanity check
+    dap_return_if_pass(!a_usage);
+// func work
+    client_statistic_key_t l_bin_key = {0};
+    client_statistic_value_t l_bin_value_new = {0};
+    size_t l_value_size = 0;
+    // forming key
+    dap_sprintf(l_bin_key.key, "0x%016"DAP_UINT64_FORMAT_X"", a_usage->service->uid.uint64);
+    dap_chain_hash_fast_to_str_do(&a_usage->client_pkey_hash, l_bin_key.key + 18);
+    // check writed value
+    client_statistic_value_t *l_bin_value = (client_statistic_value_t *)dap_global_db_get_sync(SRV_STATISTIC_GDB_GROUP, l_bin_key.key, &l_value_size, NULL, NULL);
+    if (l_bin_value && l_value_size != sizeof(client_statistic_value_t)) {
+        log_it(L_ERROR, "Wrong srv client_statistic size in GDB. Expecting %zu, getted %zu", sizeof(client_statistic_value_t), l_value_size);
+        //dap_global_db_set(SRV_STATISTIC_GDB_GROUP, l_bin_key.key, &l_bin_value_new, sizeof(client_statistic_value_t), false, NULL, NULL); value size update
+        DAP_DEL_Z(l_bin_value);
+        return;
+    }
+    if (l_bin_value) {
+        l_bin_value_new = *l_bin_value;
+    }
+    // forming new data
+    if (a_usage->is_grace) {
+        l_bin_value_new.grace.using_count += 1;
+        l_bin_value_new.grace.using_time += dap_time_now() - a_usage->ts_created;
+        l_bin_value_new.grace.bytes_received += a_usage->client->bytes_received;
+        l_bin_value_new.grace.bytes_sent += a_usage->client->bytes_sent;
+        l_bin_value_new.grace.datoshi_value = s_calc_datoshi(a_usage, l_bin_value ? &l_bin_value->grace.datoshi_value : NULL);
+    } else if (a_usage->is_free) {
+        l_bin_value_new.free.using_time += dap_time_now() - a_usage->ts_created;
+        l_bin_value_new.free.bytes_received += a_usage->client->bytes_received;
+        l_bin_value_new.free.bytes_sent += a_usage->client->bytes_sent;
+    } else if (a_usage->is_active) {
+        l_bin_value_new.payed.using_time += dap_time_now() - a_usage->ts_created;
+        l_bin_value_new.payed.bytes_received += a_usage->client->bytes_received;
+        l_bin_value_new.payed.bytes_sent += a_usage->client->bytes_sent;
+        l_bin_value_new.payed.datoshi_value = s_calc_datoshi(a_usage, l_bin_value ? &l_bin_value->payed.datoshi_value : NULL);
+    }
+    dap_global_db_set(SRV_STATISTIC_GDB_GROUP, l_bin_key.key, &l_bin_value_new, sizeof(client_statistic_value_t), false, NULL, NULL);
+
+    DAP_DEL_Z(l_bin_value);
 }
 
-static bool s_grace_period_finish(usages_in_grace_t *a_grace_item)
+static bool s_grace_period_finish(dap_chain_net_srv_grace_usage_t *a_grace_item)
 {
-    assert(a_grace_item);
+    dap_return_val_if_pass(!a_grace_item || !a_grace_item->grace, false);
     dap_stream_ch_chain_net_srv_pkt_error_t l_err = { };
     dap_chain_net_srv_grace_t *l_grace = a_grace_item->grace;
+    dap_chain_net_srv_t *l_srv = dap_chain_net_srv_get(l_grace->request->hdr.srv_uid);
+
+#define RET_WITH_DEL_A_GRACE(error) do \
+    {\
+        s_set_usage_data_to_gdb(l_grace->usage); \
+        if (error) { \
+            l_err.code = error ; \
+            s_grace_error(l_grace, l_err); \
+        } \
+        DAP_DELETE(a_grace_item); \
+        return false; \
+    } \
+    while(0);
 
-    dap_stream_ch_t *l_ch = dap_stream_ch_find_by_uuid_unsafe(l_grace->stream_worker, l_grace->ch_uuid);
+    pthread_mutex_lock(&l_srv->grace_mutex);
+    HASH_DEL(l_srv->grace_hash_tab, a_grace_item);
+    pthread_mutex_unlock(&l_srv->grace_mutex);
 
-#define RET_WITH_DEL_A_GRACE do \
-    { HASH_DEL(s_grace_table, a_grace_item); DAP_DELETE(a_grace_item); return false; } \
-    while(0);
+    dap_stream_ch_t *l_ch = dap_stream_ch_find_by_uuid_unsafe(l_grace->stream_worker, l_grace->ch_uuid);
 
-    if (!l_ch){
+    if (!l_ch || l_srv != l_grace->usage->service) {
+        l_err.code = !l_ch ? DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_SERVICE_NOT_FOUND : 
+                        DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_SERVICE_CH_NOT_FOUND;
         s_grace_error(l_grace, l_err);
-        RET_WITH_DEL_A_GRACE;
+        DAP_DELETE(a_grace_item); 
+        return false; 
     }
 
     if (l_grace->usage->is_waiting_new_tx_cond){
         log_it(L_INFO, "No new tx cond!");
-        s_grace_error(l_grace, l_err);
         l_grace->usage->is_waiting_new_tx_cond = false;
-        RET_WITH_DEL_A_GRACE;
+        RET_WITH_DEL_A_GRACE(DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NO_NEW_COND);
     }
 
+    bool l_waiting_new_tx_in_ledger = l_grace->usage->is_waiting_new_tx_cond_in_ledger;
+    l_grace->usage->is_waiting_new_tx_cond_in_ledger = false;
+
     dap_chain_net_t * l_net = l_grace->usage->net;
 
     l_err.net_id.uint64 = l_net->pub.id.uint64;
@@ -799,23 +913,17 @@ static bool s_grace_period_finish(usages_in_grace_t *a_grace_item)
 
     if ( !l_ledger ){ // No ledger
         log_it( L_WARNING, "No Ledger");
-        l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_NETWORK_NO_LEDGER ;
-        s_grace_error(l_grace, l_err);
-        RET_WITH_DEL_A_GRACE;
+        RET_WITH_DEL_A_GRACE(DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_NETWORK_NO_LEDGER);
     }
     log_it(L_INFO, "Grace period is over! Check tx in ledger.");
     l_tx = dap_ledger_tx_find_by_hash(l_ledger, &l_grace->usage->tx_cond_hash);
     if ( ! l_tx ){ // No tx cond transaction, start grace-period
         log_it( L_WARNING, "No tx cond transaction");
-        l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_FOUND ;
-        s_grace_error(l_grace, l_err);
-        RET_WITH_DEL_A_GRACE;
+        RET_WITH_DEL_A_GRACE(DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_FOUND);
     } else { // Start service in normal pay mode
         if (dap_chain_net_get_state(l_net) == NET_STATE_OFFLINE) {
             log_it(L_ERROR, "Can't pay service because net %s is offline.", l_net->pub.name);
-            l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_NETWORK_IS_OFFLINE;
-            s_grace_error(l_grace, l_err);
-            RET_WITH_DEL_A_GRACE;
+            RET_WITH_DEL_A_GRACE(DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_NETWORK_IS_OFFLINE);
         }
 
         log_it(L_INFO, "Tx is found in ledger.");
@@ -825,18 +933,14 @@ static bool s_grace_period_finish(usages_in_grace_t *a_grace_item)
 
         if ( ! l_tx_out_cond ) { // No conditioned output
             log_it( L_WARNING, "No conditioned output");
-            l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NO_COND_OUT ;
-            s_grace_error(l_grace, l_err);
-            RET_WITH_DEL_A_GRACE;
+            RET_WITH_DEL_A_GRACE(DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NO_COND_OUT);
         }
 
         // Check cond output if it equesl or not to request
         if (!dap_chain_net_srv_uid_compare(l_tx_out_cond->header.srv_uid, l_grace->usage->service->uid)) {
             log_it( L_WARNING, "Wrong service uid in request, tx expect to close its output with 0x%016"DAP_UINT64_FORMAT_X,
                    l_tx_out_cond->header.srv_uid.uint64 );
-            l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_WRONG_SRV_UID  ;
-            s_grace_error(l_grace, l_err);
-            RET_WITH_DEL_A_GRACE;
+            RET_WITH_DEL_A_GRACE(DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_WRONG_SRV_UID);
         }
 
         dap_chain_net_srv_price_t * l_price = NULL;
@@ -844,106 +948,53 @@ static bool s_grace_period_finish(usages_in_grace_t *a_grace_item)
         l_ticker = dap_ledger_tx_get_token_ticker_by_hash(l_ledger, &l_grace->usage->tx_cond_hash);
         dap_stpcpy(l_grace->usage->token_ticker, l_ticker);
 
-        if (dap_hash_fast_is_blank(&l_grace->usage->static_order_hash)){
-            dap_chain_net_srv_price_t *l_price_tmp;
-            DL_FOREACH(l_grace->usage->service->pricelist, l_price_tmp) {
-                if (!l_price_tmp){
-                    continue;
-                }
-
-                if (l_price_tmp->net->pub.id.uint64  != l_grace->usage->net->pub.id.uint64){
-                    log_it( L_WARNING, "Pricelist is not for net %s.", l_grace->usage->net->pub.name);
-                    continue;
-                }
-
-                if (dap_strcmp(l_price_tmp->token, l_ticker) != 0){
-                    log_it( L_WARNING, "Token ticker in the pricelist and tx do not match");
-                    continue;
-                }
-
-                if (l_price_tmp->units_uid.enm != l_tx_out_cond->subtype.srv_pay.unit.enm){
-                    log_it( L_WARNING, "Unit ID in the pricelist and tx do not match");
-                    continue;
-                }
-
-                uint256_t l_unit_price = {};
-                if (l_price_tmp->units != 0){
-                    DIV_256(l_price_tmp->value_datoshi, GET_256_FROM_64(l_price_tmp->units), &l_unit_price);
-                } else {
-                    log_it( L_WARNING, "Units in pricelist is zero. ");
-                    continue;
-                }
-
-                if(IS_ZERO_256(l_tx_out_cond->subtype.srv_pay.unit_price_max_datoshi) ||
-                    compare256(l_unit_price, l_tx_out_cond->subtype.srv_pay.unit_price_max_datoshi) <= 0){
-                    l_price = l_price_tmp;
-                    break;
-                } else {
-                    log_it( L_WARNING, "Unit price in pricelist is greater than max allowable.");
-                }
+        
+        char *l_order_hash_str = dap_chain_hash_fast_to_str_new(&l_grace->usage->static_order_hash);
+        log_it(L_MSG, "Using price from order %s.", l_order_hash_str);
+        DAP_DELETE(l_order_hash_str);
+        if ((l_price = l_grace->usage->price)){
+            if (l_price->net->pub.id.uint64  != l_grace->usage->net->pub.id.uint64){
+                log_it( L_WARNING, "Pricelist is not for net %s.", l_grace->usage->net->pub.name);
+                RET_WITH_DEL_A_GRACE(DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN);
             }
-        } else {
-            log_it(L_MSG, "Get price from order %s.",
-                dap_chain_hash_fast_to_str_static(&l_grace->usage->static_order_hash));
-            if ((l_price = dap_chain_net_srv_get_price_from_order(l_grace->usage->service, "srv_vpn", &l_grace->usage->static_order_hash))){
-                if (l_price->net->pub.id.uint64  != l_grace->usage->net->pub.id.uint64){
-                    log_it( L_WARNING, "Pricelist is not for net %s.", l_grace->usage->net->pub.name);
-                    l_err.code =DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN;
-                    s_grace_error(l_grace, l_err);
-                    RET_WITH_DEL_A_GRACE;
-                }
 
-                if (dap_strcmp(l_price->token, l_ticker) != 0){
-                    log_it( L_WARNING, "Token ticker in the pricelist and tx do not match");
-                    l_err.code =DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN;
-                    s_grace_error(l_grace, l_err);
-                    RET_WITH_DEL_A_GRACE;
-                }
+            if (dap_strcmp(l_price->token, l_ticker) != 0){
+                log_it( L_WARNING, "Token ticker in the pricelist and tx do not match");
+                RET_WITH_DEL_A_GRACE(DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN);
+            }
 
-                if (l_price->units_uid.enm != l_tx_out_cond->subtype.srv_pay.unit.enm){
-                    log_it( L_WARNING, "Unit ID in the pricelist and tx do not match");
-                    l_err.code =DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN;
-                    s_grace_error(l_grace, l_err);
-                    RET_WITH_DEL_A_GRACE;
-                }
+            if (l_price->units_uid.enm != l_tx_out_cond->subtype.srv_pay.unit.enm) {
+                log_it( L_WARNING, "Unit ID in the pricelist and tx do not match");
+                RET_WITH_DEL_A_GRACE(DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN);
+            }
 
-                uint256_t l_unit_price = {};
-                if (l_price->units != 0){
-                    DIV_256(l_price->value_datoshi, GET_256_FROM_64(l_price->units), &l_unit_price);
-                } else {
-                    log_it( L_WARNING, "Units in pricelist is zero. ");
-                    l_err.code =DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN;
-                    s_grace_error(l_grace, l_err);
-                    RET_WITH_DEL_A_GRACE;
-                }
+            uint256_t l_unit_price = {};
+            if (l_price->units != 0){
+                DIV_256(l_price->value_datoshi, GET_256_FROM_64(l_price->units), &l_unit_price);
+            } else {
+                log_it( L_WARNING, "Units in pricelist is zero. ");
+                RET_WITH_DEL_A_GRACE(DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN);
+            }
 
-                if(IS_ZERO_256(l_tx_out_cond->subtype.srv_pay.unit_price_max_datoshi) ||
-                    compare256(l_unit_price, l_tx_out_cond->subtype.srv_pay.unit_price_max_datoshi) <= 0){
-                } else {
-                    log_it( L_WARNING, "Unit price in pricelist is greater than max allowable.");
-                    l_err.code =DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN;
-                    s_grace_error(l_grace, l_err);
-                    RET_WITH_DEL_A_GRACE;
-                }
+            if(IS_ZERO_256(l_tx_out_cond->subtype.srv_pay.unit_price_max_datoshi) ||
+                compare256(l_unit_price, l_tx_out_cond->subtype.srv_pay.unit_price_max_datoshi) <= 0){
+            } else {
+                log_it( L_WARNING, "Unit price in pricelist is greater than max allowable.");
+                RET_WITH_DEL_A_GRACE(DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN);
             }
         }
 
+
         if ( !l_price ) {
             log_it( L_WARNING, "Request can't be processed because no acceptable price in pricelist for token %s in network %s",
                    l_ticker, l_net->pub.name );
-            l_err.code =DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN;
-            s_grace_error(l_grace, l_err);
-            RET_WITH_DEL_A_GRACE;
+            RET_WITH_DEL_A_GRACE(DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN);
         }
 
-        l_grace->usage->price = l_price;
-
         int ret;
         if ((ret = l_grace->usage->service->callbacks.requested(l_grace->usage->service, l_grace->usage->id, l_grace->usage->client, l_grace->request, l_grace->request_size)) != 0) {
             log_it( L_WARNING, "Request canceled by service callback, return code %d", ret);
-            l_err.code = (uint32_t) ret ;
-            s_grace_error(l_grace, l_err);
-            RET_WITH_DEL_A_GRACE;
+            RET_WITH_DEL_A_GRACE((uint32_t) ret);
         }
 
         if (!l_grace->usage->receipt){
@@ -951,36 +1002,19 @@ static bool s_grace_period_finish(usages_in_grace_t *a_grace_item)
             dap_stream_ch_chain_net_srv_remain_service_store_t* l_remain_service = NULL;
             l_remain_service = l_grace->usage->service->callbacks.get_remain_service(l_grace->usage->service, l_grace->usage->id, l_grace->usage->client);
             if (l_remain_service && !l_grace->usage->is_active &&
-                (l_remain_service->limits_ts || l_remain_service->limits_bytes) &&
-                l_remain_service->remain_units_type.enm == l_tx_out_cond->subtype.srv_pay.unit.enm){
+                ((l_remain_service->limits_ts && l_tx_out_cond->subtype.srv_pay.unit.enm == SERV_UNIT_SEC)  || 
+                (l_remain_service->limits_bytes && l_tx_out_cond->subtype.srv_pay.unit.enm == SERV_UNIT_B))){
                 // Accept connection, set limits and start service
                 dap_chain_net_srv_stream_session_t * l_srv_session = (dap_chain_net_srv_stream_session_t *) l_grace->usage->client->ch->stream->session->_inheritor;
-                char *l_unit_type_str = NULL;
-                switch(l_remain_service->remain_units_type.enm){
+                switch(l_tx_out_cond->subtype.srv_pay.unit.enm){
                     case SERV_UNIT_SEC:
-                        l_unit_type_str = dap_strdup_printf( "SEC");
-                        l_srv_session->limits_ts = l_remain_service->limits_ts;
-                        break;
-                    case SERV_UNIT_DAY:
-                        l_unit_type_str = dap_strdup_printf( "DAY");
                         l_srv_session->limits_ts = l_remain_service->limits_ts;
                         break;
-                    case SERV_UNIT_MB:
-                        l_unit_type_str = dap_strdup_printf( "MB");
-                        l_srv_session->limits_bytes = l_remain_service->limits_bytes;
-                        break;
-                    case SERV_UNIT_KB:
-                        l_unit_type_str = dap_strdup_printf( "KB");
-                        l_srv_session->limits_bytes = l_remain_service->limits_bytes;
-                        break;
                     case SERV_UNIT_B:
-                        l_unit_type_str = dap_strdup_printf( "B");
                         l_srv_session->limits_bytes = l_remain_service->limits_bytes;
                         break;
                 }
-
-                log_it(L_INFO, "User has %ld %s remain service. Start service without paying.", l_remain_service->limits_ts ? l_remain_service->limits_ts : l_remain_service->limits_bytes, l_unit_type_str);
-                DAP_DELETE(l_unit_type_str);
+                log_it(L_INFO, "User has %ld %s remain service. Start service without paying.", l_remain_service->limits_ts ? l_remain_service->limits_ts : l_remain_service->limits_bytes, dap_chain_srv_unit_enum_to_str(l_tx_out_cond->subtype.srv_pay.unit.enm));
 
                 size_t l_success_size = sizeof (dap_stream_ch_chain_net_srv_pkt_success_hdr_t );
                 dap_stream_ch_chain_net_srv_pkt_success_t *l_success = DAP_NEW_Z_SIZE(dap_stream_ch_chain_net_srv_pkt_success_t,
@@ -1008,12 +1042,9 @@ static bool s_grace_period_finish(usages_in_grace_t *a_grace_item)
                                                                             sizeof(dap_chain_datum_tx_receipt_t) + l_grace->usage->receipt->size + l_grace->usage->receipt->exts_size);
                     DAP_DELETE(l_success);
                 }
-                DAP_DELETE(l_grace->request);
                 DAP_DELETE(l_grace);
                 DAP_DELETE(l_remain_service);
-                HASH_DEL(s_grace_table, a_grace_item);
-                DAP_DELETE(a_grace_item);
-                return false;
+                RET_WITH_DEL_A_GRACE(0);
             }
         }
 
@@ -1027,14 +1058,19 @@ static bool s_grace_period_finish(usages_in_grace_t *a_grace_item)
         } else {
             log_it(L_INFO, "Send first receipt to sign");
             l_grace->usage->receipt = dap_chain_net_srv_issue_receipt(l_grace->usage->service, l_grace->usage->price, NULL, 0);
-            dap_stream_ch_pkt_write_unsafe(l_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_REQUEST,
+            if (l_grace->usage->receipt )
+                dap_stream_ch_pkt_write_unsafe(l_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_REQUEST,
                                        l_grace->usage->receipt, l_grace->usage->receipt->size);
-            RET_WITH_DEL_A_GRACE;
+            else{
+                log_it(L_WARNING, "Can't sign the receipt.");
+                RET_WITH_DEL_A_GRACE(DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_UNDEFINED);
+            }
+
+            RET_WITH_DEL_A_GRACE(0);
         }
         if (!l_receipt) {
             log_it(L_ERROR, "Receipt is not present, finish grace");
-            s_grace_error(l_grace, l_err);
-            RET_WITH_DEL_A_GRACE;
+            RET_WITH_DEL_A_GRACE(DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_RECEIPT_IS_NOT_PRESENT);
         }
         size_t l_receipt_size = l_receipt->size;
 
@@ -1042,11 +1078,10 @@ static bool s_grace_period_finish(usages_in_grace_t *a_grace_item)
         dap_sign_t * l_receipt_sign = dap_chain_datum_tx_receipt_sign_get( l_receipt, l_receipt_size, 1);
         if ( ! l_receipt_sign ){
             log_it(L_WARNING, "Tx already in chain, but receipt is not signed by client. Finish grace and wait receipt sign responce.");
-            s_grace_error(l_grace, l_err);
-            RET_WITH_DEL_A_GRACE;
+            RET_WITH_DEL_A_GRACE(DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_RECEIPT_NO_SIGN);
         }
         dap_get_data_hash_str_static(l_receipt, l_receipt_size, l_receipt_hash_str);
-        dap_global_db_set("local.receipts", l_receipt_hash_str, l_receipt, l_receipt_size, false, NULL, NULL);
+        dap_global_db_set(SRV_RECEIPTS_GDB_GROUP, l_receipt_hash_str, l_receipt, l_receipt_size, false, NULL, NULL);
             // Form input transaction
         char *l_hash_str = dap_hash_fast_to_str_new(&l_grace->usage->tx_cond_hash);
         log_it(L_NOTICE, "Trying create input tx cond from tx %s with active receipt", l_hash_str);
@@ -1055,31 +1090,28 @@ static bool s_grace_period_finish(usages_in_grace_t *a_grace_item)
         char *l_tx_in_hash_str = dap_chain_mempool_tx_create_cond_input(l_grace->usage->net, &l_grace->usage->tx_cond_hash, l_grace->usage->price->wallet_addr,
                                                                         l_grace->usage->price->receipt_sign_cert->enc_key,
                                                                         l_receipt, "hex", &ret_status);
-//        DAP_DEL_Z(l_wallet_addr);
         if (!ret_status) {
             dap_chain_hash_fast_from_str(l_tx_in_hash_str, &l_grace->usage->tx_cond_hash);
             log_it(L_NOTICE, "Formed tx %s for input with active receipt", l_tx_in_hash_str);
             DAP_DELETE(l_tx_in_hash_str);
-
-        }else{
+        } else {
             if(ret_status == DAP_CHAIN_MEMPOOl_RET_STATUS_NOT_ENOUGH){
-//                memset(&l_grace->usage->tx_cond_hash, 0, sizeof(l_grace->usage->tx_cond_hash));
-//                DAP_DEL_Z(l_grace->usage->receipt_next);
                 log_it(L_ERROR, "Tx cond have not enough funds");
+                if (l_waiting_new_tx_in_ledger){
+                    log_it(L_ERROR, "New tx cond have not enough funds. Waiting for end of service.");
+                    RET_WITH_DEL_A_GRACE(DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_NEW_TX_COND_NOT_ENOUGH);
+                }
+
                 dap_chain_net_srv_grace_t* l_grace_new = DAP_NEW_Z(dap_chain_net_srv_grace_t);
                 if (!l_grace_new) {
                     log_it(L_CRITICAL, "Memory allocation error");
-                    DAP_DELETE(a_grace_item->grace->request);
-                    DAP_DEL_Z(a_grace_item->grace);
-                    RET_WITH_DEL_A_GRACE;
+                    RET_WITH_DEL_A_GRACE(0);
                 }
                 // Parse the request
                 l_grace_new->request = DAP_NEW_Z_SIZE(dap_stream_ch_chain_net_srv_pkt_request_t, sizeof(dap_stream_ch_chain_net_srv_pkt_request_t));
                 if (!l_grace_new->request) {
                     log_it(L_CRITICAL, "Memory allocation error");
-                    DAP_DELETE(a_grace_item->grace->request);
-                    DAP_DEL_Z(a_grace_item->grace);
-                    RET_WITH_DEL_A_GRACE;
+                    RET_WITH_DEL_A_GRACE(0);
                 }
                 l_grace_new->request->hdr.net_id = a_grace_item->grace->usage->net->pub.id;
                 dap_stpcpy(l_grace_new->request->hdr.token, a_grace_item->grace->usage->token_ticker);
@@ -1090,17 +1122,16 @@ static bool s_grace_period_finish(usages_in_grace_t *a_grace_item)
                 l_grace_new->stream_worker = a_grace_item->grace->usage->client->ch->stream_worker;
                 l_grace_new->usage = a_grace_item->grace->usage;
                 l_grace_new->usage->is_waiting_new_tx_cond = true;
-                s_grace_period_start(l_grace_new);
 
-                l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ENOUGH;
-                dap_stream_ch_pkt_write_unsafe(l_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err));
-                if (l_grace->usage->service->callbacks.response_error)
+                if (s_grace_period_start(l_grace_new)){
+                    l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ENOUGH;
+                    dap_stream_ch_pkt_write_unsafe(l_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err));
+                    if (l_grace->usage->service->callbacks.response_error)
                         l_grace->usage->service->callbacks.response_error(l_grace->usage->service,l_grace->usage->id, l_grace->usage->client,&l_err,sizeof (l_err));
+                }
                 DAP_DELETE(l_tx_in_hash_str);
-                DAP_DELETE(a_grace_item->grace->request);
-                DAP_DEL_Z(a_grace_item->grace);
-                RET_WITH_DEL_A_GRACE;
-            }else{
+                RET_WITH_DEL_A_GRACE(0);
+            } else {
                 log_it(L_ERROR, "Can't create input tx cond transaction!");
                 memset(&l_grace->usage->tx_cond_hash, 0, sizeof(l_grace->usage->tx_cond_hash));
                 if (l_grace->usage->receipt_next){
@@ -1117,9 +1148,7 @@ static bool s_grace_period_finish(usages_in_grace_t *a_grace_item)
         }
     }
     l_grace->usage->is_grace = false;
-    DAP_DELETE(a_grace_item->grace->request);
-    DAP_DEL_Z(a_grace_item->grace);
-    RET_WITH_DEL_A_GRACE;
+    RET_WITH_DEL_A_GRACE(0);
 #undef RET_WITH_DEL_A_GRACE
 }
 
@@ -1324,7 +1353,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
         // Store receipt if any problems with transactions
         char *l_receipt_hash_str;
         dap_get_data_hash_str_static(l_receipt, l_receipt_size, l_receipt_hash_str);
-        dap_global_db_set("local.receipts", l_receipt_hash_str, l_receipt, l_receipt_size, false, NULL, NULL);
+        dap_global_db_set(SRV_RECEIPTS_GDB_GROUP, l_receipt_hash_str, l_receipt, l_receipt_size, false, NULL, NULL);
         size_t l_success_size;
         if (!l_usage->is_grace) {
             // Form input transaction
@@ -1340,7 +1369,6 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                 log_it(L_NOTICE, "Formed tx %s for input with active receipt", l_tx_in_hash_str);
                 DAP_DELETE(l_tx_in_hash_str);
             }else{
-                // TODO add ret status handling/ if tx not found start grace again
                 dap_chain_net_srv_grace_t *l_grace = NULL;
                 switch(ret_status){
                 case DAP_CHAIN_MEMPOOl_RET_STATUS_CANT_FIND_FINAL_TX_HASH:
@@ -1399,11 +1427,12 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                     l_grace->ch_uuid = a_ch->uuid;
                     l_grace->stream_worker = a_ch->stream_worker;
                     l_grace->usage = l_usage;
-                    s_grace_period_start(l_grace);
-                    l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ENOUGH;
-                    dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err));
-                    if (l_usage->service->callbacks.response_error)
-                            l_usage->service->callbacks.response_error(l_usage->service,l_usage->id, l_usage->client,&l_err,sizeof (l_err));
+                    if (s_grace_period_start(l_grace)){
+                        l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ENOUGH;
+                        dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err));
+                        if (l_usage->service->callbacks.response_error)
+                                l_usage->service->callbacks.response_error(l_usage->service,l_usage->id, l_usage->client,&l_err,sizeof (l_err));
+                        }
                     DAP_DELETE(l_tx_in_hash_str);
                     break;
                 case DAP_CHAIN_MEMPOOL_RET_STATUS_BAD_ARGUMENTS:
@@ -1523,16 +1552,18 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
         }
 
         l_usage->is_waiting_new_tx_cond = false;
+        l_usage->is_waiting_new_tx_cond_in_ledger = true;
         dap_stream_ch_chain_net_srv_pkt_error_t l_err = { };
-        usages_in_grace_t *l_curr_grace_item = NULL;
-        pthread_mutex_lock(&s_ht_grace_table_mutex);
-        HASH_FIND(hh, s_grace_table, &l_usage->tx_cond_hash, sizeof(dap_hash_fast_t), l_curr_grace_item);
-        pthread_mutex_unlock(&s_ht_grace_table_mutex);
+        dap_chain_net_srv_t *l_srv = dap_chain_net_srv_get(l_responce->hdr.srv_uid);
+        dap_chain_net_srv_grace_usage_t *l_curr_grace_item = NULL;
+        pthread_mutex_lock(&l_srv->grace_mutex);
+        HASH_FIND(hh, l_srv->grace_hash_tab, &l_usage->tx_cond_hash, sizeof(dap_hash_fast_t), l_curr_grace_item);
+        pthread_mutex_unlock(&l_srv->grace_mutex);
 
         if (dap_hash_fast_is_blank(&l_responce->hdr.tx_cond)){ //if new tx cond creation failed tx_cond in responce will be blank
             if (l_curr_grace_item){
-                HASH_DEL(s_grace_table, l_curr_grace_item);
-                dap_timerfd_delete_mt(l_curr_grace_item->grace->stream_worker->worker, l_curr_grace_item->grace->timer_es_uuid);
+                HASH_DEL(l_srv->grace_hash_tab, l_curr_grace_item);
+                dap_timerfd_delete_mt(l_curr_grace_item->grace->timer->worker, l_curr_grace_item->grace->timer->esocket_uuid);
                 s_grace_error(l_curr_grace_item->grace, l_err);
                 DAP_DEL_Z(l_curr_grace_item);
             }
@@ -1545,7 +1576,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
             if (l_curr_grace_item){
                 log_it(L_INFO, "Found tx in ledger by net tx responce handler. Finish waiting new tx grace period.");
                 // Stop timer
-                dap_timerfd_delete_mt(l_curr_grace_item->grace->stream_worker->worker, l_curr_grace_item->grace->timer_es_uuid);
+                dap_timerfd_delete_mt(l_curr_grace_item->grace->timer->worker, l_curr_grace_item->grace->timer->esocket_uuid);
                 // finish grace
                 l_usage->tx_cond_hash = l_responce->hdr.tx_cond;
                 l_curr_grace_item->grace->request->hdr.tx_cond = l_responce->hdr.tx_cond;
@@ -1555,11 +1586,11 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
             if (l_curr_grace_item){
                 l_curr_grace_item->grace->usage->tx_cond_hash = l_responce->hdr.tx_cond;
                 l_curr_grace_item->grace->request->hdr.tx_cond = l_responce->hdr.tx_cond;
-                pthread_mutex_lock(&s_ht_grace_table_mutex);
-                HASH_DEL(s_grace_table, l_curr_grace_item);
+                pthread_mutex_lock(&l_srv->grace_mutex);
+                HASH_DEL(l_srv->grace_hash_tab, l_curr_grace_item);
                 l_curr_grace_item->tx_cond_hash = l_responce->hdr.tx_cond;
-                HASH_ADD(hh, s_grace_table, tx_cond_hash, sizeof(dap_hash_fast_t), l_curr_grace_item);
-                pthread_mutex_unlock(&s_ht_grace_table_mutex);
+                HASH_ADD(hh, l_srv->grace_hash_tab, tx_cond_hash, sizeof(dap_hash_fast_t), l_curr_grace_item);
+                pthread_mutex_unlock(&l_srv->grace_mutex);
             }
         }
 
@@ -1590,8 +1621,6 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
  */
 static bool s_stream_ch_packet_out(dap_stream_ch_t* a_ch , void* a_arg)
 {
-    (void) a_arg;
-
     dap_stream_ch_set_ready_to_write_unsafe(a_ch, false);
     // Callback should note that after write action it should restore write flag if it has more data to send on next iteration
     dap_chain_net_srv_call_write_all( a_ch);
diff --git a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.h b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.h
deleted file mode 100644
index 18d3f1a112..0000000000
--- a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Authors:
- * Alexander Lysikov <alexander.lysikov@demlabs.net>
- * Cellframe       https://cellframe.net
- * DeM Labs Inc.   https://demlabs.net
- * Copyright  (c) 2020
- * All rights reserved.
-
- This file is part of CellFrame SDK the open source project
-
- CellFrame SDK is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- CellFrame SDK is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-#include <pthread.h>
-#include "dap_stream_worker.h"
-#include "dap_stream_ch_pkt.h"
-#include "dap_chain_common.h"
-
-#include "dap_chain.h"
-#include "dap_chain_datum_tx.h"
-#include "dap_chain_datum_tx_in.h"
-#include "dap_chain_datum_tx_in_cond.h"
-#include "dap_chain_datum_tx_out.h"
-#include "dap_chain_datum_tx_out_cond.h"
-#include "dap_chain_datum_tx_receipt.h"
-#include "dap_chain_mempool.h"
-#include "dap_common.h"
-
-typedef struct dap_stream_ch_chain_net_srv dap_stream_ch_chain_net_srv_t;
-
-typedef void (*dap_stream_ch_chain_net_srv_callback_packet_t)(dap_stream_ch_chain_net_srv_t *, uint8_t,
-        dap_stream_ch_pkt_t *, void *);
-
-typedef struct dap_stream_ch_chain_net_srv {
-    dap_chain_net_srv_uid_t srv_uid;
-    dap_stream_ch_t *ch;
-    dap_stream_ch_uuid_t ch_uuid;
-    dap_stream_ch_chain_net_srv_callback_packet_t notify_callback;
-    void *notify_callback_arg;
-} dap_stream_ch_chain_net_srv_t;
-
-#define DAP_STREAM_CH_CHAIN_NET_SRV(a) ((dap_stream_ch_chain_net_srv_t *) ((a)->internal) )
-#define DAP_STREAM_CH_NET_SRV_ID 'R'
-
-int dap_stream_ch_chain_net_srv_init(void);
-
-void dap_stream_ch_chain_net_srv_tx_cond_added_cb(void *a_arg, dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx);
diff --git a/modules/channel/chain-net-srv/include/dap_stream_ch_chain_net_srv.h b/modules/channel/chain-net-srv/include/dap_stream_ch_chain_net_srv.h
index 637939a8ff..7f1970fb4f 100644
--- a/modules/channel/chain-net-srv/include/dap_stream_ch_chain_net_srv.h
+++ b/modules/channel/chain-net-srv/include/dap_stream_ch_chain_net_srv.h
@@ -1,33 +1,62 @@
 /*
  * Authors:
- * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * Alexander Lysikov <alexander.lysikov@demlabs.net>
+ * Cellframe       https://cellframe.net
  * DeM Labs Inc.   https://demlabs.net
- * CellFrame       https://cellframe.net
- * Sources         https://gitlab.demlabs.net/cellframe
- * Copyright  (c) 2017-2019
+ * Copyright  (c) 2020
  * All rights reserved.
 
- This file is part of DAP (Demlabs Application Protocol) the open source project
+ This file is part of CellFrame SDK the open source project
 
-    DAP (Demlabs Application Protocol) is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
+ CellFrame SDK is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
 
-    DAP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
+ CellFrame SDK is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
 
-    You should have received a copy of the GNU General Public License
-    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
-*/
+ You should have received a copy of the GNU General Public License
+ along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+ */
 
 #pragma once
 
+#include <pthread.h>
+#include "dap_stream_worker.h"
+#include "dap_stream_ch_pkt.h"
 #include "dap_chain_common.h"
 
-int dap_stream_ch_chain_net_srv_init(void);
-void dap_stream_ch_chain_net_srv_deinit(void);
-
-void dap_stream_ch_chain_net_srv_set_srv_uid(dap_stream_ch_t* a_ch, dap_chain_net_srv_uid_t a_srv_uid);
+#include "dap_chain.h"
+#include "dap_chain_datum_tx.h"
+#include "dap_chain_datum_tx_in.h"
+#include "dap_chain_datum_tx_in_cond.h"
+#include "dap_chain_datum_tx_out.h"
+#include "dap_chain_datum_tx_out_cond.h"
+#include "dap_chain_datum_tx_receipt.h"
+#include "dap_chain_mempool.h"
+#include "dap_common.h"
+#include "dap_chain_net_srv.h"
+
+typedef struct dap_stream_ch_chain_net_srv dap_stream_ch_chain_net_srv_t;
+
+typedef void (*dap_stream_ch_chain_net_srv_callback_packet_t)(dap_stream_ch_chain_net_srv_t *, uint8_t,
+        dap_stream_ch_pkt_t *, void *);
+
+typedef struct dap_stream_ch_chain_net_srv {
+    dap_chain_net_srv_uid_t srv_uid;
+    dap_stream_ch_t *ch;
+    dap_stream_ch_uuid_t ch_uuid;
+    dap_stream_ch_chain_net_srv_callback_packet_t notify_callback;
+    void *notify_callback_arg;
+} dap_stream_ch_chain_net_srv_t;
+
+#define DAP_STREAM_CH_CHAIN_NET_SRV(a) ((dap_stream_ch_chain_net_srv_t *) ((a)->internal) )
+#define DAP_STREAM_CH_NET_SRV_ID 'R'
+
+int dap_stream_ch_chain_net_srv_init(dap_chain_net_srv_t *a_srv);
+
+void dap_stream_ch_chain_net_srv_tx_cond_added_cb(void *a_arg, dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx);
+char *dap_stream_ch_chain_net_srv_create_statistic_report();
diff --git a/modules/channel/chain-net/dap_stream_ch_chain_net.c b/modules/channel/chain-net/dap_stream_ch_chain_net.c
index b2c9a96cd9..831f04a10e 100644
--- a/modules/channel/chain-net/dap_stream_ch_chain_net.c
+++ b/modules/channel/chain-net/dap_stream_ch_chain_net.c
@@ -190,7 +190,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t *a_ch, void* a_arg)
                 dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
                 log_it(L_ERROR, "Invalid net id in packet");
             } else {
-                dap_chain_net_srv_order_t * l_orders = NULL;
+                dap_list_t * l_orders = NULL;
                 dap_enc_key_t * enc_key_pvt = NULL;
                 dap_chain_t *l_chain = NULL;
                 DL_FOREACH(l_net->pub.chains, l_chain)
@@ -236,20 +236,18 @@ void s_stream_ch_packet_in(dap_stream_ch_t *a_ch, void* a_arg)
                 //strncpy(send->header.data,(uint8_t*)l_ch_chain_net_pkt->data,10);
                 flags = (l_net->pub.mempool_autoproc) ? flags | A_PROC : flags & ~A_PROC;
 
-                dap_chain_net_srv_order_find_all_by(l_net,SERV_DIR_UNDEFINED,l_uid,
-                                                   l_price_unit,NULL,l_price_min,l_price_max,&l_orders,&l_orders_num);
-                size_t l_orders_size = 0;
-                for (size_t i = 0; i< l_orders_num; i++){
-                    dap_chain_net_srv_order_t *l_order =(dap_chain_net_srv_order_t *) (((byte_t*) l_orders) + l_orders_size);
-                    l_orders_size += dap_chain_net_srv_order_get_size(l_order);
-                    if(l_order->node_addr.uint64 == l_cur_node_addr.uint64)
-                    {
-                        flags = flags | F_ORDR;
-                        break;
+                if (dap_chain_net_srv_order_find_all_by(l_net,SERV_DIR_UNDEFINED,l_uid,
+                                                    l_price_unit,NULL,l_price_min,l_price_max,&l_orders,&l_orders_num)==0){
+                    for (dap_list_t *l_temp = l_orders;l_temp; l_temp = l_orders->next){
+                        dap_chain_net_srv_order_t *l_order =(dap_chain_net_srv_order_t *) l_temp->data;
+                        if(l_order->node_addr.uint64 == l_cur_node_addr.uint64)
+                        {
+                            flags = flags | F_ORDR;
+                            break;
+                        }
                     }
+                    dap_list_free_full(l_orders, NULL);
                 }
-                if (l_orders_num)
-                    DAP_DELETE(l_orders);
                 bool auto_online = dap_config_get_item_bool_default( g_config, "general", "auto_online", false );
                 bool auto_update = false;
                 if((system("systemctl status cellframe-updater.service") == 768) && (system("systemctl status cellframe-updater.timer") == 0))
diff --git a/modules/common/dap_chain_datum.c b/modules/common/dap_chain_datum.c
index b5e90e48a0..1dbb358441 100644
--- a/modules/common/dap_chain_datum.c
+++ b/modules/common/dap_chain_datum.c
@@ -839,7 +839,6 @@ void dap_chain_datum_dump(dap_string_t *a_str_out, dap_chain_datum_t *a_datum, c
                 {
                     log_it(L_ERROR, "Illformed DATUM type %d, TSD section is out-of-buffer (%" DAP_UINT64_FORMAT_U " vs %zu)",
                         l_emission->hdr.type, l_emission->data.type_auth.tsd_total_size, l_emission_size);
-
                     dap_string_append_printf(a_str_out, "  Skip incorrect or illformed DATUM");
                     break;
                 }
diff --git a/modules/common/include/dap_chain_common.h b/modules/common/include/dap_chain_common.h
index d07547d443..fe9cebf3cc 100644
--- a/modules/common/include/dap_chain_common.h
+++ b/modules/common/include/dap_chain_common.h
@@ -126,10 +126,7 @@ extern const dap_chain_addr_t c_dap_chain_addr_blank;
 
 enum dap_chain_srv_unit_enum {
     SERV_UNIT_UNDEFINED = 0 ,
-    SERV_UNIT_MB = 0x00000001, // megabytes
     SERV_UNIT_SEC = 0x00000002, // seconds
-    SERV_UNIT_DAY = 0x00000003,  // days
-    SERV_UNIT_KB = 0x00000010,  // kilobytes
     SERV_UNIT_B = 0x00000011,   // bytes
     SERV_UNIT_PCS = 0x00000022  // pieces
 };
@@ -138,28 +135,19 @@ typedef uint32_t dap_chain_srv_unit_enum_t;
 DAP_STATIC_INLINE const char *dap_chain_srv_unit_enum_to_str(dap_chain_srv_unit_enum_t a_unit_enum)
 {
     switch (a_unit_enum) {
-    case SERV_UNIT_UNDEFINED: return "SERV_UNIT_UNDEFINED";
-    case SERV_UNIT_MB: return "SERV_UNIT_MB";
-    case SERV_UNIT_SEC: return "SERV_UNIT_SEC";
-    case SERV_UNIT_DAY: return "SERV_UNIT_DAY";
-    case SERV_UNIT_KB: return "SERV_UNIT_KB";
-    case SERV_UNIT_B: return "SERV_UNIT_B";
-    case SERV_UNIT_PCS: return "SERV_UNIT_PCS";
+    case SERV_UNIT_UNDEFINED: return "UNDEFINED";
+    case SERV_UNIT_SEC: return "SEC";
+    case SERV_UNIT_B: return "B";
+    case SERV_UNIT_PCS: return "PCS";
     default: return "UNDEFINED";
     }
 }
 
-DAP_STATIC_INLINE dap_chain_srv_unit_enum_t dap_chain_srv_str_to_unit_enum(char* a_price_unit_str) {
+DAP_STATIC_INLINE dap_chain_srv_unit_enum_t dap_chain_srv_str_to_unit_enum(const char* a_price_unit_str) {
     if (!a_price_unit_str)
         return SERV_UNIT_UNDEFINED;
-    if (!dap_strcmp(a_price_unit_str, "MB")){
-        return SERV_UNIT_MB;
-    } else if (!dap_strcmp(a_price_unit_str, "SEC")){
+    if (!dap_strcmp(a_price_unit_str, "SEC")){
         return SERV_UNIT_SEC;
-    } else if (!dap_strcmp(a_price_unit_str, "DAY")){
-        return SERV_UNIT_DAY;
-    } else if (!dap_strcmp(a_price_unit_str, "KB")){
-        return SERV_UNIT_KB;
     } else if (!dap_strcmp(a_price_unit_str, "B")){
         return SERV_UNIT_B;
     } else if (!dap_strcmp(a_price_unit_str, "PCS")){
diff --git a/modules/net/dap_chain_ledger.c b/modules/net/dap_chain_ledger.c
index 3a6bc21aea..67264de681 100644
--- a/modules/net/dap_chain_ledger.c
+++ b/modules/net/dap_chain_ledger.c
@@ -5936,12 +5936,10 @@ const char *dap_ledger_tx_get_main_ticker(dap_ledger_t *a_ledger, dap_chain_datu
 {
     const char *l_main_ticker = NULL;
     dap_chain_hash_fast_t * l_tx_hash = dap_chain_node_datum_tx_calc_hash(a_tx);
-    int l_rc = dap_ledger_tx_cache_check(a_ledger, a_tx, l_tx_hash, false, NULL, NULL, (char **)&l_main_ticker);
-    
+    int l_rc = dap_ledger_tx_cache_check(a_ledger, a_tx, l_tx_hash, false, NULL, NULL, (char **)&l_main_ticker);   
+
     if (l_rc == DAP_LEDGER_TX_ALREADY_CACHED)
-    {
         l_main_ticker = dap_ledger_tx_get_token_ticker_by_hash(a_ledger, l_tx_hash);
-    }
 
     if (a_ledger_rc)
         *a_ledger_rc = l_rc;
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index c8b0298dc2..05e8dc7b92 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -1755,8 +1755,8 @@ static int s_cli_net(int argc, char **argv, void **reply)
                                                "Can't save public key hash %s in database", l_hash_hex_str);
                         DAP_DELETE(l_hash_hex_str);
                         return DAP_CHAIN_NET_JSON_RPC_CAN_NOT_SAVE_PUBLIC_KEY_IN_DATABASE;
-                    }
-                    DAP_DELETE(l_hash_hex_str);
+                    } else
+                        DAP_DELETE(l_hash_hex_str);
                 } else{
                     json_object_put(l_jobj_return);
                     dap_json_rpc_error_add(DAP_CHAIN_NET_JSON_RPC_CAN_NOT_SAVE_PUBLIC_KEY_IN_DATABASE, "%s",
diff --git a/modules/net/dap_chain_net_voting.c b/modules/net/dap_chain_net_voting.c
index 590e07e9a2..ad54206ed9 100644
--- a/modules/net/dap_chain_net_voting.c
+++ b/modules/net/dap_chain_net_voting.c
@@ -296,6 +296,7 @@ bool s_datum_tx_voting_verification_callback(dap_ledger_t *a_ledger, dap_chain_t
                 *(bool*)((byte_t*)l_voting->voting_params.voting_tx + l_voting->voting_params.delegate_key_required_offset)){
                 if (!dap_chain_net_srv_stake_check_pkey_hash(&pkey_hash)){
                     log_it(L_ERROR, "The voting required a delegated key.");
+                    dap_list_free(l_signs_list);
                     return false;
                 }
             }
@@ -336,6 +337,7 @@ bool s_datum_tx_voting_verification_callback(dap_ledger_t *a_ledger, dap_chain_t
                 }
                 l_temp = l_temp->next;
             }
+            dap_list_free(l_signs_list);
         }
 
         uint256_t l_weight = {};
@@ -422,6 +424,7 @@ bool s_datum_tx_voting_verification_callback(dap_ledger_t *a_ledger, dap_chain_t
             dap_chain_net_vote_t *l_vote_item = DAP_NEW_Z(dap_chain_net_vote_t);
             if (!l_vote_item){
                 log_it(L_CRITICAL, "Memory allocate_error!");
+                dap_list_free(l_signs_list);
                 return false;
             }
             l_vote_item->vote_hash = l_hash;
@@ -438,15 +441,18 @@ bool s_datum_tx_voting_verification_callback(dap_ledger_t *a_ledger, dap_chain_t
                         l_voting->votes = dap_list_append(l_voting->votes, l_vote_item);
 
                         log_it(L_ERROR, "Vote is changed.");
+                        dap_list_free(l_signs_list);
                         return true;
                     } else {
                         log_it(L_ERROR, "The voting don't allow change your vote.");
+                        dap_list_free(l_signs_list);
                         DAP_DELETE(l_vote_item);
                         return false;
                     }
                 }
                 l_temp = l_temp->next;
             }
+            dap_list_free(l_signs_list);
             log_it(L_INFO, "Vote is accepted.");
             l_voting->votes = dap_list_append(l_voting->votes, l_vote_item);
         }
@@ -591,16 +597,12 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply)
             return -103;
         }
 
-        dap_time_t *l_time_expire = NULL;
-        if(l_voting_expire_str){
-            dap_time_t l_expired_time = dap_time_from_str_rfc822(l_voting_expire_str);
-            l_time_expire = &l_expired_time;
-        }
-        uint64_t *l_max_count = NULL;
-        if (l_max_votes_count_str) {
-            uint64_t ll_max_count = atoll(l_max_votes_count_str);
-            l_max_count = &ll_max_count;
-        }
+        dap_time_t l_time_expire = 0;
+        if (l_voting_expire_str)
+            l_time_expire = dap_time_from_str_rfc822(l_voting_expire_str);
+        uint64_t l_max_count = 0;
+        if (l_max_votes_count_str)
+            l_max_count = strtoul(l_max_votes_count_str, NULL, 10);
 
         bool l_is_delegated_key = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-delegated_key_required", NULL) ? true : false;
         bool l_is_vote_changing_allowed = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-vote_changing_allowed", NULL) ? true : false;
@@ -613,6 +615,8 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply)
 
         char *l_hash_ret = NULL;
         int res = dap_chain_net_vote_create(l_question_str, l_options_list, l_time_expire, l_max_count, l_value_fee, l_is_delegated_key, l_is_vote_changing_allowed, l_wallet_fee, l_net, l_hash_out_type, &l_hash_ret);
+        dap_list_free(l_options_list);
+        dap_chain_wallet_close(l_wallet_fee);
 
         switch (res) {
             case DAP_CHAIN_NET_VOTE_CREATE_OK: {
@@ -743,12 +747,14 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply)
             return -112;
         }
 
-        uint64_t l_option_idx_count = atoll(l_option_idx_str);
+        uint64_t l_option_idx_count = strtoul(l_option_idx_str, NULL, 10);
 
         char *l_hash_tx;
 
         int res = dap_chain_net_vote_voting(l_cert, l_value_fee, l_wallet_fee, l_voting_hash, l_option_idx_count,
                                             l_net, l_hash_out_type, &l_hash_tx);
+        dap_chain_wallet_close(l_wallet_fee);
+
         switch (res) {
             case DAP_CHAIN_NET_VOTE_VOTING_OK: {
                 dap_cli_server_cmd_set_reply_text(a_str_reply, "Datum %s successfully added to mempool", l_hash_tx);
@@ -1124,8 +1130,8 @@ static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_has
     return 1;
 }
 
-int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap_time_t *a_expire_vote,
-                              uint64_t *a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
+int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote,
+                              uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
                               bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
                               dap_chain_net_t *a_net, const char *a_hash_out_type, char **a_hash_output) {
 
@@ -1196,9 +1202,9 @@ int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap
     }
 
     // add voting expire time if needed
-    if(a_expire_vote){
-        dap_time_t l_expired_vote = *a_expire_vote;
-        if (*a_expire_vote < dap_time_now()){
+    if(a_expire_vote != 0){
+        dap_time_t l_expired_vote = a_expire_vote;
+        if (l_expired_vote < dap_time_now()){
             dap_chain_datum_tx_delete(l_tx);
             return DAP_CHAIN_NET_VOTE_CREATE_INPUT_TIME_MORE_CURRENT_TIME;
         }
@@ -1213,8 +1219,8 @@ int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap
     }
 
     // Add vote max count if needed
-    if(a_max_vote){
-        dap_chain_tx_tsd_t* l_max_votes_item = dap_chain_datum_voting_max_votes_count_tsd_create(*a_max_vote);
+    if (a_max_vote != 0) {
+        dap_chain_tx_tsd_t* l_max_votes_item = dap_chain_datum_voting_max_votes_count_tsd_create(a_max_vote);
         if(!l_max_votes_item){
             dap_chain_datum_tx_delete(l_tx);
             return DAP_CHAIN_NET_VOTE_CREATE_CAN_NOT_CREATE_TSD_EXPIRE_TIME;
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index 1363047b38..785eb810a5 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -5022,7 +5022,7 @@ int com_tx_cond_create(int a_argc, char ** a_argv, void **a_str_reply)
     dap_chain_net_srv_price_unit_uid_t l_price_unit = { .enm = dap_chain_srv_str_to_unit_enum((char*)l_unit_str)};
 
     if(l_price_unit.enm == SERV_UNIT_UNDEFINED) {
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't recognize unit '%s'. Unit must look like {mb | kb | b | sec | day}",
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't recognize unit '%s'. Unit must look like { B | SEC }",
                 l_unit_str);
         return -9;
     }
diff --git a/modules/net/include/dap_chain_ledger.h b/modules/net/include/dap_chain_ledger.h
index 0a6ca76a68..0b1b58d21a 100644
--- a/modules/net/include/dap_chain_ledger.h
+++ b/modules/net/include/dap_chain_ledger.h
@@ -275,7 +275,6 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx
 
 const char *dap_ledger_tx_get_main_ticker(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, int *a_ledger_rc);
 
-
 /**
  * Delete all transactions from the cache
  */
diff --git a/modules/net/include/dap_chain_net_voting.h b/modules/net/include/dap_chain_net_voting.h
index e03e6dda51..c045605f30 100644
--- a/modules/net/include/dap_chain_net_voting.h
+++ b/modules/net/include/dap_chain_net_voting.h
@@ -79,8 +79,8 @@ enum DAP_CHAIN_NET_VOTE_CREATE_ERROR {
     DAP_CHAIN_NET_VOTE_CREATE_CAN_NOT_SIGNED_TX,
     DAP_CHAIN_NET_VOTE_CREATE_CAN_NOT_POOL_DATUM_IN_MEMPOOL
 };
-int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap_time_t *a_expire_vote,
-                              uint64_t *a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
+int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote,
+                              uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required,
                               bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet,
                               dap_chain_net_t *a_net, const char *a_hash_out_type, char **a_hash_output);
 
diff --git a/modules/net/include/dap_chain_node_cli_cmd_tx.h b/modules/net/include/dap_chain_node_cli_cmd_tx.h
index 1dc043c876..54d784bd94 100644
--- a/modules/net/include/dap_chain_node_cli_cmd_tx.h
+++ b/modules/net/include/dap_chain_node_cli_cmd_tx.h
@@ -50,10 +50,10 @@ json_object * dap_db_tx_history_to_json(dap_chain_hash_fast_t* a_tx_hash,
                                         int l_ret_code,
                                         bool *accepted_tx,
                                         bool out_brief);
+
 json_object *dap_db_history_tx_all(dap_chain_t *l_chain, dap_chain_net_t *l_net,
                                    const char *l_hash_out_type, json_object *json_obj_summary,
                                    size_t a_limit, size_t a_offset, bool out_brief);
-
 /**
  * ledger command
  *
diff --git a/modules/net/srv/dap_chain_net_srv.c b/modules/net/srv/dap_chain_net_srv.c
index 5661288884..6ef4cde5fd 100644
--- a/modules/net/srv/dap_chain_net_srv.c
+++ b/modules/net/srv/dap_chain_net_srv.c
@@ -40,7 +40,6 @@
 #include "utlist.h"
 
 #include "dap_chain_net.h"
-#include "dap_chain_net_tx.h"
 #include "dap_hash.h"
 #include "dap_common.h"
 #include "dap_enc_base58.h"
@@ -53,6 +52,7 @@
 #include "dap_chain_net_tx.h"
 #include "dap_chain_net_srv_order.h"
 #include "dap_chain_net_srv_stream_session.h"
+#include "dap_chain_net_tx.h"
 #include "dap_stream_ch_chain_net_srv.h"
 #include "dap_chain_cs_blocks.h"
 #ifdef DAP_MODULES_DYNAMIC
@@ -74,10 +74,7 @@ typedef struct service_list {
 static service_list_t *s_srv_list = NULL;
 // for separate access to s_srv_list
 static pthread_mutex_t s_srv_list_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-
-
-static int s_cli_net_srv(int argc, char **argv, void **a_str_reply);
+static int s_cli_net_srv(int argc, char **argv, void **reply);
 static void s_load(const char * a_path);
 static void s_load_all();
 
@@ -95,20 +92,22 @@ int dap_chain_net_srv_init()
 {
     dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY, s_pay_verificator_callback, NULL);
     dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE, s_fee_verificator_callback, NULL);
-    dap_stream_ch_chain_net_srv_init();
 
     dap_cli_server_cmd_add ("net_srv", s_cli_net_srv, "Network services managment",
-        "net_srv -net <net_name> order find [-direction {sell | buy}] [-srv_uid <Service UID>] [-price_unit <price unit>]\n"
-        " [-price_token <Token ticker>] [-price_min <Price minimum>] [-price_max <Price maximum>]\n"
+        "net_srv -net <net_name> order find [-direction {sell | buy}] [-srv_uid <service_UID>] [-price_unit <price_unit>]"
+        " [-price_token <token_ticker>] [-price_min <price_minimum>] [-price_max <price_maximum>]\n"
         "\tOrders list, all or by UID and/or class\n"
-        "net_srv -net <net_name> order delete -hash <Order hash>\n"
+        "net_srv -net <net_name> order delete -hash <ip_addr>\n"
         "\tOrder delete\n"
-        "net_srv -net <net_name> order dump -hash <Order hash>\n"
+        "net_srv -net <net_name> order dump -hash <ip_addr>\n"
         "\tOrder dump info\n"
         "net_srv -net <net_name> order create -direction {sell | buy} -srv_uid <Service UID> -price <Price>\n"
         " -price_unit <Price Unit> -price_token <token_ticker> -units <units> [-node_addr <Node Address>] [-tx_cond <TX Cond Hash>]\n"
         " [-expires <Unix time when expires>] [-cert <cert name to sign order>]\n"
         " [{-ext <Extension with params> | -region <Region name> -continent <Continent name>}]\n"
+        "net_srv get_limits -net <net_name> -srv_uid <Service_UID> -provider_pkey_hash <Service_provider_public_key_hash> -client_pkey_hash <Client_public_key_hash>\n"
+        "net_srv report\n"
+        "\tGet report about srv usage"
 #ifdef DAP_MODULES_DYNAMIC
         "\tOrder create\n"
             "net_srv -net <net_name> order static [save | delete]\n"
@@ -202,6 +201,15 @@ static int s_cli_net_srv( int argc, char **argv, void **a_str_reply)
         return -1;
     }
 
+
+    int l_report = dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "report", NULL);
+    if (l_report) {
+        const char *l_report_str = dap_stream_ch_chain_net_srv_create_statistic_report();
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "%s", l_report_str);
+        DAP_DEL_Z(l_report_str);
+        return 0;
+    }
+
     int l_ret = dap_chain_node_cli_cmd_values_parse_net_chain( &arg_index, argc, argv, a_str_reply, NULL, &l_net );
     if ( l_net ) {
         //char * l_orders_group = dap_chain_net_srv_order_get_gdb_group( l_net );
@@ -209,6 +217,8 @@ static int s_cli_net_srv( int argc, char **argv, void **a_str_reply)
         dap_string_t *l_string_ret = dap_string_new("");
         const char *l_order_str = NULL;
         int l_order_arg_pos = dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "order", &l_order_str);
+        const char *l_get_limits_str = NULL;
+        int l_get_limits_arg_pos = dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "get_limits", &l_get_limits_str);
 
         // Order direction
         const char *l_direction_str = NULL;
@@ -254,38 +264,39 @@ static int s_cli_net_srv( int argc, char **argv, void **a_str_reply)
         const char *l_units_str = NULL;
         dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-units", &l_units_str);
 
-        char *l_order_hash_hex_str = NULL;
-        char *l_order_hash_base58_str = NULL;
-        // datum hash may be in hex or base58 format
-        if (l_order_hash_str) {
-            if(!dap_strncmp(l_order_hash_str, "0x", 2) || !dap_strncmp(l_order_hash_str, "0X", 2)) {
-                l_order_hash_hex_str = dap_strdup(l_order_hash_str);
-                l_order_hash_base58_str = dap_enc_base58_from_hex_str_to_str(l_order_hash_str);
-            } else {
-                l_order_hash_hex_str = dap_enc_base58_to_hex_str_from_str(l_order_hash_str);
-                l_order_hash_base58_str = dap_strdup(l_order_hash_str);
+        if (l_order_str){
+            char *l_order_hash_hex_str = NULL;
+            char *l_order_hash_base58_str = NULL;
+            // datum hash may be in hex or base58 format
+            if (l_order_hash_str) {
+                if(!dap_strncmp(l_order_hash_str, "0x", 2) || !dap_strncmp(l_order_hash_str, "0X", 2)) {
+                    l_order_hash_hex_str = dap_strdup(l_order_hash_str);
+                    l_order_hash_base58_str = dap_enc_base58_from_hex_str_to_str(l_order_hash_str);
+                } else {
+                    l_order_hash_hex_str = dap_enc_base58_to_hex_str_from_str(l_order_hash_str);
+                    l_order_hash_base58_str = dap_strdup(l_order_hash_str);
+                }
             }
-        }
-        if(l_continent_str && l_continent_num <= 0) {
-            dap_string_t *l_string_err = dap_string_new("Unrecognized \"-continent\" option=");
-            dap_string_append_printf(l_string_err, "\"%s\". Variants: ", l_continent_str);
-            int i = 0;
-            while(1) {
-                const char *l_continent = dap_chain_net_srv_order_continent_to_str(i);
-                if(!l_continent)
-                    break;
-                if(!i)
-                    dap_string_append_printf(l_string_err, "\"%s\"", l_continent);
-                else
-                    dap_string_append_printf(l_string_err, ", \"%s\"", l_continent);
-                i++;
+            if(l_continent_str && l_continent_num <= 0) {
+                dap_string_t *l_string_err = dap_string_new("Unrecognized \"-continent\" option=");
+                dap_string_append_printf(l_string_err, "\"%s\". Variants: ", l_continent_str);
+                int i = 0;
+                while(1) {
+                    const char *l_continent = dap_chain_net_srv_order_continent_to_str(i);
+                    if(!l_continent)
+                        break;
+                    if(!i)
+                        dap_string_append_printf(l_string_err, "\"%s\"", l_continent);
+                    else
+                        dap_string_append_printf(l_string_err, ", \"%s\"", l_continent);
+                    i++;
+                }
+                dap_string_append_printf(l_string_ret, "%s\n", l_string_err->str);
+                dap_string_free(l_string_err, true);
+                l_ret = -1;
             }
-            dap_string_append_printf(l_string_ret, "%s\n", l_string_err->str);
-            dap_string_free(l_string_err, true);
-            l_ret = -1;
-        }
-        // Update order
-        else if(!dap_strcmp(l_order_str, "update")) {
+            // Update order
+            else if(!dap_strcmp(l_order_str, "update")) {
 
             if(!l_order_hash_str) {
                 l_ret = -1;
@@ -384,181 +395,176 @@ static int s_cli_net_srv( int argc, char **argv, void **a_str_reply)
             if ( l_price_max_str )
                 l_price_max = dap_chain_balance_scan(l_price_max_str);
 
-            if (l_price_unit_str){
-                if (!dap_strcmp(l_price_unit_str, "MB")){
-                    l_price_unit.uint32 = SERV_UNIT_MB;
-                } else if (!dap_strcmp(l_price_unit_str, "SEC")){
-                    l_price_unit.uint32 = SERV_UNIT_SEC;
-                } else if (!dap_strcmp(l_price_unit_str, "DAY")){
-                    l_price_unit.uint32 = SERV_UNIT_DAY;
-                } else if (!dap_strcmp(l_price_unit_str, "KB")){
-                    l_price_unit.uint32 = SERV_UNIT_KB;
-                } else if (!dap_strcmp(l_price_unit_str, "B")){
-                    l_price_unit.uint32 = SERV_UNIT_B;
-                } else if (!dap_strcmp(l_price_unit_str, "PCS")){
-                    l_price_unit.uint32 = SERV_UNIT_PCS;
-                }
-            }
+            l_price_unit.uint32 = dap_chain_srv_str_to_unit_enum(l_price_unit_str);
 
-            dap_chain_net_srv_order_t * l_orders;
+            dap_list_t * l_orders;
             size_t l_orders_num = 0;
             if( dap_chain_net_srv_order_find_all_by( l_net, l_direction,l_srv_uid,l_price_unit,l_price_token_str,l_price_min, l_price_max,&l_orders,&l_orders_num) == 0 ){
                 dap_string_append_printf(l_string_ret, "Found %zu orders:\n", l_orders_num);
-                size_t l_orders_size = 0;
-                for (size_t i = 0; i< l_orders_num; i++){
-                    dap_chain_net_srv_order_t *l_order =(dap_chain_net_srv_order_t *) (((byte_t*) l_orders) + l_orders_size);
+                for (dap_list_t *l_temp = l_orders;l_temp; l_temp = l_orders->next){
+                    dap_chain_net_srv_order_t *l_order =(dap_chain_net_srv_order_t *) l_temp->data;
                     dap_chain_net_srv_order_dump_to_string(l_order, l_string_ret, l_hash_out_type, l_net->pub.native_ticker);
-                    l_orders_size += dap_chain_net_srv_order_get_size(l_order);
                     dap_string_append(l_string_ret,"\n");
                 }
                 l_ret = 0;
-                if (l_orders_num)
-                    DAP_DELETE(l_orders);
-             }else{
+                dap_list_free_full(l_orders, NULL);
+            }else{
                 l_ret = -5 ;
                 dap_string_append(l_string_ret,"Can't get orders: some internal error or wrong params\n");
             }
-        } else if(!dap_strcmp( l_order_str, "dump" )) {
-            // Select with specified service uid
-            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_hex_str );
-                if (l_order) {
-                    dap_chain_net_srv_order_dump_to_string(l_order,l_string_ret, l_hash_out_type, l_net->pub.native_ticker);
-                    l_ret = 0;
-                }else{
-                    l_ret = -7 ;
-                    if(!dap_strcmp(l_hash_out_type,"hex"))
-                        dap_string_append_printf(l_string_ret,"Can't find order with hash %s\n", l_order_hash_hex_str );
-                    else
-                        dap_string_append_printf(l_string_ret,"Can't find order with hash %s\n", l_order_hash_base58_str );
-                }
-            } else {
-
-                dap_chain_net_srv_order_t * l_orders = NULL;
-                size_t l_orders_num = 0;
-                dap_chain_net_srv_uid_t l_srv_uid={{0}};
-                uint256_t l_price_min = {};
-                uint256_t l_price_max = {};
-                dap_chain_net_srv_price_unit_uid_t l_price_unit={{0}};
-                dap_chain_net_srv_order_direction_t l_direction = SERV_DIR_UNDEFINED;
-
-                if( !dap_chain_net_srv_order_find_all_by( l_net,l_direction,l_srv_uid,l_price_unit, NULL, l_price_min, l_price_max,&l_orders,&l_orders_num) ){
-                    dap_string_append_printf(l_string_ret,"Found %zd orders:\n",l_orders_num);
-                    size_t l_orders_size = 0;
-                    for(size_t i = 0; i < l_orders_num; i++) {
-                        dap_chain_net_srv_order_t *l_order =(dap_chain_net_srv_order_t *) (((byte_t*) l_orders) + l_orders_size);
-                        dap_chain_net_srv_order_dump_to_string(l_order, l_string_ret, l_hash_out_type, l_net->pub.native_ticker);
-                        l_orders_size += dap_chain_net_srv_order_get_size(l_order);
-                        dap_string_append(l_string_ret, "\n");
-                    }
-                    l_ret = 0;
-                }else{
-                    l_ret = -5 ;
-                    dap_string_append(l_string_ret,"Can't get orders: some internal error or wrong params\n");
-                }
-                DAP_DELETE(l_orders);
-            }
-        } else if(!dap_strcmp( l_order_str, "delete" )) {
-            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_hex_str);
-                if (l_order) {
-                    if (!dap_chain_net_srv_order_delete_by_hash_str_sync(l_net, l_order_hash_hex_str)) {
+            } else if(!dap_strcmp( l_order_str, "dump" )) {
+                // Select with specified service uid
+                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_hex_str );
+                    if (l_order) {
+                        dap_chain_net_srv_order_dump_to_string(l_order,l_string_ret, l_hash_out_type, l_net->pub.native_ticker);
                         l_ret = 0;
-                        dap_string_append_printf(l_string_ret, "Deleted order %s\n", l_order_hash_str);
-                    } else {
-                        l_ret = -9;
-                        dap_string_append_printf(l_string_ret, "Can't delete order with hash %s\n", l_order_hash_str);
+                    }else{
+                        l_ret = -7 ;
+                        if(!dap_strcmp(l_hash_out_type,"hex"))
+                            dap_string_append_printf(l_string_ret,"Can't find order with hash %s\n", l_order_hash_hex_str );
+                        else
+                            dap_string_append_printf(l_string_ret,"Can't find order with hash %s\n", l_order_hash_base58_str );
                     }
                 } else {
-                    l_ret = -8;
-                    dap_string_append_printf(l_string_ret, "Can't find order with hash %s\n", l_order_hash_str);
-                }
-                DAP_DELETE(l_order);
-            } else {
-                l_ret = -9;
-                dap_string_append(l_string_ret,"Comman 'oreder delete' requires -hash param\n");
-            }
-        } else if(!dap_strcmp( l_order_str, "create" )) {
-            if (dap_chain_net_get_role(l_net).enums > NODE_ROLE_MASTER) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Node role should be not lower than master\n");
-                return -4;
-            }
-            const char *l_order_cert_name = NULL;
-            dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-cert", &l_order_cert_name);
-            if ( l_srv_uid_str && l_price_str && l_price_token_str && l_price_unit_str && l_units_str) {
-                dap_chain_net_srv_uid_t l_srv_uid={{0}};
-                dap_chain_node_addr_t l_node_addr={0};
-                dap_chain_hash_fast_t l_tx_cond_hash={{0}};
-                dap_time_t l_expires = 0; // TS when the service expires
-                uint256_t l_price = {0};
-                char l_price_token[DAP_CHAIN_TICKER_SIZE_MAX]={0};
-                dap_chain_net_srv_price_unit_uid_t l_price_unit={{0}};
-                dap_chain_net_srv_order_direction_t l_direction = SERV_DIR_UNDEFINED;
-                if ( l_direction_str ){
-                    if (!strcmp(l_direction_str, "sell")) {
-                        l_direction = SERV_DIR_SELL;
-                        log_it(L_DEBUG, "Created order to sell");
-                    } else if (!strcmp(l_direction_str, "buy")) {
-                        l_direction = SERV_DIR_BUY;
-                        log_it(L_DEBUG, "Created order to buy");
-                    } else {
-                        log_it(L_WARNING, "Undefined order direction");
-                        dap_string_free(l_string_ret, true);
-                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Wrong direction of the token was "
-                                                                       "specified, possible directions: buy, sell.");
-                        return -18;
+                    dap_list_t * l_orders = NULL;
+                    size_t l_orders_num = 0;
+                    dap_chain_net_srv_uid_t l_srv_uid={{0}};
+                    uint256_t l_price_min = {};
+                    uint256_t l_price_max = {};
+                    dap_chain_net_srv_price_unit_uid_t l_price_unit={{0}};
+                    dap_chain_net_srv_order_direction_t l_direction = SERV_DIR_UNDEFINED;
+
+                    if( !dap_chain_net_srv_order_find_all_by( l_net,l_direction,l_srv_uid,l_price_unit, NULL, l_price_min, l_price_max,&l_orders,&l_orders_num) ){
+                        dap_string_append_printf(l_string_ret,"Found %zd orders:\n",l_orders_num);
+                        for(dap_list_t *l_temp = l_orders;l_temp; l_temp = l_orders->next) {
+                            dap_chain_net_srv_order_t *l_order =(dap_chain_net_srv_order_t *) l_temp->data;
+                            dap_chain_net_srv_order_dump_to_string(l_order, l_string_ret, l_hash_out_type, l_net->pub.native_ticker);
+                            dap_string_append(l_string_ret, "\n");
+                        }
+                        l_ret = 0;
+                    }else{
+                        l_ret = -5 ;
+                        dap_string_append(l_string_ret,"Can't get orders: some internal error or wrong params\n");
                     }
+                    dap_list_free_full(l_orders, NULL);
                 }
-
-                if (l_expires_str)
-                    l_expires = (dap_time_t ) atoll( l_expires_str);
-                if (l_srv_uid_str && dap_id_uint64_parse(l_srv_uid_str ,&l_srv_uid.uint64)) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't recognize '%s' string as 64-bit id, hex or dec.", l_srv_uid_str);
-                    dap_string_free(l_string_ret, true);
-                    return -21;
-                }
-                if (l_node_addr_str) {
-                    if (dap_chain_node_addr_str_check(l_node_addr_str)) {
-                        dap_chain_node_addr_from_str( &l_node_addr, l_node_addr_str );
-                    } else {
-                        log_it(L_ERROR, "Can't parse \"%s\" as node addr", l_node_addr_str);
-                        dap_cli_server_cmd_set_reply_text(a_str_reply, "The order has not been created. "
-                                                                       "Failed to convert string representation of '%s' "
-                                                                       "to node address.", l_node_addr_str);
-                        dap_string_free(l_string_ret, true);
-                        return -17;
+            } else if (!dap_strcmp(l_order_str, "delete")) {
+                if (l_order_hash_str) {
+                    l_ret = dap_chain_net_srv_order_delete_by_hash_str_sync(l_net, l_order_hash_hex_str);
+                    if (!l_ret)
+                        dap_string_append_printf(l_string_ret, "Deleted order %s\n", l_order_hash_str);
+                    else {
+                        l_ret = -8;
+                        dap_string_append_printf(l_string_ret, "Can't find order with hash %s\n", l_order_hash_str);
                     }
                 } else {
-                    l_node_addr.uint64 = dap_chain_net_get_cur_addr_int(l_net);
+                    l_ret = -9 ;
+                    dap_string_append(l_string_ret,"need -hash param to obtain what the order we need to dump\n");
                 }
-                if (l_tx_cond_hash_str)
-                    dap_chain_hash_fast_from_str (l_tx_cond_hash_str, &l_tx_cond_hash);
-                l_price = dap_chain_balance_scan(l_price_str);
-
-                if (s_str_to_price_unit(l_price_unit_str, &l_price_unit)){
-                    log_it(L_ERROR, "Undefined price unit");
-                    dap_string_free(l_string_ret, true);
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Wrong unit type sepcified, possible values: B, KB, MB, SEC, DAY, PCS");
-                    return -18;
+            } else if(!dap_strcmp( l_order_str, "create" )) {
+                if (dap_chain_net_get_role(l_net).enums > NODE_ROLE_MASTER) {
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Node role should be not lower than master\n");
+                    return -4;
                 }
+                const char *l_order_cert_name = NULL;
+                dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-cert", &l_order_cert_name);
+                if ( l_srv_uid_str && l_price_str && l_price_token_str && l_price_unit_str && l_units_str) {
+                    dap_chain_net_srv_uid_t l_srv_uid={{0}};
+                    dap_chain_node_addr_t l_node_addr={0};
+                    dap_chain_hash_fast_t l_tx_cond_hash={{0}};
+                    dap_time_t l_expires = 0; // TS when the service expires
+                    uint256_t l_price = {0};
+                    char l_price_token[DAP_CHAIN_TICKER_SIZE_MAX]={0};
+                    dap_chain_net_srv_price_unit_uid_t l_price_unit={{0}};
+                    dap_chain_net_srv_order_direction_t l_direction = SERV_DIR_UNDEFINED;
+                    if ( l_direction_str ){
+                        if (!strcmp(l_direction_str, "sell")) {
+                            l_direction = SERV_DIR_SELL;
+                            log_it(L_DEBUG, "Created order to sell");
+                        } else if (!strcmp(l_direction_str, "buy")) {
+                            l_direction = SERV_DIR_BUY;
+                            log_it(L_DEBUG, "Created order to buy");
+                        } else {
+                            log_it(L_WARNING, "Undefined order direction");
+                            dap_string_free(l_string_ret, true);
+                            dap_cli_server_cmd_set_reply_text(a_str_reply, "Wrong direction of the token was "
+                                                                           "specified, possible directions: buy, sell.");
+                            return -18;
+                        }
+                    }
 
-                uint64_t l_units = atoi(l_units_str);
-                strncpy(l_price_token, l_price_token_str, DAP_CHAIN_TICKER_SIZE_MAX - 1);
-                size_t l_ext_len = l_ext? strlen(l_ext) + 1 : 0;
-                // get cert to order sign
-                dap_cert_t *l_cert = NULL;
-                dap_enc_key_t *l_key = NULL;
-                if(l_order_cert_name) {
-                    l_cert = dap_cert_find_by_name(l_order_cert_name);
-                    if(l_cert) {
-                        l_key = l_cert->enc_key;
-                    } else {
-                        log_it(L_ERROR, "Can't load cert '%s' for sign order", l_order_cert_name);
-                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't load cert '%s' for sign "
-                                                                       "order", l_order_cert_name);
+                    if (l_expires_str)
+                        l_expires = (dap_time_t ) atoll( l_expires_str);
+                    if (l_srv_uid_str && dap_id_uint64_parse(l_srv_uid_str ,&l_srv_uid.uint64)) {
+                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't recognize '%s' string as 64-bit id, hex or dec.", l_srv_uid_str);
                         dap_string_free(l_string_ret, true);
-                        return -19;
+                        return -21;
+                    }else if (!l_srv_uid_str){
+                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Parameter -srv_uid is required.");
+                        dap_string_free(l_string_ret, true);
+                        return -22;
                     }
+                    if (l_node_addr_str){
+                        if (dap_chain_node_addr_str_check(l_node_addr_str)) {
+                            dap_chain_node_addr_from_str( &l_node_addr, l_node_addr_str );
+                        } else {
+                            log_it(L_ERROR, "Can't parse \"%s\" as node addr", l_node_addr_str);
+                            dap_cli_server_cmd_set_reply_text(a_str_reply, "The order has not been created. "
+                                                                           "Failed to convert string representation of '%s' "
+                                                                           "to node address.", l_node_addr_str);
+                            dap_string_free(l_string_ret, true);
+                            return -17;
+                        }
+                    } else {
+                        l_node_addr.uint64 = dap_chain_net_get_cur_addr_int(l_net);
+                    }
+                    if (l_tx_cond_hash_str)
+                        dap_chain_hash_fast_from_str (l_tx_cond_hash_str, &l_tx_cond_hash);
+                    l_price = dap_chain_balance_scan(l_price_str);
+
+                    uint64_t l_units = atoi(l_units_str);
+
+                    if (!dap_strcmp(l_price_unit_str, "B")){
+                        l_price_unit.enm = SERV_UNIT_B;
+                    } else if (!dap_strcmp(l_price_unit_str, "KB")){
+                        l_price_unit.enm = SERV_UNIT_B;
+                        l_units *= 1024;
+                    } else if (!dap_strcmp(l_price_unit_str, "MB")){
+                        l_price_unit.enm = SERV_UNIT_B;
+                        l_units *= 1024*1024;
+                    } else if (!dap_strcmp(l_price_unit_str, "DAY")){
+                        l_price_unit.enm = SERV_UNIT_SEC;
+                        l_units *= 3600*24;
+                    } else if (!dap_strcmp(l_price_unit_str, "SEC")){
+                        l_price_unit.enm = SERV_UNIT_SEC;
+                    } else if (!dap_strcmp(l_price_unit_str, "PCS")){
+                        l_price_unit.enm = SERV_UNIT_PCS;
+                    } else {
+                        log_it(L_ERROR, "Undefined price unit");
+                        dap_string_free(l_string_ret, true);
+                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Wrong unit type sepcified, possible values: B, KB, MB, SEC, DAY, PCS");
+                        return -18;
+                    } 
+
+
+                    
+                    strncpy(l_price_token, l_price_token_str, DAP_CHAIN_TICKER_SIZE_MAX - 1);
+                    size_t l_ext_len = l_ext? strlen(l_ext) + 1 : 0;
+                    // get cert to order sign
+                    dap_cert_t *l_cert = NULL;
+                    dap_enc_key_t *l_key = NULL;
+                    if(l_order_cert_name) {
+                        l_cert = dap_cert_find_by_name(l_order_cert_name);
+                        if(l_cert) {
+                            l_key = l_cert->enc_key;
+                        } else {
+                            log_it(L_ERROR, "Can't load cert '%s' for sign order", l_order_cert_name);
+                            dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't load cert '%s' for sign "
+                                                                           "order", l_order_cert_name);
+                            dap_string_free(l_string_ret, true);
+                            return -19;
+                        }
                 } else {
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "The certificate name was not "
                                                                    "specified. Since version 5.2 it is not possible to "
@@ -582,73 +588,74 @@ static int s_cli_net_srv( int argc, char **argv, void **a_str_reply)
                 dap_string_append_printf( l_string_ret, "Missed some required params\n");
                 l_ret=-5;
             }
-        }
-#ifdef DAP_MODULES_DYNAMIC
-        else if(!dap_strcmp( l_order_str, "recheck" )) {
-            int (*dap_chain_net_srv_vpn_cdb_server_list_check_orders)(dap_chain_net_t *a_net);
-            dap_chain_net_srv_vpn_cdb_server_list_check_orders = dap_modules_dynamic_get_cdb_func("dap_chain_net_srv_vpn_cdb_server_list_check_orders");
-            int l_init_res = dap_chain_net_srv_vpn_cdb_server_list_check_orders ? dap_chain_net_srv_vpn_cdb_server_list_check_orders(l_net) : -5;
-            if (l_init_res >= 0) {
-                dap_string_append_printf(l_string_ret, "Orders recheck started\n");
-                l_ret = 0;
-            } else {
-                dap_string_append_printf(l_string_ret, "Orders recheck not started, code %d\n", l_init_res);
-                l_ret = -10;
+            }
+            else if (l_order_str) {
+                dap_string_append_printf(l_string_ret, "Unrecognized subcommand '%s'", l_order_str);
+                l_ret = -14;
+            }
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "%s", l_string_ret->str);
+            dap_string_free(l_string_ret, true);
+        } else if (l_get_limits_str){
+            const char *l_provider_pkey_hash_str = NULL;
+            dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-provider_pkey_hash", &l_provider_pkey_hash_str);
+
+            const char *l_client_pkey_hash_str = NULL;
+            dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-client_pkey_hash", &l_client_pkey_hash_str);
+
+            if (!l_provider_pkey_hash_str){
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'get_limits' require the parameter provider_pkey_hash");
+                dap_string_free(l_string_ret, true);
+                return -15;
             }
 
-        } else if(!dap_strcmp( l_order_str, "static" )) {
-            // find the subcommand directly after the 'order' command
-            int l_subcmd_save = dap_cli_server_cmd_find_option_val(argv, l_order_arg_pos + 1, l_order_arg_pos + 2, "save", NULL);
-            int l_subcmd_del = dap_cli_server_cmd_find_option_val(argv, l_order_arg_pos + 1, l_order_arg_pos + 2, "delete", NULL) |
-                               dap_cli_server_cmd_find_option_val(argv, l_order_arg_pos + 1, l_order_arg_pos + 2, "del", NULL);
-
-            int (*dap_chain_net_srv_vpn_cdb_server_list_static_create)(dap_chain_net_t *a_net) = NULL;
-            int (*dap_chain_net_srv_vpn_cdb_server_list_static_delete)(dap_chain_net_t *a_net) = NULL;
-            //  find func from dinamic library
-            if(l_subcmd_save || l_subcmd_del) {
-                dap_chain_net_srv_vpn_cdb_server_list_static_create = dap_modules_dynamic_get_cdb_func("dap_chain_net_srv_vpn_cdb_server_list_static_create");
-                dap_chain_net_srv_vpn_cdb_server_list_static_delete = dap_modules_dynamic_get_cdb_func("dap_chain_net_srv_vpn_cdb_server_list_static_delete");
+            if (!l_client_pkey_hash_str){
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'get_limits' require the parameter client_pkey_hash");
+                dap_string_free(l_string_ret, true);
+                return -16;
             }
-            if(l_subcmd_save) {
-                int l_init_res = dap_chain_net_srv_vpn_cdb_server_list_static_create ? dap_chain_net_srv_vpn_cdb_server_list_static_create(l_net) : -5;
-                if(l_init_res >= 0){
-                    dap_string_append_printf(l_string_ret, "Static node list saved, %d orders in list\n", l_init_res);
-                    l_ret = 0;
-                }
-                else{
-                    dap_string_append_printf(l_string_ret, "Static node list not saved, error code %d\n", l_init_res);
-                    l_ret = -11;
-                }
 
-            } else if(l_subcmd_del) {
-                int l_init_res = dap_chain_net_srv_vpn_cdb_server_list_static_delete ? dap_chain_net_srv_vpn_cdb_server_list_static_delete(l_net) : -5;
-                if(!l_init_res){
-                    dap_string_append_printf(l_string_ret, "Static node list deleted\n");
-                    l_ret = 0;
-                }
-                else if(l_init_res > 0){
-                    dap_string_append_printf(l_string_ret, "Static node list already deleted\n");
-                    l_ret = -12;
-                }
-                else
-                    dap_string_append_printf(l_string_ret, "Static node list not deleted, error code %d\n", l_init_res);
-            } else {
-                dap_string_append(l_string_ret, "not found subcommand 'save' or 'delete'\n");
-                l_ret = -13;
+            dap_chain_net_srv_uid_t l_srv_uid={{0}};
+            if (l_srv_uid_str && dap_id_uint64_parse(l_srv_uid_str ,&l_srv_uid.uint64)) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't recognize '%s' string as 64-bit id, hex or dec.", l_srv_uid_str);
+                dap_string_free(l_string_ret, true);
+                return -21;
+            } else if (!l_srv_uid_str){
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Parameter -srv_uid is required.");
+                dap_string_free(l_string_ret, true);
+                return -22;
             }
-        }
-#endif
-        else if (l_order_str) {
-            dap_string_append_printf(l_string_ret, "Unrecognized subcommand '%s'", l_order_str);
-            l_ret = -14;
+
+            dap_stream_ch_chain_net_srv_remain_service_store_t *l_remain_service = NULL;
+            size_t l_remain_service_size = 0;
+            char *l_remain_limits_gdb_group =  dap_strdup_printf( "%s.0x%016"DAP_UINT64_FORMAT_x".remain_limits.%s",
+                                                                l_net->pub.gdb_groups_prefix, l_srv_uid.uint64,
+                                                                l_provider_pkey_hash_str);
+
+            l_remain_service = (dap_stream_ch_chain_net_srv_remain_service_store_t*) dap_global_db_get_sync(l_remain_limits_gdb_group, l_client_pkey_hash_str, &l_remain_service_size, NULL, NULL);
+            DAP_DELETE(l_remain_limits_gdb_group);
+
+            if(!l_remain_service || !l_remain_service_size){
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't get remain service data");
+                dap_string_free(l_string_ret, true);
+                return -21;
+            }
+
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Provider %s. Client %s remain service values:\n"
+                                                   "SEC: %"DAP_UINT64_FORMAT_U"\n"
+                                                   "BYTES: %"DAP_UINT64_FORMAT_U"\n", l_provider_pkey_hash_str, l_client_pkey_hash_str,
+                                              (uint64_t)l_remain_service->limits_ts, (uint64_t)l_remain_service->limits_bytes);
+
+            dap_string_free(l_string_ret, true);
+            DAP_DELETE(l_remain_service);
         } else {
-            dap_string_append_printf(l_string_ret, "Command 'net_srv' requires subcommand 'order'");
-            l_ret = -3;
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Unrecognized bcommand.");
+            dap_string_free(l_string_ret, true);
+            return -17;
         }
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "%s", l_string_ret->str);
-        dap_string_free(l_string_ret, true);
+
     }
 
+
     return l_ret;
 }
 
@@ -836,12 +843,21 @@ dap_chain_net_srv_price_t * dap_chain_net_srv_get_price_from_order(dap_chain_net
     const char *l_wallet_addr = dap_config_get_item_str_default(g_config, a_config_section, "wallet_addr", NULL);
     const char *l_cert_name = dap_config_get_item_str_default(g_config, a_config_section, "receipt_sign_cert", NULL);
     const char *l_net_name = dap_config_get_item_str_default(g_config, a_config_section, "net", NULL);
-    if (!l_wallet_addr || !l_cert_name || !l_net_name){
+    if (!l_wallet_addr){
+        log_it(L_CRITICAL, "Wallet addr is not defined. Check node configuration file.");
+        return NULL;
+    }
+    if (!l_cert_name){
+        log_it(L_CRITICAL, "Receipt sign certificate is not defined. Check node configuration file.");
+        return NULL;
+    }
+    if (!l_net_name){
+        log_it(L_CRITICAL, "Net for is not defined. Check node configuration file.");
         return NULL;
     }
-
     dap_chain_net_t *l_net = dap_chain_net_by_name(l_net_name);
     if (!l_net) {
+        log_it(L_CRITICAL, "Can't find net %s. Check node configuration file.", l_net_name);
         return NULL;
     }
 
@@ -875,7 +891,7 @@ dap_chain_net_srv_price_t * dap_chain_net_srv_get_price_from_order(dap_chain_net
     l_price->net = l_net;
     l_price->net_name = dap_strdup(l_net->pub.name);
     uint256_t l_max_price = GET_256_FROM_64(l_max_price_cfg); // Change this value when max price wil be calculated
-    if (IS_ZERO_256(l_order->price) || l_order->units == 0 ){
+    if ((IS_ZERO_256(l_order->price) || l_order->units == 0 ) && !a_srv->allow_free_srv){
         log_it(L_ERROR, "Invalid order: units count or price unspecified");
         DAP_DELETE(l_price);
         DAP_DEL_Z(l_order);
@@ -918,9 +934,20 @@ dap_chain_net_srv_price_t * dap_chain_net_srv_get_price_from_order(dap_chain_net
     dap_hash_fast_t order_pkey_hash = {};
     dap_hash_fast_t price_pkey_hash = {};
     dap_sign_get_pkey_hash((dap_sign_t*)(l_order->ext_n_sign + l_order->ext_size), &order_pkey_hash);
-    dap_hash_fast(l_price->receipt_sign_cert->enc_key->pub_key_data,
-                  l_price->receipt_sign_cert->enc_key->pub_key_data_size, &price_pkey_hash);
-    if (dap_hash_fast_compare(&order_pkey_hash, &price_pkey_hash))
+    size_t l_key_size = 0;
+    uint8_t *l_pub_key = dap_enc_key_serialize_pub_key(l_price->receipt_sign_cert->enc_key, &l_key_size);
+    if (!l_pub_key || !l_key_size)
+    {
+        log_it(L_ERROR, "Can't get pkey from cert %s.", l_cert_name);
+        DAP_DEL_Z(l_order);
+        DAP_DELETE(l_price);
+        return NULL;
+    }
+
+    dap_hash_fast(l_pub_key, l_key_size, &price_pkey_hash);
+    DAP_DELETE(l_pub_key);
+
+    if (!dap_hash_fast_compare(&order_pkey_hash, &price_pkey_hash))
     {
         log_it(L_ERROR, "pkey in order not equal to pkey in config.");
         DAP_DEL_Z(l_order);
@@ -930,197 +957,14 @@ dap_chain_net_srv_price_t * dap_chain_net_srv_get_price_from_order(dap_chain_net
 
     DAP_DELETE(l_order);
     return l_price;
-
 }
 
+int dap_chain_net_srv_price_apply_from_my_order(dap_chain_net_srv_t *a_srv, const char *a_config_section)
+{
 
-int dap_chain_net_srv_price_apply_from_my_order(dap_chain_net_srv_t *a_srv, const char *a_config_section){
-
-//    const char *l_wallet_path = dap_config_get_item_str_default(g_config, "resources", "wallets_path", NULL);
-//    const char *l_wallet_name = dap_config_get_item_str_default(g_config, a_config_section, "wallet", NULL);
-
-    const char *l_wallet_addr = dap_config_get_item_str_default(g_config, a_config_section, "wallet_addr", NULL);
-    const char *l_cert_name = dap_config_get_item_str_default(g_config, a_config_section, "receipt_sign_cert", NULL);
-    const char *l_net_name = dap_config_get_item_str_default(g_config, a_config_section, "net", NULL);
-    if (!l_wallet_addr || !l_cert_name || !l_net_name){
-        return -2;
-    }
-
-//    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_name, l_wallet_path);
-//    if (!l_wallet) {
-//        return -3;
-//    }
-    dap_chain_net_t *l_net = dap_chain_net_by_name(l_net_name);
-    if (!l_net) {
-        return -4;
-    }
-    a_srv->grace_period = dap_config_get_item_uint32_default(g_config, a_config_section, "grace_period", 60);
-    a_srv->allow_free_srv = dap_config_get_item_bool_default(g_config, a_config_section, "allow_free_srv", false);
-    int l_err_code = 0;
-    size_t l_orders_count = 0;
-    uint64_t l_max_price_cfg = dap_config_get_item_uint64_default(g_config, a_config_section, "max_price", 0xFFFFFFFFFFFFFFF);
-    char *l_gdb_order_group = dap_chain_net_srv_order_get_gdb_group(l_net);
-    dap_global_db_obj_t *l_orders = dap_global_db_get_all_sync(l_gdb_order_group, &l_orders_count);
-    log_it(L_INFO, "Found %"DAP_UINT64_FORMAT_U" orders.", l_orders_count);
-    for (size_t i=0; i < l_orders_count; i++){
-        l_err_code = -4;
-        dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_read(l_orders[i].value, l_orders[i].value_len);
-        if(!l_order){
-            log_it(L_ERROR, "Invalid order: NULL. Skip order.");
-            continue;
-        }
-        if (l_order->node_addr.uint64 == g_node_addr.uint64 &&
-            l_order->srv_uid.uint64 == a_srv->uid.uint64) {
-            l_err_code = 0;
-            dap_chain_net_srv_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_price_t);
-            if (!l_price) {
-                log_it(L_CRITICAL, "Memory allocation error");
-                DAP_DEL_Z(l_order);
-                dap_global_db_objs_delete(l_orders, l_orders_count);
-                return -1;
-            }
-            l_price->net = l_net;
-            l_price->net_name = dap_strdup(l_net->pub.name);
-            uint256_t l_max_price = GET_256_FROM_64(l_max_price_cfg); // Change this value when max price wil be calculated
-            if (IS_ZERO_256(l_order->price) || l_order->units == 0 ){
-                log_it(L_ERROR, "Invalid order: units count or price unspecified");
-                DAP_DELETE(l_price);
-                continue;
-            }
-            l_price->value_datoshi = l_order->price;
-            dap_stpcpy(l_price->token, l_order->price_ticker);
-            l_price->units = l_order->units;
-            l_price->units_uid = l_order->price_unit;
-            if (!IS_ZERO_256(l_max_price)){
-                uint256_t l_price_unit = uint256_0;
-                DIV_256(l_price->value_datoshi,  GET_256_FROM_64(l_order->units), &l_price_unit);
-                if (compare256(l_price_unit, l_max_price)>0){
-                    char *l_price_unit_str = dap_chain_balance_print(l_price_unit), *l_max_price_str = dap_chain_balance_print(l_max_price);
-                    log_it(L_ERROR, "Unit price exeeds max permitted value: %s > %s", l_price_unit_str, l_max_price_str);
-                    DAP_DELETE(l_price_unit_str);
-                    DAP_DELETE(l_max_price_str);
-                    DAP_DELETE(l_price);
-                    continue;
-                }
-            }
-//          l_price->wallet = l_wallet;
-            l_price->wallet_addr = dap_chain_addr_from_str(l_wallet_addr);
-            if(!l_price->wallet_addr){
-                log_it(L_ERROR, "Can't get wallet addr from wallet_addr in config file.");
-                DAP_DEL_Z(l_order);
-                DAP_DELETE(l_price);
-                dap_global_db_objs_delete(l_orders, l_orders_count);
-                return -100;
-            }
-
-            l_price->receipt_sign_cert = dap_cert_find_by_name(l_cert_name);
-            if(!l_price->receipt_sign_cert){
-                log_it(L_ERROR, "Can't find cert %s.", l_cert_name);
-                DAP_DEL_Z(l_order);
-                DAP_DELETE(l_price);
-                dap_global_db_objs_delete(l_orders, l_orders_count);
-                return -101;
-            }
-
-            dap_hash_fast_t order_pkey_hash = { }, price_pkey_hash = { };
-            dap_sign_get_pkey_hash((dap_sign_t*)(l_order->ext_n_sign + l_order->ext_size), &order_pkey_hash);
-            dap_hash_fast(l_price->receipt_sign_cert->enc_key->pub_key_data,
-                          l_price->receipt_sign_cert->enc_key->pub_key_data_size, &price_pkey_hash);
-            if (dap_hash_fast_compare(&order_pkey_hash, &price_pkey_hash))
-            {
-                log_it(L_ERROR, "pkey in order not equal to pkey in config.");
-                DAP_DEL_Z(l_order);
-                DAP_DELETE(l_price);
-                dap_global_db_objs_delete(l_orders, l_orders_count);
-                continue;
-            }
 
-            // TODO: find most advantageous order for us
-            DL_APPEND(a_srv->pricelist, l_price);
-            break;
-        }
-        DAP_DELETE(l_order);
-    }
-    dap_global_db_objs_delete(l_orders, l_orders_count);
-    return l_err_code;
-}
 
-int dap_chain_net_srv_parse_pricelist(dap_chain_net_srv_t *a_srv, const char *a_config_section)
-{
-    int ret = 0;
-    if (!a_config_section)
-        return ret;
-    a_srv->grace_period = dap_config_get_item_uint32_default(g_config, a_config_section, "grace_period", 60);
-    uint16_t l_pricelist_count = 0;
-    char **l_pricelist = dap_config_get_array_str(g_config, a_config_section, "pricelist", &l_pricelist_count);
-    for (uint16_t i = 0; i < l_pricelist_count; i++) {
-        dap_chain_net_srv_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_price_t);
-        if (!l_price) {
-            log_it(L_CRITICAL, "Memory allocation error");
-            return ret;
-        }
-        short l_iter = 0;
-        char *l_price_str = dap_strdup(l_pricelist[i]), *l_ctx;
-        for (char *l_price_token = strtok_r(l_price_str, ":", &l_ctx); l_price_token || l_iter == 6; l_price_token = strtok_r(NULL, ":", &l_ctx), ++l_iter) {
-            //log_it(L_DEBUG, "Tokenizer: %s", l_price_token);
-            switch (l_iter) {
-            case 0:
-                l_price->net_name = l_price_token;
-                if (!(l_price->net = dap_chain_net_by_name(l_price->net_name))) {
-                    log_it(L_ERROR, "Error parsing pricelist: can't find network \"%s\"", l_price_token);
-                    break;
-                }
-                continue;
-            case 1:
-                l_price->value_datoshi = dap_chain_coins_to_balance(l_price_token);
-                if (IS_ZERO_256(l_price->value_datoshi)) {
-                    log_it(L_ERROR, "Error parsing pricelist: text on 2nd position \"%s\" is not floating number", l_price_token);
-                    l_iter = 0;
-                    break;
-                }
-                continue;
-            case 2:
-                dap_stpcpy(l_price->token, l_price_token);
-                continue;
-            case 3:
-                l_price->units = strtoul(l_price_token, NULL, 10);
-                if (!l_price->units) {
-                    log_it(L_ERROR, "Error parsing pricelist: text on 4th position \"%s\" is not unsigned integer", l_price_token);
-                    l_iter = 0;
-                    break;
-                }
-                continue;
-            case 4:
-                if (s_str_to_price_unit(l_price_token, &(l_price->units_uid))) {
-                    log_it(L_ERROR, "Error parsing pricelist: wrong unit type \"%s\"", l_price_token);
-                    l_iter = 0;
-                    break;
-                }
-                continue;
-            case 5:
-//                if (!(l_price->wallet = dap_chain_wallet_open(l_price_token, dap_config_get_item_str_default(g_config, "resources", "wallets_path", NULL)))) {
-//                    log_it(L_ERROR, "Error parsing pricelist: can't open wallet \"%s\"", l_price_token);
-//                    l_iter = 0;
-//                    break;
-//                }
-                continue;
-            case 6:
-                log_it(L_INFO, "Price item correct, added to service");
-                ret++;
-                break;
-            default:
-                break;
-            }
-            log_it(L_DEBUG, "Done with price item %d", i);
-            if (l_iter == 6)
-                DL_APPEND(a_srv->pricelist, l_price);
-            break; // double break exits tokenizer loop and steps to next price item
-        }
-        if (l_iter != 6)
-            DAP_DELETE(l_price);
-        DAP_DELETE(l_price_str);
-    }
-    return ret;
+    return 0;
 }
 
 /**
@@ -1139,6 +983,13 @@ dap_chain_net_srv_t* dap_chain_net_srv_add(dap_chain_net_srv_uid_t a_uid,
     service_list_t *l_sdata = NULL;
     dap_chain_net_srv_t * l_srv = NULL;
     dap_chain_net_srv_uid_t l_uid = {.uint64 = a_uid.uint64 }; // Copy to let then compiler to pass args via registers not stack
+    const char* l_net_name_str = dap_config_get_item_str_default(g_config, a_config_section, "net", "");
+    dap_chain_net_t *l_net = dap_chain_net_by_name(l_net_name_str);
+    if(!l_net && a_uid.uint64 == 1){
+        log_it(L_ERROR, "Can't find net [%s]. Check configuration file.", l_net_name_str);
+        return NULL;
+    }
+
     pthread_mutex_lock(&s_srv_list_mutex);
     HASH_FIND(hh, s_srv_list, &l_uid, sizeof(l_uid), l_sdata);
     if(!l_sdata) {
@@ -1162,11 +1013,14 @@ dap_chain_net_srv_t* dap_chain_net_srv_add(dap_chain_net_srv_uid_t a_uid,
         l_sdata->uid = l_uid;
         strncpy(l_sdata->name, a_config_section, sizeof(l_sdata->name) - 1);
         l_sdata->srv = l_srv;
-        dap_chain_net_srv_price_apply_from_my_order(l_srv, a_config_section);
-//        dap_chain_net_srv_parse_pricelist(l_srv, a_config_section);
+        if (a_uid.uint64 == 1){
+            l_srv->grace_period = dap_config_get_item_uint32_default(g_config, a_config_section, "grace_period", DAP_CHAIN_NET_SRV_GRACE_PERIOD_DEFAULT);
+            l_srv->allow_free_srv = dap_config_get_item_bool_default(g_config, a_config_section, "allow_free_srv", false);
+        }
         HASH_ADD(hh, s_srv_list, uid, sizeof(l_srv->uid), l_sdata);
-        if (l_srv->pricelist)
-            dap_ledger_tx_add_notify(l_srv->pricelist->net->pub.ledger, dap_stream_ch_chain_net_srv_tx_cond_added_cb, NULL);
+        dap_stream_ch_chain_net_srv_init(l_srv);
+        if (l_net)
+            dap_ledger_tx_add_notify(l_net->pub.ledger, dap_stream_ch_chain_net_srv_tx_cond_added_cb, NULL);
     }else{
         log_it(L_ERROR, "Already present service with 0x%016"DAP_UINT64_FORMAT_X, a_uid.uint64);
     }
@@ -1178,14 +1032,26 @@ dap_chain_net_srv_t* dap_chain_net_srv_add(dap_chain_net_srv_uid_t a_uid,
  * @brief dap_chain_net_srv_del
  * @param a_srv
  */
-void dap_chain_net_srv_del(dap_chain_net_srv_t * a_srv)
+void dap_chain_net_srv_del(dap_chain_net_srv_t *a_srv)
 {
+// sanity check
+    dap_return_if_pass(!a_srv);
+// func work
     service_list_t *l_sdata;
-    if(!a_srv)
-        return;
+    // delete srv from hash table
     pthread_mutex_lock(&s_srv_list_mutex);
     HASH_FIND(hh, s_srv_list, a_srv, sizeof(dap_chain_net_srv_uid_t), l_sdata);
     if(l_sdata) {
+        // grace table clean
+        dap_chain_net_srv_grace_usage_t *l_gdata, *l_gdata_tmp;
+        pthread_mutex_lock(&a_srv->grace_mutex);
+        HASH_ITER(hh, a_srv->grace_hash_tab, l_gdata, l_gdata_tmp)
+        {
+            HASH_DEL(a_srv->grace_hash_tab, l_gdata);
+            DAP_DELETE(l_gdata);
+        } 
+        pthread_mutex_unlock(&a_srv->grace_mutex);
+
         HASH_DEL(s_srv_list, l_sdata);
         pthread_mutex_destroy(&a_srv->banlist_mutex);
         DAP_DELETE(a_srv);
@@ -1250,6 +1116,7 @@ void dap_chain_net_srv_del_all(void)
     pthread_mutex_lock(&s_srv_list_mutex);
     HASH_ITER(hh, s_srv_list , l_sdata, l_sdata_tmp)
     {
+        // Clang bug at this, l_sdata should change at every loop cycle
         HASH_DEL(s_srv_list, l_sdata);
         pthread_mutex_destroy(&l_sdata->srv->banlist_mutex);
         DAP_DELETE(l_sdata->srv);
@@ -1263,7 +1130,7 @@ void dap_chain_net_srv_del_all(void)
  * @param a_uid
  * @return
  */
-dap_chain_net_srv_t * dap_chain_net_srv_get(dap_chain_net_srv_uid_t a_uid)
+dap_chain_net_srv_t *dap_chain_net_srv_get(dap_chain_net_srv_uid_t a_uid)
 {
     service_list_t *l_sdata = NULL;
     pthread_mutex_lock(&s_srv_list_mutex);
diff --git a/modules/net/srv/dap_chain_net_srv_order.c b/modules/net/srv/dap_chain_net_srv_order.c
index 9a27a68489..1141d2584c 100644
--- a/modules/net/srv/dap_chain_net_srv_order.c
+++ b/modules/net/srv/dap_chain_net_srv_order.c
@@ -44,6 +44,7 @@ OC : Oceania			geonameId=6255151
 SA : South America		geonameId=6255150
 AN : Antarctica			geonameId=6255152
  */
+
 char *s_server_continents[]={
         "None",
         "Africa",
@@ -449,13 +450,15 @@ int dap_chain_net_srv_order_find_all_by(dap_chain_net_t * a_net,const dap_chain_
                                         const dap_chain_net_srv_uid_t a_srv_uid,
                                         const dap_chain_net_srv_price_unit_uid_t a_price_unit,const char a_price_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
                                         const uint256_t a_price_min, const uint256_t a_price_max,
-                                        dap_chain_net_srv_order_t ** a_output_orders, size_t * a_output_orders_count)
+                                        dap_list_t** a_output_orders, size_t * a_output_orders_count)
 {
     if (!a_net || !a_output_orders || !a_output_orders_count)
         return -1;
     size_t l_orders_size = 0, l_output_orders_count = 0;
     *a_output_orders = NULL;
 
+    dap_list_t* l_out_list = NULL;
+
     for (int i = 0; i < 2; i++) {
         char *l_gdb_group_str = i ? dap_chain_net_srv_order_get_gdb_group(a_net)
                                   : dap_chain_net_srv_order_get_common_group(a_net);
@@ -464,7 +467,6 @@ int dap_chain_net_srv_order_find_all_by(dap_chain_net_t * a_net,const dap_chain_
         log_it( L_DEBUG, "Loaded %zu orders", l_orders_count);
         dap_chain_net_srv_order_t *l_order = NULL;
         for (size_t i = 0; i < l_orders_count; i++) {
-            DAP_DEL_Z(l_order);
             l_order = dap_chain_net_srv_order_read(l_orders[i].value, l_orders[i].value_len);
             if (!l_order) {
                 dap_global_db_del_sync(l_gdb_group_str, l_orders[i].key);
@@ -496,16 +498,16 @@ int dap_chain_net_srv_order_find_all_by(dap_chain_net_t * a_net,const dap_chain_
             if (a_price_ticker && strcmp( l_order->price_ticker, a_price_ticker))
                 continue;
             size_t l_order_mem_size = dap_chain_net_srv_order_get_size(l_order);
-            *a_output_orders = DAP_REALLOC(*a_output_orders, l_orders_size + l_order_mem_size);
-            memcpy((byte_t *)*a_output_orders + l_orders_size, l_order, l_order_mem_size);
+            dap_chain_net_srv_order_t *l_output_order = DAP_DUP_SIZE(l_order, l_order_mem_size);
             DAP_DEL_Z(l_order);
-            l_orders_size += l_order_mem_size;
+            l_out_list = dap_list_append(l_out_list, l_output_order);
             l_output_orders_count++;
         }
         dap_global_db_objs_delete(l_orders, l_orders_count);
         DAP_DELETE(l_gdb_group_str);
     }
     *a_output_orders_count = l_output_orders_count;
+    *a_output_orders = l_out_list;
     return 0;
 }
 
diff --git a/modules/net/srv/dap_chain_net_srv_stream_session.c b/modules/net/srv/dap_chain_net_srv_stream_session.c
index 63ff8c9de4..ddf96cb51d 100644
--- a/modules/net/srv/dap_chain_net_srv_stream_session.c
+++ b/modules/net/srv/dap_chain_net_srv_stream_session.c
@@ -133,7 +133,7 @@ dap_chain_net_srv_usage_t* dap_chain_net_srv_usage_find_unsafe (dap_chain_net_sr
                                                                              uint32_t a_usage_id)
 {
     dap_chain_net_srv_usage_t * l_ret = NULL;
-    if (a_srv_session->usage_active->id == a_usage_id)
+    if (a_srv_session && a_srv_session->usage_active && a_srv_session->usage_active->id == a_usage_id)
         l_ret = a_srv_session->usage_active;
     return  l_ret;
 }
diff --git a/modules/net/srv/include/dap_chain_net_srv.h b/modules/net/srv/include/dap_chain_net_srv.h
index 8669a791d9..938efa969a 100755
--- a/modules/net/srv/include/dap_chain_net_srv.h
+++ b/modules/net/srv/include/dap_chain_net_srv.h
@@ -33,6 +33,8 @@ along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/lic
 #include "dap_stream_ch.h"
 #include "dap_time.h"
 
+#define DAP_CHAIN_NET_SRV_GRACE_PERIOD_DEFAULT 60
+
 //Service direction
 enum dap_chain_net_srv_order_direction{
     SERV_DIR_BUY = 1,
@@ -41,6 +43,10 @@ enum dap_chain_net_srv_order_direction{
 };
 typedef byte_t dap_chain_net_srv_order_direction_t;
 
+typedef struct {
+    intmax_t limits_bytes; // Bytes provided for using the service left
+    time_t limits_ts; //Time provided for using the service
+} dap_stream_ch_chain_net_srv_remain_service_store_t;
 
 typedef struct dap_chain_net_srv_abstract
 {
@@ -111,16 +117,20 @@ typedef struct dap_chain_net_srv_price
 #define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ENOUGH         0x00000402
 #define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NOT_ACCEPT_TOKEN   0x00000403
 #define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_WRONG_SRV_UID      0x00000404
-#define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_WRONG_SIZE                 0x00000405
-#define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_BIG_SIZE                   0x00000406
+#define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_NO_NEW_COND        0x00000405
+#define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_WRONG_SIZE                 0x00000406
+#define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_BIG_SIZE                   0x00000407
+#define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_NEW_TX_COND_NOT_ENOUGH     0x00000408
 #define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_RECEIPT_CANT_FIND          0x00000500
 #define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_RECEIPT_NO_SIGN            0x00000501
 #define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_RECEIPT_WRONG_PKEY_HASH    0x00000502
 #define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_RECEIPT_BANNED_PKEY_HASH   0x00000503
+#define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_RECEIPT_IS_NOT_PRESENT     0x00000504
 #define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_PRICE_NOT_FOUND            0x00000600
 #define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_WRONG_HASH                 0x00000BAD
 #define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_ALLOC_MEMORY_ERROR         0x00BADA55
 
+
 #define DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_UNKNOWN                    0xffffffff
 // TYPE_REQUEST
 typedef struct dap_stream_ch_chain_net_srv_pkt_request_hdr{
@@ -192,7 +202,7 @@ typedef struct dap_chain_net_srv_grace {
     dap_stream_worker_t *stream_worker;
     dap_stream_ch_uuid_t ch_uuid;
     dap_chain_net_srv_usage_t *usage;
-    dap_events_socket_uuid_t timer_es_uuid;
+    dap_timerfd_t *timer;
     dap_stream_ch_chain_net_srv_pkt_request_t *request;
     size_t request_size;
 } dap_chain_net_srv_grace_t;
@@ -209,12 +219,6 @@ typedef struct dap_chain_net_srv_client_remote
     struct dap_chain_net_srv_client_remote *next;
 } dap_chain_net_srv_client_remote_t;
 
-typedef struct {
-    intmax_t limits_bytes; // Bytes provided for using the service left
-    time_t limits_ts; //Time provided for using the service
-    dap_chain_net_srv_price_unit_uid_t remain_units_type;
-} dap_stream_ch_chain_net_srv_remain_service_store_t;
-
 typedef int  (*dap_chain_net_srv_callback_data_t)(dap_chain_net_srv_t *, uint32_t, dap_chain_net_srv_client_remote_t *, const void *, size_t);
 typedef void* (*dap_chain_net_srv_callback_custom_data_t)(dap_chain_net_srv_t *, dap_chain_net_srv_usage_t *, const void *, size_t, size_t *);
 typedef void (*dap_chain_net_srv_callback_ch_t)(dap_chain_net_srv_t *, dap_stream_ch_t *);
@@ -256,11 +260,17 @@ typedef struct dap_chain_net_srv_callbacks {
     dap_chain_net_srv_callback_ch_t stream_ch_write;
 } dap_chain_net_srv_callbacks_t;
 
+typedef struct dap_chain_net_srv_grace_usage {
+    dap_hash_fast_t tx_cond_hash;
+    dap_chain_net_srv_grace_t *grace;
+    UT_hash_handle hh;
+} dap_chain_net_srv_grace_usage_t;
+
 typedef struct dap_chain_net_srv
 {
     dap_chain_net_srv_uid_t uid; // Unique ID for service.
     dap_chain_net_srv_abstract_t srv_common;
-    dap_chain_net_srv_price_t *pricelist;
+    // dap_chain_net_srv_price_t *pricelist;
 
     bool allow_free_srv;
     uint32_t grace_period;
@@ -269,6 +279,9 @@ typedef struct dap_chain_net_srv
 
     dap_chain_net_srv_callbacks_t callbacks;
 
+    dap_chain_net_srv_grace_usage_t *grace_hash_tab;
+    pthread_mutex_t grace_mutex;
+
     // Pointer to inheritor object
     void *_inheritor;
     // Pointer to internal server structure
@@ -329,10 +342,7 @@ DAP_STATIC_INLINE const char * dap_chain_net_srv_price_unit_uid_to_str( dap_chai
 {
     switch ( a_uid.enm) {
         case SERV_UNIT_B: return "BYTE";
-        case SERV_UNIT_KB: return "KILOBYTE";
-        case SERV_UNIT_MB: return "MEGABYTE";
         case SERV_UNIT_SEC: return "SECOND";
-        case SERV_UNIT_DAY: return  "DAY";
         case SERV_UNIT_PCS: return "PIECES";
         default: return "UNKNOWN";
     }
@@ -341,14 +351,8 @@ DAP_STATIC_INLINE const char * dap_chain_net_srv_price_unit_uid_to_str( dap_chai
 DAP_STATIC_INLINE dap_chain_net_srv_price_unit_uid_t dap_chain_net_srv_price_unit_uid_from_str( const char  *a_unit_str )
 {
     dap_chain_net_srv_price_unit_uid_t l_price_unit = { .enm = SERV_UNIT_UNDEFINED };
-    if(!dap_strcmp(a_unit_str, "mb"))
-        l_price_unit.enm = SERV_UNIT_MB;
-    else if(!dap_strcmp(a_unit_str, "sec"))
+    if(!dap_strcmp(a_unit_str, "sec"))
         l_price_unit.enm = SERV_UNIT_SEC;
-    else if(!dap_strcmp(a_unit_str, "day"))
-        l_price_unit.enm = SERV_UNIT_DAY;
-    else if(!dap_strcmp(a_unit_str, "kb"))
-        l_price_unit.enm = SERV_UNIT_KB;
     else if(!dap_strcmp(a_unit_str, "b") || !dap_strcmp(a_unit_str, "bytes"))
         l_price_unit.enm = SERV_UNIT_B;
     else if(!dap_strcmp(a_unit_str, "pcs") || !dap_strcmp(a_unit_str, "pieces"))
diff --git a/modules/net/srv/include/dap_chain_net_srv_order.h b/modules/net/srv/include/dap_chain_net_srv_order.h
index 8ebb4ed5d0..29906fce08 100644
--- a/modules/net/srv/include/dap_chain_net_srv_order.h
+++ b/modules/net/srv/include/dap_chain_net_srv_order.h
@@ -28,7 +28,6 @@ along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/lic
 #include "dap_string.h"
 #include "dap_chain_common.h"
 #include "dap_chain_net_srv.h"
-
 typedef struct dap_chain_net_srv_order_old
 {
     uint16_t version;
@@ -104,7 +103,7 @@ int dap_chain_net_srv_order_find_all_by(
     const dap_chain_net_srv_price_unit_uid_t a_price_unit,
     const char a_price_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
     const uint256_t a_price_min, const uint256_t a_price_max,
-    dap_chain_net_srv_order_t** a_output_orders,
+    dap_list_t** a_output_orders,
     size_t* a_output_orders_count);
 
 int dap_chain_net_srv_order_delete_by_hash_str_sync( dap_chain_net_t * a_net,const char * a_hash_str );
diff --git a/modules/net/srv/include/dap_chain_net_srv_stream_session.h b/modules/net/srv/include/dap_chain_net_srv_stream_session.h
index dcd2088c88..3ec4c2c797 100644
--- a/modules/net/srv/include/dap_chain_net_srv_stream_session.h
+++ b/modules/net/srv/include/dap_chain_net_srv_stream_session.h
@@ -52,12 +52,13 @@ typedef struct dap_chain_net_srv_usage{
     dap_chain_hash_fast_t tx_cond_hash;
     dap_chain_hash_fast_t client_pkey_hash;
     dap_chain_hash_fast_t static_order_hash;
-    dap_events_socket_uuid_t timer_es_uuid;
+    dap_timerfd_t *save_limits_timer;
     char token_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
     bool is_active;
     bool is_free;
     bool is_grace;
     bool is_waiting_new_tx_cond;
+    bool is_waiting_new_tx_cond_in_ledger;
     bool is_waiting_first_receipt_sign;
     bool is_limits_changed;
 //    UT_hash_handle hh; //
diff --git a/modules/service/datum/dap_chain_net_srv_datum.c b/modules/service/datum/dap_chain_net_srv_datum.c
index 0f3f5ae93a..202795189e 100644
--- a/modules/service/datum/dap_chain_net_srv_datum.c
+++ b/modules/service/datum/dap_chain_net_srv_datum.c
@@ -51,14 +51,6 @@ int dap_chain_net_srv_datum_init()
         return -1;
     }
     s_srv_datum->uid.uint64 = DAP_CHAIN_NET_SRV_DATUM_ID;
-    dap_chain_net_srv_price_apply_from_my_order(s_srv_datum, "srv_datum");
-    dap_chain_net_srv_price_t *l_price;
-    DL_FOREACH(s_srv_datum->pricelist, l_price) {
-        dap_chain_net_t *l_net = l_price->net;
-        if (!l_net)
-            continue;
-        dap_chain_net_srv_order_add_notify_callback(l_net, s_order_notficator, l_net);
-    }
     return 0;
 }
 
@@ -214,10 +206,7 @@ void s_order_notficator(dap_store_obj_t *a_obj, void *a_arg)
     if (!dap_chain_net_srv_uid_compare(l_order->srv_uid, s_srv_datum->uid))
         return; // order from another service
     dap_chain_net_srv_price_t *l_price = NULL;
-    DL_FOREACH(s_srv_datum->pricelist, l_price) {
-        if (l_price->net == l_net)
-            break;
-    }
+
     if (!l_price || l_price->net != l_net) {
         log_it(L_DEBUG, "Price for net %s is not set", l_net->pub.name);
         return; // price not set for this network
diff --git a/modules/service/vpn/dap_chain_net_srv_vpn.c b/modules/service/vpn/dap_chain_net_srv_vpn.c
index fc801241fe..6c81105973 100644
--- a/modules/service/vpn/dap_chain_net_srv_vpn.c
+++ b/modules/service/vpn/dap_chain_net_srv_vpn.c
@@ -101,7 +101,6 @@ typedef struct iphdr dap_os_iphdr_t;
 #include "dap_chain_node_cli.h"
 #include "dap_chain_ledger.h"
 #include "dap_events.h"
-#include "dap_context.h"
 
 #define LOG_TAG "dap_chain_net_srv_vpn"
 
@@ -197,6 +196,7 @@ static dap_stream_ch_chain_net_srv_remain_service_store_t* s_callback_get_remain
                                          dap_chain_net_srv_client_remote_t * a_srv_client);
 static int s_callback_save_remain_service(dap_chain_net_srv_t * a_srv,  uint32_t usage_id, dap_chain_net_srv_client_remote_t * a_srv_client);
 static bool s_save_limits(void* arg);
+static char* s_ch_vpn_get_my_pkey_str(dap_chain_net_srv_usage_t* a_usage);
 // Stream callbacks
 static void s_ch_vpn_new(dap_stream_ch_t* ch, void* arg);
 static void s_ch_vpn_delete(dap_stream_ch_t* ch, void* arg);
@@ -248,6 +248,7 @@ static bool s_tun_client_send_data_unsafe(dap_chain_net_srv_ch_vpn_t * l_ch_vpn,
     size_t l_data_sent = dap_stream_ch_pkt_write_unsafe(l_ch_vpn->ch, DAP_STREAM_CH_PKT_TYPE_NET_SRV_VPN_DATA, l_pkt_out, l_data_to_send);
     s_update_limits(l_ch_vpn->ch,l_srv_session,l_usage, l_data_sent);
     l_srv_session->stats.bytes_recv += l_data_sent;
+    l_usage->client->bytes_received += l_data_sent;
     if ( l_data_sent < l_data_to_send){
         log_it(L_WARNING, "Wasn't sent all the data in tunnel (%zd was sent from %zd): probably buffer overflow", l_data_sent, l_data_to_send);
         l_srv_session->stats.bytes_recv_lost += l_data_to_send - l_data_sent;
@@ -281,6 +282,7 @@ static bool s_tun_client_send_data_inter(dap_events_socket_t * a_es_input, dap_c
         return false;
     }else{
         l_srv_session->stats.bytes_recv += l_data_sent;
+        l_usage->client->bytes_received += l_data_sent;
         l_srv_session->stats.packets_recv++;
         return true;
     }
@@ -870,6 +872,10 @@ static int s_vpn_service_create(dap_config_t * g_config)
 
 
     dap_chain_net_srv_t* l_srv = dap_chain_net_srv_add(l_uid, "srv_vpn", &l_srv_callbacks);
+    if (!l_srv){
+        log_it(L_CRITICAL, "VPN service initialization failed.");
+        return -2;
+    }
 
     dap_chain_net_srv_vpn_t* l_srv_vpn  = DAP_NEW_Z( dap_chain_net_srv_vpn_t);
     if(!l_srv_vpn) {
@@ -895,19 +901,24 @@ int dap_chain_net_srv_vpn_init(dap_config_t * g_config) {
     s_vpn_tun_init();
 
     log_it(L_DEBUG,"Initializing TUN driver...");
-    if(s_vpn_tun_create(g_config) != 0){
+    if(s_vpn_tun_create(g_config)){
         log_it(L_CRITICAL, "Error initializing TUN device driver!");
+        dap_chain_net_srv_vpn_deinit();
         return -1;
     }
 
     log_it(L_INFO,"TUN driver configured successfuly");
-    s_vpn_service_create(g_config);
+    if (s_vpn_service_create(g_config)){
+        log_it(L_CRITICAL, "VPN service creating failed");
+        dap_chain_net_srv_vpn_deinit();
+        return -2;
+    }
     dap_stream_ch_proc_add(DAP_STREAM_CH_NET_SRV_ID_VPN, s_ch_vpn_new, s_ch_vpn_delete, s_ch_packet_in,
             s_ch_packet_out);
 
     // add console command to display vpn statistics
     dap_cli_server_cmd_add ("vpn_stat", com_vpn_statistics, "VPN statistics",
-            "vpn_stat -net <net name> [-full]\n"
+            "vpn_stat -net <net_name> [-full]\n"
             );
     return 0;
 }
@@ -919,8 +930,8 @@ void dap_chain_net_srv_vpn_deinit(void)
 {
     pthread_mutex_destroy(&s_tun_sockets_mutex_started);
     pthread_cond_destroy(&s_tun_sockets_cond_started);
-    DAP_DELETE(s_srv_vpn_addr);
-    DAP_DELETE(s_srv_vpn_mask);
+    DAP_DEL_Z(s_srv_vpn_addr);
+    DAP_DEL_Z(s_srv_vpn_mask);
     if(s_raw_server)
         DAP_DELETE(s_raw_server);
 }
@@ -950,10 +961,8 @@ static int s_callback_response_success(dap_chain_net_srv_t * a_srv, uint32_t a_u
     size_t l_receipt_size = a_request_size;
     log_it( L_INFO, "s_callback_response_success is called");
 
-//    dap_stream_ch_chain_net_srv_pkt_request_t * l_request =  (dap_stream_ch_chain_net_srv_pkt_request_t *) a_request;
-//    dap_chain_net_srv_stream_session_t * l_srv_session = (dap_chain_net_srv_stream_session_t *) a_srv_client->ch->stream->session->_inheritor;
     dap_chain_net_srv_stream_session_t * l_srv_session = (dap_chain_net_srv_stream_session_t *) a_srv_client->ch->stream->session->_inheritor;
-    dap_chain_net_srv_usage_t * l_usage_active = l_srv_session->usage_active;// dap_chain_net_srv_usage_find_unsafe(l_srv_session,a_usage_id);
+    dap_chain_net_srv_usage_t * l_usage_active = l_srv_session->usage_active;
     dap_chain_net_srv_ch_vpn_t * l_srv_ch_vpn =(dap_chain_net_srv_ch_vpn_t*) a_srv_client->ch->stream->channel[DAP_CHAIN_NET_SRV_VPN_ID] ?
             a_srv_client->ch->stream->channel[DAP_CHAIN_NET_SRV_VPN_ID]->internal : NULL;
     if ( !l_usage_active){
@@ -981,47 +990,30 @@ static int s_callback_response_success(dap_chain_net_srv_t * a_srv, uint32_t a_u
         l_args->srv = a_srv;
         l_args->srv_client = a_srv_client;
         l_args->usage_id = a_usage_id;
-        l_usage_active->timer_es_uuid = dap_timerfd_start_on_worker(l_usage_active->client->stream_worker->worker, 60 * 1000,
-                                                             (dap_timerfd_callback_t)s_save_limits, l_args)->esocket_uuid;
+        l_usage_active->save_limits_timer = dap_timerfd_start_on_worker(l_usage_active->client->stream_worker->worker, 60 * 1000,
+                                                             (dap_timerfd_callback_t)s_save_limits, l_args);
         l_srv_session->limits_units_type.uint32 = l_usage_active->receipt->receipt_info.units_type.uint32;
         switch( l_usage_active->receipt->receipt_info.units_type.enm){
-            case SERV_UNIT_DAY:{
-                l_srv_session->last_update_ts = time(NULL);
-                if (!l_usage_active->is_grace && l_srv_session->limits_ts <= 0){
-                    l_srv_session->limits_ts = (time_t)l_usage_active->receipt->receipt_info.units*24*3600;
-                    log_it(L_INFO,"%"DAP_UINT64_FORMAT_U" seconds more for VPN usage", l_usage_active->receipt->receipt_info.units);
-                }
-            } break;
             case SERV_UNIT_SEC:{
                 l_srv_session->last_update_ts = time(NULL);
                 if (!l_usage_active->is_grace && l_srv_session->limits_ts <= 0){
+                    log_it(L_INFO,"%"DAP_UINT64_FORMAT_U" seconds more for VPN usage", l_srv_session->limits_ts < 0 ? l_usage_active->receipt->receipt_info.units + l_srv_session->limits_ts :
+                                                                                                                        l_usage_active->receipt->receipt_info.units);
                     l_srv_session->limits_ts += (time_t)l_usage_active->receipt->receipt_info.units;
-                    log_it(L_INFO,"%"DAP_UINT64_FORMAT_U" seconds more for VPN usage", l_usage_active->receipt->receipt_info.units);
                 }
             } break;
             case SERV_UNIT_B:{
                 if (!l_usage_active->is_grace && l_srv_session->limits_bytes <= 0){
+                    log_it(L_INFO,"%"DAP_UINT64_FORMAT_U" bytes more for VPN usage", l_srv_session->limits_ts < 0 ? l_usage_active->receipt->receipt_info.units + l_srv_session->limits_ts :
+                                                                                                                        l_usage_active->receipt->receipt_info.units);
                     l_srv_session->limits_bytes = (uintmax_t) l_usage_active->receipt->receipt_info.units;
-                    log_it(L_INFO,"%"DAP_UINT64_FORMAT_U" bytes more for VPN usage", l_usage_active->receipt->receipt_info.units);
-                }
-            } break;
-            case SERV_UNIT_KB:{
-                if (!l_usage_active->is_grace && l_srv_session->limits_bytes <= 0){
-                    l_srv_session->limits_bytes = 1000ull * ( (uintmax_t) l_usage_active->receipt->receipt_info.units);
-                    log_it(L_INFO,"%"DAP_UINT64_FORMAT_U" bytes more for VPN usage", l_usage_active->receipt->receipt_info.units);
-                }
-            } break;
-            case SERV_UNIT_MB:{
-                if (!l_usage_active->is_grace && l_srv_session->limits_bytes <= 0){
-                    l_srv_session->limits_bytes = 1000000ull * ( (uintmax_t) l_usage_active->receipt->receipt_info.units);
-                    log_it(L_INFO,"%"DAP_UINT64_FORMAT_U" bytes more for VPN usage", l_usage_active->receipt->receipt_info.units);
                 }
             } break;
             default: {
                 log_it(L_WARNING, "VPN doesnt accept serv unit type 0x%08X", l_usage_active->receipt->receipt_info.units_type.uint32 );
+                dap_stream_ch_pkt_write_unsafe(l_usage_active->client->ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 );
                 dap_stream_ch_set_ready_to_write_unsafe(l_usage_active->client->ch,false);
                 dap_stream_ch_set_ready_to_read_unsafe(l_usage_active->client->ch,false);
-                dap_stream_ch_pkt_write_unsafe(l_usage_active->client->ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 );
             }
         }
     } else if (!l_usage_active->is_free && !l_usage_active->receipt && l_usage_active->is_grace){
@@ -1091,7 +1083,13 @@ static dap_stream_ch_chain_net_srv_remain_service_store_t* s_callback_get_remain
     dap_chain_net_t *l_net = l_usage->net;
 
     // get remain units from DB
-    char *l_remain_limits_gdb_group =  dap_strdup_printf( "local.srv_pay.%s.vpn_srv.remain_limits", l_net->pub.name);
+    char *l_server_pkey_hash = s_ch_vpn_get_my_pkey_str(l_usage);
+    if (!l_server_pkey_hash){
+        log_it(L_DEBUG, "Can't get server pkey hash.");
+        return NULL;
+    }
+    char *l_remain_limits_gdb_group =  dap_strdup_printf( "%s.0x%016"DAP_UINT64_FORMAT_x".remain_limits.%s", l_net->pub.gdb_groups_prefix, a_srv->uid.uint64, l_server_pkey_hash);
+    DAP_DEL_Z(l_server_pkey_hash);
     char *l_user_key = dap_chain_hash_fast_to_str_new(&l_usage->client_pkey_hash);
     log_it(L_DEBUG, "Checkout user %s in group %s", l_user_key, l_remain_limits_gdb_group);
     dap_stream_ch_chain_net_srv_remain_service_store_t* l_remain_service = NULL;
@@ -1112,6 +1110,33 @@ static bool s_save_limits(void* arg)
     return true;
 }
 
+static char* s_ch_vpn_get_my_pkey_str(dap_chain_net_srv_usage_t* a_usage)
+{
+    dap_chain_net_srv_usage_t* l_usage = a_usage;
+    if (!l_usage){
+        log_it(L_DEBUG, "Can't save remain servis. Usage is NULL.");
+        return NULL;
+    }
+
+    dap_chain_net_srv_price_t *l_price = l_usage->price;
+
+    dap_hash_fast_t price_pkey_hash = {};
+    size_t l_key_size = 0;
+    uint8_t *l_pub_key = dap_enc_key_serialize_pub_key(l_price->receipt_sign_cert->enc_key, &l_key_size);
+    if (!l_pub_key || !l_key_size)
+    {
+        log_it(L_ERROR, "Can't get pkey from cert %s.", l_price->receipt_sign_cert->name);
+        return NULL;
+    }
+
+    dap_hash_fast(l_pub_key, l_key_size, &price_pkey_hash);
+    DAP_DELETE(l_pub_key);
+    char* l_pkey_hash_str = dap_chain_hash_fast_to_str_new(&price_pkey_hash);
+
+    return l_pkey_hash_str;
+
+}
+
 static int s_callback_save_remain_service(dap_chain_net_srv_t * a_srv,  uint32_t a_usage_id,
                                           dap_chain_net_srv_client_remote_t * a_srv_client)
 {
@@ -1136,7 +1161,13 @@ static int s_callback_save_remain_service(dap_chain_net_srv_t * a_srv,  uint32_t
     dap_chain_net_t *l_net = l_usage->net;
 
     // save remain units from DB
-    char *l_remain_limits_gdb_group =  dap_strdup_printf( "local.srv_pay.%s.vpn_srv.remain_limits", l_net->pub.name);
+    char *l_server_pkey_hash = s_ch_vpn_get_my_pkey_str(l_usage);
+    if (!l_server_pkey_hash){
+        log_it(L_DEBUG, "Can't get server pkey hash.");
+        return -101;
+    }
+    char *l_remain_limits_gdb_group =  dap_strdup_printf( "%s.0x%016"DAP_UINT64_FORMAT_x".remain_limits.%s", l_net->pub.gdb_groups_prefix, a_srv->uid.uint64, l_server_pkey_hash);
+    DAP_DEL_Z(l_server_pkey_hash);
     char *l_user_key = dap_chain_hash_fast_to_str_new(&l_usage->client_pkey_hash);
     log_it(L_DEBUG, "Save user %s remain service into group %s", l_user_key, l_remain_limits_gdb_group);
 
@@ -1146,16 +1177,13 @@ static int s_callback_save_remain_service(dap_chain_net_srv_t * a_srv,  uint32_t
         l_receipt_sign = dap_chain_datum_tx_receipt_sign_get( l_srv_session->usage_active->receipt_next, l_srv_session->usage_active->receipt_next->size, 1);
     }
 
-    l_remain_service.remain_units_type.enm = l_srv_session->limits_units_type.enm;
-    switch(l_remain_service.remain_units_type.enm){
+//    l_remain_service.remain_units_type.enm = l_srv_session->limits_units_type.enm;
+    switch(l_srv_session->limits_units_type.enm){
         case SERV_UNIT_SEC:
-        case SERV_UNIT_DAY:
             l_remain_service.limits_ts = l_srv_session->limits_ts >= 0 ? l_srv_session->limits_ts : 0;
             if(l_receipt_sign)
                 l_remain_service.limits_ts += l_srv_session->usage_active->receipt_next->receipt_info.units;
             break;
-        case SERV_UNIT_MB:
-        case SERV_UNIT_KB:
         case SERV_UNIT_B:
             l_remain_service.limits_bytes = l_srv_session->limits_bytes >= 0 ? l_srv_session->limits_bytes : 0;            
             if (l_receipt_sign)
@@ -1249,14 +1277,16 @@ static void s_ch_vpn_delete(dap_stream_ch_t* a_ch, void* arg)
     dap_chain_net_srv_ch_vpn_t * l_ch_vpn = CH_VPN(a_ch);
     dap_chain_net_srv_vpn_t * l_srv_vpn =(dap_chain_net_srv_vpn_t *) l_ch_vpn->net_srv->_internal;
 
-    // So complicated to update usage client to be sure that nothing breaks it
-    usage_client_t * l_usage_client = NULL;
+    dap_chain_net_srv_usage_t *l_usage =  NULL;
 
     dap_chain_net_srv_stream_session_t *l_srv_session = DAP_CHAIN_NET_SRV_STREAM_SESSION(l_ch_vpn->ch->stream->session);
-    if (l_srv_session && l_srv_session->usage_active &&
-        l_srv_session->usage_active->client && l_srv_session->usage_active->client->stream_worker)
-        dap_timerfd_delete_mt(l_srv_session->usage_active->client->stream_worker->worker, l_srv_session->usage_active->timer_es_uuid);
+    if (l_srv_session)
+        l_usage =  l_srv_session->usage_active;
 
+    if (l_usage && l_usage->save_limits_timer){
+        dap_timerfd_delete_mt(l_usage->save_limits_timer->worker, l_usage->save_limits_timer->esocket_uuid);
+        l_usage->save_limits_timer = NULL;
+    }
     bool l_is_unleased = false;
     if ( l_ch_vpn->addr_ipv4.s_addr ){ // if leased address
         s_tun_send_msg_ip_unassigned_all(a_ch->stream_worker->worker->id,l_ch_vpn, l_ch_vpn->addr_ipv4); // Signal all the workers that we're switching off
@@ -1321,14 +1351,10 @@ static void s_update_limits(dap_stream_ch_t * a_ch ,
         return;
     }
 
-    if (a_usage->receipt->receipt_info.units_type.enm == SERV_UNIT_DAY ||
-        a_usage->receipt->receipt_info.units_type.enm == SERV_UNIT_SEC){
+    if (a_usage->receipt->receipt_info.units_type.enm == SERV_UNIT_SEC){
         time_t l_current_limit_ts = 0;
 
         switch( a_usage->receipt->receipt_info.units_type.enm){
-            case SERV_UNIT_DAY:{
-                l_current_limit_ts = (time_t)a_usage->receipt->receipt_info.units*24*3600;
-            } break;
             case SERV_UNIT_SEC:{
                 l_current_limit_ts = (time_t)a_usage->receipt->receipt_info.units;
             }
@@ -1358,49 +1384,36 @@ static void s_update_limits(dap_stream_ch_t * a_ch ,
             if ( a_usage->receipt){ // If there is next receipt add the time and request the next receipt
                 a_srv_session->limits_units_type.uint32 = a_usage->receipt->receipt_info.units_type.uint32;
                 switch( a_usage->receipt->receipt_info.units_type.enm){
-                case SERV_UNIT_DAY:{
-                    a_srv_session->limits_ts += (time_t)a_usage->receipt->receipt_info.units*24*3600;
-                    log_it(L_INFO,"%"DAP_UINT64_FORMAT_U" days more for VPN usage", a_usage->receipt->receipt_info.units);
-                } break;
                 case SERV_UNIT_SEC:{
                     a_srv_session->limits_ts += (time_t)a_usage->receipt->receipt_info.units;
                     log_it(L_INFO,"%"DAP_UINT64_FORMAT_U" seconds more for VPN usage", a_usage->receipt->receipt_info.units);
                 } break;
                 default: {
                     log_it(L_WARNING, "VPN doesnt accept serv unit type 0x%08X for limits_ts", a_usage->receipt->receipt_info.units_type.uint32 );
+                    dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 );
                     dap_stream_ch_set_ready_to_write_unsafe(a_ch,false);
                     dap_stream_ch_set_ready_to_read_unsafe(a_ch,false);
-                    dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 );
                 }
                 }
             }else if (!a_usage->is_grace){
                 log_it( L_NOTICE, "No activate receipt in usage, switch off write callback for channel");
                 dap_stream_ch_chain_net_srv_pkt_error_t l_err = { };
                 l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_RECEIPT_CANT_FIND ;
+                dap_stream_ch_pkt_write_unsafe(a_ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , &l_err, sizeof(l_err));
                 dap_stream_ch_set_ready_to_write_unsafe(a_ch,false);
                 dap_stream_ch_set_ready_to_read_unsafe(a_ch,false);
-                dap_stream_ch_pkt_write_unsafe(a_ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , &l_err, sizeof(l_err));
             }
         }
-    }else if ( a_usage->receipt->receipt_info.units_type.enm == SERV_UNIT_B ||
-               a_usage->receipt->receipt_info.units_type.enm == SERV_UNIT_KB ||
-               a_usage->receipt->receipt_info.units_type.enm == SERV_UNIT_MB ){
+    }else if ( a_usage->receipt->receipt_info.units_type.enm == SERV_UNIT_B){
         intmax_t current_limit_bytes = 0;
         if ( a_usage->receipt){// if we have active receipt and a_srv_session->last_update_ts == 0 then we counts units by traffic
             switch( a_usage->receipt->receipt_info.units_type.enm){
             case SERV_UNIT_B:{
                 current_limit_bytes = (uintmax_t) a_usage->receipt->receipt_info.units;
             } break;
-            case SERV_UNIT_KB:{
-                current_limit_bytes = 1000ull * ( (uintmax_t) a_usage->receipt->receipt_info.units);
-            } break;
-            case SERV_UNIT_MB:{
-                current_limit_bytes = 1000000ull * ( (uintmax_t) a_usage->receipt->receipt_info.units);
-            } break;
             }
         }
 
-
         a_srv_session->limits_bytes -= (intmax_t) a_bytes;
         a_usage->is_limits_changed = true;
         if (a_srv_session->limits_bytes && a_srv_session->limits_bytes < current_limit_bytes/2 && ! a_usage->receipt_next){
@@ -1426,28 +1439,20 @@ static void s_update_limits(dap_stream_ch_t * a_ch ,
                     a_srv_session->limits_bytes +=  (uintmax_t) a_usage->receipt->receipt_info.units;
                     log_it(L_INFO,"%"DAP_UINT64_FORMAT_U" bytes more for VPN usage", a_usage->receipt->receipt_info.units);
                 } break;
-                case SERV_UNIT_KB:{
-                    a_srv_session->limits_bytes += 1000ull * ( (uintmax_t) a_usage->receipt->receipt_info.units);
-                    log_it(L_INFO,"%"DAP_UINT64_FORMAT_U" bytes more for VPN usage", a_usage->receipt->receipt_info.units);
-                } break;
-                case SERV_UNIT_MB:{
-                    a_srv_session->limits_bytes += 1000000ull * ( (uintmax_t) a_usage->receipt->receipt_info.units);
-                    log_it(L_INFO,"%"DAP_UINT64_FORMAT_U" bytes more for VPN usage", a_usage->receipt->receipt_info.units);
-                } break;
                 default: {
                     log_it(L_WARNING, "VPN doesnt accept serv unit type 0x%08X for limits_bytes", a_usage->receipt->receipt_info.units_type.uint32 );
+                    dap_stream_ch_pkt_write_unsafe( a_ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 );
                     dap_stream_ch_set_ready_to_write_unsafe(a_ch,false);
                     dap_stream_ch_set_ready_to_read_unsafe(a_ch,false);
-                    dap_stream_ch_pkt_write_unsafe( a_ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 );
                 }
                 }
             }else if (!a_usage->is_grace){
                 log_it( L_NOTICE, "No activate receipt in usage, switch off write callback for channel");
                 dap_stream_ch_chain_net_srv_pkt_error_t l_err = { };
                 l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_RECEIPT_CANT_FIND ;
-                dap_stream_ch_set_ready_to_write_unsafe(a_ch,false);
-                dap_stream_ch_set_ready_to_read_unsafe(a_ch,false);
                 dap_stream_ch_pkt_write_unsafe( a_ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , &l_err, sizeof(l_err));
+                dap_stream_ch_set_ready_to_write_unsafe(a_ch,false);
+                dap_stream_ch_set_ready_to_read_unsafe(a_ch,false);              
             }
         }
 
@@ -1710,6 +1715,7 @@ void s_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
             "You can't provide service with ID %"DAP_UINT64_FORMAT_X" in net %s. Node role should be not lower than master\n",
             l_usage->service->uid.uint64, l_usage->net->pub.name
             );
+        l_usage->is_active = false;
         if (l_usage->client)
             dap_stream_ch_pkt_write_unsafe( l_usage->client->ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 );
         dap_stream_ch_set_ready_to_write_unsafe(a_ch,false);
@@ -1787,6 +1793,7 @@ void s_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                 size_t l_ret = dap_events_socket_write_unsafe(l_tun->es, l_vpn_pkt,
                     sizeof(l_vpn_pkt->header) + l_vpn_pkt->header.op_data.data_size) - sizeof(l_vpn_pkt->header);
                 l_srv_session->stats.bytes_sent += l_ret;
+                l_usage->client->bytes_sent += l_ret;
                 s_update_limits(a_ch, l_srv_session, l_usage, l_ret);
                 if (l_ret == l_vpn_pkt->header.op_data.data_size) {
                     l_srv_session->stats.packets_sent++;
@@ -1830,8 +1837,9 @@ static bool s_ch_packet_out(dap_stream_ch_t* a_ch, void* a_arg)
         dap_stream_ch_set_ready_to_read_unsafe(a_ch,false);
         return false;
     }
-    if ( (! l_usage->is_free) && (! l_usage->receipt && !l_usage->is_grace) ){
+    if ( (!l_usage->is_free) && (! l_usage->receipt && !l_usage->is_grace) ){
         log_it(L_WARNING, "No active receipt, switching off");
+        l_usage->is_active = false;
         if (l_usage->client)
             dap_stream_ch_pkt_write_unsafe( l_usage->client->ch , DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_NOTIFY_STOPPED , NULL, 0 );
         dap_stream_ch_set_ready_to_write_unsafe(a_ch,false);
diff --git a/modules/service/vpn/dap_chain_net_vpn_client.c b/modules/service/vpn/dap_chain_net_vpn_client.c
index fa9395dfd8..6465c2df8e 100644
--- a/modules/service/vpn/dap_chain_net_vpn_client.c
+++ b/modules/service/vpn/dap_chain_net_vpn_client.c
@@ -441,7 +441,8 @@ char *dap_chain_net_vpn_client_check_result(dap_chain_net_t *a_net, const char*
 {
 
 
-    dap_chain_net_srv_order_t * l_orders = NULL;
+    // dap_chain_net_srv_order_t 
+    dap_list_t* l_orders = NULL;
     size_t l_orders_num = 0;
     dap_chain_net_srv_uid_t l_srv_uid = { { 0 } };
     uint256_t l_price_min = {};
@@ -452,8 +453,8 @@ char *dap_chain_net_vpn_client_check_result(dap_chain_net_t *a_net, const char*
 
     if(dap_chain_net_srv_order_find_all_by(a_net, l_direction, l_srv_uid, l_price_unit, NULL, l_price_min, l_price_max, &l_orders, &l_orders_num) == 0){
         size_t l_orders_size = 0;
-        for(size_t i = 0; i < l_orders_num; i++) {
-            dap_chain_net_srv_order_t *l_order = (dap_chain_net_srv_order_t *) (((byte_t*) l_orders) + l_orders_size);
+        for(dap_list_t *l_temp = l_orders;l_temp; l_temp = l_orders->next) {
+            dap_chain_net_srv_order_t *l_order = (dap_chain_net_srv_order_t *) l_temp->data;
             //dap_chain_net_srv_order_dump_to_string(l_order, l_string_ret, l_hash_out_type);
             dap_chain_hash_fast_t l_hash={0};
             char *l_hash_str;
@@ -477,9 +478,9 @@ char *dap_chain_net_vpn_client_check_result(dap_chain_net_t *a_net, const char*
             }
             dap_string_append_printf(l_string_ret, "Order %s: State %s\n", l_hash_str, l_state_str);
             DAP_DELETE(l_hash_str);
-            l_orders_size += dap_chain_net_srv_order_get_size(l_order);
             //dap_string_append(l_string_ret, "\n");
         }
+        dap_list_free_full(l_orders, NULL);
     }
     // return str from dap_string_t
     return dap_string_free(l_string_ret, false);
diff --git a/modules/service/xchange/dap_chain_net_srv_xchange.c b/modules/service/xchange/dap_chain_net_srv_xchange.c
index 31e49902ec..dcdafae8ff 100644
--- a/modules/service/xchange/dap_chain_net_srv_xchange.c
+++ b/modules/service/xchange/dap_chain_net_srv_xchange.c
@@ -1220,100 +1220,54 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, v
                 }
                 case XCHANGE_CREATE_ERROR_INVALID_ARGUMENT: {
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "Some parameters could not be set during a function call");
-                    DAP_DELETE(l_hash_ret);
                     return -24;
                 }
                 case XCHANGE_CREATE_ERROR_TOKEN_TICKER_SELL_IS_NOT_FOUND_LEDGER: {
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "Token ticker %s not found", l_token_sell_str);
-                    DAP_DELETE(l_hash_ret);
                     return -6;
                 }
                 case XCHANGE_CREATE_ERROR_TOKEN_TICKER_BUY_IS_NOT_FOUND_LEDGER: {
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "Token ticker %s not found", l_token_buy_str);
-                    DAP_DELETE(l_hash_ret);
                     return -6;
                 }
                 case XCHANGE_CREATE_ERROR_RATE_IS_ZERO: {
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -rate n.n = buy / sell (eg: 1.0, 1.135)");
-                    DAP_DELETE(l_hash_ret);
                     return -9;
                 }
                 case XCHANGE_CREATE_ERROR_FEE_IS_ZERO: {
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -value <unsigned integer 256>");
-                    DAP_DELETE(l_hash_ret);
                     return -21;
                 }
                 case XCHANGE_CREATE_ERROR_VALUE_SELL_IS_ZERO: {
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -value <unsigned integer 256>");
-                    DAP_DELETE(l_hash_ret);
                     return -9;
                 }
                 case XCHANGE_CREATE_ERROR_INTEGER_OVERFLOW_WITH_SUM_OF_VALUE_AND_FEE: {
                     log_it(L_ERROR, "Integer overflow with sum of value and fee");
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "Integer overflow with sum of value and fee");
-                    DAP_DELETE(l_hash_ret);
                     return -22;
                 }
                 case XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_FOR_FEE_IN_SPECIFIED_WALLET: {
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nNot enough cash for fee in specified wallet", l_sign_str);
-                    DAP_DELETE(l_hash_ret);
                     return -23;
                 }
                 case XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_IN_SPECIFIED_WALLET: {
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nNot enough cash in specified wallet", l_sign_str);
-                    DAP_DELETE(l_hash_ret);
                     return -12;
                 }
                 case XCHANGE_CREATE_ERROR_MEMORY_ALLOCATED: {
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "Out of memory");
-                    DAP_DELETE(l_hash_ret);
                     return -1;
                 }
                 case XCHANGE_CREATE_ERROR_CAN_NOT_COMPOSE_THE_CONDITIONAL_TRANSACTION: {
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nCan't compose the conditional transaction", l_sign_str);
-                    DAP_DELETE(l_hash_ret);
                     return -14;
                 }
                 case XCHANGE_CREATE_ERROR_CAN_NOT_PUT_TRANSACTION_TO_MEMPOOL: {
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nCan't compose the conditional transaction", l_sign_str);
-                    DAP_DELETE(l_hash_ret);
                     return -15;
                 }
             }
-
-            // Create the price
-            dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t);
-            if (!l_price) {
-                log_it(L_CRITICAL, "Memory allocation error");
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Out of memory");
-                dap_chain_wallet_close(l_wallet);
-                return -1;
-            }
-            dap_stpcpy(l_price->token_sell, l_token_sell_str);
-            l_price->net = l_net;
-            dap_stpcpy(l_price->token_buy, l_token_buy_str);
-            l_price->datoshi_sell = l_datoshi_sell;
-            l_price->rate = l_rate;
-            l_price->fee = l_fee;
-            // Create conditional transaction
-            dap_chain_datum_tx_t *l_tx = s_xchange_tx_create_request(l_price, l_wallet);
-            if (!l_tx) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nCan't compose the conditional transaction", l_sign_str);
-                DAP_DELETE(l_price);
-                dap_chain_wallet_close(l_wallet);
-                return -14;
-            }
-            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_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);
-                return -15;
-            }
-            // To avoid confusion, the term "order" will apply to the original conditional exchange offer transactions.
-            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:{
-- 
GitLab