diff --git a/CMakeLists.txt b/CMakeLists.txt
index fb253140c30cc55ba369661e9bb0b5b218e1e36d..81f707bea95be8b29830ae3cce3b3780767ed916 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,7 +2,7 @@ project(cellframe-sdk C)
 cmake_minimum_required(VERSION 2.8)
 
 set(CMAKE_C_STANDARD 11)
-set(CELLFRAME_SDK_NATIVE_VERSION "2.6-56")
+set(CELLFRAME_SDK_NATIVE_VERSION "2.6-61")
 add_definitions ("-DCELLFRAME_SDK_VERSION=\"${CELLFRAME_SDK_NATIVE_VERSION}\"")
 
 set(DAPSDK_MODULES "")
diff --git a/dap-sdk/core/src/dap_list.c b/dap-sdk/core/src/dap_list.c
index 4c6ee31c2be86bd2c6f0c460445b6eeced7cf4e5..d5d1cb033fa8717c64d4271937e65a167fcdba9a 100755
--- a/dap-sdk/core/src/dap_list.c
+++ b/dap-sdk/core/src/dap_list.c
@@ -351,7 +351,6 @@ dap_list_t *dap_list_remove(dap_list_t *list, const void * data)
         {
             list = _dap_list_remove_link(list, tmp);
             dap_list_free1(tmp);
-
             break;
         }
     }
@@ -717,7 +716,7 @@ dap_list_t * dap_list_last(dap_list_t *list)
 {
     if(list)
     {
-        while(list->next)
+        while(list && list->next)
             list = list->next;
     }
 
diff --git a/dap-sdk/core/src/rpmalloc/rpmalloc.c b/dap-sdk/core/src/rpmalloc/rpmalloc.c
index 8b1bbcdfa549ed4552d0b487f47db5b00652fab8..cab7ed149d76e532c4321870af18b12b705f741c 100644
--- a/dap-sdk/core/src/rpmalloc/rpmalloc.c
+++ b/dap-sdk/core/src/rpmalloc/rpmalloc.c
@@ -2230,7 +2230,8 @@ rpaligned_alloc(size_t alignment, size_t size) {
       ptr = (void*)(((uintptr_t)ptr & ~(uintptr_t)align_mask) + alignment);
     //Mark as having aligned blocks
     span_t* span = (span_t*)((uintptr_t)ptr & _memory_span_mask);
-    span->flags |= SPAN_FLAG_ALIGNED_BLOCKS;
+    if (span)
+        span->flags |= SPAN_FLAG_ALIGNED_BLOCKS;
     return ptr;
   }
 
diff --git a/dap-sdk/core/src/unix/linux/dap_network_monitor.c b/dap-sdk/core/src/unix/linux/dap_network_monitor.c
index 3341ad089f80ec0b0d9df86938c5ade3e8ef0a40..27b2aa373e4dc7ce01da8a4d170051aa174b1307 100755
--- a/dap-sdk/core/src/unix/linux/dap_network_monitor.c
+++ b/dap-sdk/core/src/unix/linux/dap_network_monitor.c
@@ -189,7 +189,7 @@ static void _link_msg_handler(struct nlmsghdr *nlh,
 
 static void clear_results(dap_network_notification_t* cb_result)
 {
-    bzero(cb_result, sizeof (dap_network_notification_t));
+    memset(cb_result, 0,sizeof (dap_network_notification_t));
     cb_result->route.destination_address = (uint64_t) -1;
     cb_result->route.gateway_address = (uint64_t) -1;
 }
diff --git a/dap-sdk/crypto/src/dap_enc_base58.c b/dap-sdk/crypto/src/dap_enc_base58.c
index fba7d9a63399290516220f17d4bf207fed7242bc..84282f26f97c1b9da2101a7b8274f93091f89f06 100755
--- a/dap-sdk/crypto/src/dap_enc_base58.c
+++ b/dap-sdk/crypto/src/dap_enc_base58.c
@@ -98,6 +98,7 @@ size_t dap_enc_base58_decode(const char * a_in, void * a_out)
     }
 
     unsigned char l_out_u80[l_out_size_max];
+    memset(l_out_u80,0,l_out_size_max);
     unsigned char *l_out_u8 = l_out_u80;
     j = 0;
     switch (bytesleft) {
diff --git a/dap-sdk/crypto/src/dap_enc_bliss.c b/dap-sdk/crypto/src/dap_enc_bliss.c
index ce87eabdc2c342f6a65c622a2f02baa317c020ed..e75d0f8d8d46d6947e779c473b8b07b8cd8f218c 100755
--- a/dap-sdk/crypto/src/dap_enc_bliss.c
+++ b/dap-sdk/crypto/src/dap_enc_bliss.c
@@ -199,7 +199,7 @@ bliss_signature_t* dap_enc_sig_bliss_read_signature(const uint8_t *a_buf, size_t
     l_sign->kind = kind;
     l_sign->z1 = DAP_NEW_SIZE(int32_t, p.n * sizeof(int32_t));
     l_sign->z2 = DAP_NEW_SIZE(int32_t, p.n * sizeof(int32_t));
-    l_sign->c = DAP_NEW_SIZE(uint32_t, p.kappa * sizeof(int32_t));
+    l_sign->c = DAP_NEW_SIZE(unsigned int, p.kappa * sizeof(unsigned int));
     size_t l_shift_mem = sizeof(size_t) + sizeof(bliss_kind_t);
     memcpy(l_sign->z1, a_buf + l_shift_mem, p.n * sizeof(int32_t));
     l_shift_mem += p.n * sizeof(int32_t);
diff --git a/dap-sdk/crypto/src/dap_enc_key.c b/dap-sdk/crypto/src/dap_enc_key.c
index 4c82fd3a69b8859e84ef66efc27a3e37b3f5778e..a04f827079a692449a16d1f796f1117295b0905e 100755
--- a/dap-sdk/crypto/src/dap_enc_key.c
+++ b/dap-sdk/crypto/src/dap_enc_key.c
@@ -709,7 +709,8 @@ dap_enc_key_t *dap_enc_key_new(dap_enc_key_type_t a_key_type)
             s_callbacks[a_key_type].new_callback(ret);
         }
     }
-    ret->type = a_key_type;
+    if(ret)
+        ret->type = a_key_type;
     return ret;
 }
 
diff --git a/dap-sdk/crypto/src/dap_sign.c b/dap-sdk/crypto/src/dap_sign.c
index 4b390b5258004767fce2a537e3d91017b82a6615..fd3c76f9900204bbbeae0f188ea38c019501eaa7 100755
--- a/dap-sdk/crypto/src/dap_sign.c
+++ b/dap-sdk/crypto/src/dap_sign.c
@@ -500,27 +500,32 @@ dap_multi_sign_t *dap_multi_sign_deserialize(dap_sign_type_enum_t a_type, uint8_
     l_mem_shift++;
     memcpy(&l_sign->sign_count, &a_sign[l_mem_shift], 1);
     l_mem_shift++;
-    l_sign->key_seq = DAP_NEW_Z_SIZE(dap_multi_sign_keys_t, l_sign->sign_count * sizeof(dap_multi_sign_keys_t));
+    if(l_sign->sign_count)
+        l_sign->key_seq = DAP_NEW_Z_SIZE(dap_multi_sign_keys_t, l_sign->sign_count * sizeof(dap_multi_sign_keys_t));
     for (int i = 0; i < l_sign->sign_count; i++) {
         memcpy(&l_sign->key_seq[i].num, &a_sign[l_mem_shift], 1);
         l_mem_shift++;
         memcpy(&l_sign->key_seq[i].type, &a_sign[l_mem_shift], sizeof(dap_sign_type_t));
         l_mem_shift += sizeof(dap_sign_type_t);
     }
-    l_sign->meta = DAP_NEW_Z_SIZE(dap_multi_sign_meta_t, l_sign->sign_count * sizeof(dap_multi_sign_meta_t));
     size_t l_pkeys_size = 0, l_signes_size = 0;
-    for (int i = 0; i < l_sign->sign_count; i++) {
-        memcpy(&l_sign->meta[i].pkey_size, &a_sign[l_mem_shift], sizeof(uint32_t));
-        l_mem_shift += sizeof(uint32_t);
-        l_pkeys_size += l_sign->meta[i].pkey_size;
-        memcpy(&l_sign->meta[i].sign_size, &a_sign[l_mem_shift], sizeof(uint32_t));
-        l_mem_shift += sizeof(uint32_t);
-        l_signes_size += l_sign->meta[i].sign_size;
+    if(l_sign->sign_count){
+        l_sign->meta = DAP_NEW_Z_SIZE(dap_multi_sign_meta_t, l_sign->sign_count * sizeof(dap_multi_sign_meta_t));
+        for (int i = 0; i < l_sign->sign_count; i++) {
+            memcpy(&l_sign->meta[i].pkey_size, &a_sign[l_mem_shift], sizeof(uint32_t));
+            l_mem_shift += sizeof(uint32_t);
+            l_pkeys_size += l_sign->meta[i].pkey_size;
+            memcpy(&l_sign->meta[i].sign_size, &a_sign[l_mem_shift], sizeof(uint32_t));
+            l_mem_shift += sizeof(uint32_t);
+            l_signes_size += l_sign->meta[i].sign_size;
+        }
     }
-    l_sign->key_hashes = DAP_NEW_Z_SIZE(dap_chain_hash_fast_t, l_sign->total_count * sizeof(dap_chain_hash_fast_t));
-    for (int i = 0; i < l_sign->total_count; i++) {
-        memcpy(&l_sign->key_hashes[i], &a_sign[l_mem_shift], sizeof(dap_chain_hash_fast_t));
-        l_mem_shift += sizeof(dap_chain_hash_fast_t);
+    if(l_sign->total_count){
+        l_sign->key_hashes = DAP_NEW_Z_SIZE(dap_chain_hash_fast_t, l_sign->total_count * sizeof(dap_chain_hash_fast_t));
+        for (int i = 0; i < l_sign->total_count; i++) {
+            memcpy(&l_sign->key_hashes[i], &a_sign[l_mem_shift], sizeof(dap_chain_hash_fast_t));
+            l_mem_shift += sizeof(dap_chain_hash_fast_t);
+        }
     }
     uint32_t l_data_shift = 0, l_data_size = 0;
     l_sign->pub_keys = DAP_NEW_Z_SIZE(uint8_t, l_pkeys_size);
diff --git a/dap-sdk/net/client/dap_client.c b/dap-sdk/net/client/dap_client.c
index f70f5132dc6cc88ab9aaa2a4c8f60eeed972f25a..aa42b899ad6f2a7825a52282bbd7b491f867ba51 100644
--- a/dap-sdk/net/client/dap_client.c
+++ b/dap-sdk/net/client/dap_client.c
@@ -294,7 +294,7 @@ static void s_go_stage_on_client_worker_unsafe(dap_worker_t * a_worker,void * a_
     }
     l_client_pvt->refs_count--;
     if ( l_client_pvt->is_to_delete )
-        dap_client_delete_unsafe(l_client_pvt->client);
+        dap_client_delete_unsafe(l_client);
 
 }
 /**
diff --git a/dap-sdk/net/client/dap_client_pvt.c b/dap-sdk/net/client/dap_client_pvt.c
index 8cad69894eaa7bc5dc850187cbca3ed7025c86f3..77f47f987301ec0bd3638b64f460abccd700eab1 100644
--- a/dap-sdk/net/client/dap_client_pvt.c
+++ b/dap-sdk/net/client/dap_client_pvt.c
@@ -721,47 +721,52 @@ static void s_request_error(int a_err_code, void * a_obj)
  */
 static void s_request_response(void * a_response, size_t a_response_size, void * a_obj)
 {
-    dap_client_pvt_t * a_client_internal = (dap_client_pvt_t *) a_obj;
-    if(!a_client_internal || !a_client_internal->client){
-        if( !a_client_internal )
+    dap_client_pvt_t * l_client_pvt = (dap_client_pvt_t *) a_obj;
+    if (! l_client_pvt ||  !dap_client_pvt_check(l_client_pvt) ){
+        // Response received after client_pvt was deleted
+        return;
+    }
+
+    if(!l_client_pvt || !l_client_pvt->client){
+        if( !l_client_pvt )
             log_it(L_ERROR,"Client internal is NULL for s_request_response");
         else
             log_it(L_ERROR,"Client is NULL for s_request_response");
 
         return;
     }
-    a_client_internal->refs_count--;
+    l_client_pvt->refs_count--;
 
-    if (a_client_internal->is_to_delete){
-        if(a_client_internal->refs_count==0) // Was requested to delete until we was working with request
-            dap_client_delete_unsafe(a_client_internal->client); // Init delete
+    if (l_client_pvt->is_to_delete){
+        if(l_client_pvt->refs_count==0) // Was requested to delete until we was working with request
+            dap_client_delete_unsafe(l_client_pvt->client); // Init delete
         return;
     }
 
 
     //int l_ref = dap_client_pvt_get_ref(a_client_internal);
-    if(a_client_internal->is_encrypted) {
+    if(l_client_pvt->is_encrypted) {
         size_t l_response_dec_size_max = a_response_size ? a_response_size * 2 + 16 : 0;
         char * l_response_dec = a_response_size ? DAP_NEW_Z_SIZE(char, l_response_dec_size_max) : NULL;
         size_t l_response_dec_size = 0;
         if(a_response_size)
-            l_response_dec_size = dap_enc_decode(a_client_internal->session_key,
+            l_response_dec_size = dap_enc_decode(l_client_pvt->session_key,
                     a_response, a_response_size,
                     l_response_dec, l_response_dec_size_max,
                     DAP_ENC_DATA_TYPE_RAW);
 
-        if ( a_client_internal->request_response_callback )
-            a_client_internal->request_response_callback(a_client_internal->client, l_response_dec, l_response_dec_size);
+        if ( l_client_pvt->request_response_callback )
+            l_client_pvt->request_response_callback(l_client_pvt->client, l_response_dec, l_response_dec_size);
         else
-            log_it(L_ERROR, "NULL request_response_callback for encrypted client %p", a_client_internal->client );
+            log_it(L_ERROR, "NULL request_response_callback for encrypted client %p", l_client_pvt->client );
 
         if(l_response_dec)
             DAP_DELETE(l_response_dec);
     } else {
-        if ( a_client_internal->request_response_callback )
-            a_client_internal->request_response_callback(a_client_internal->client, a_response, a_response_size);
+        if ( l_client_pvt->request_response_callback )
+            l_client_pvt->request_response_callback(l_client_pvt->client, a_response, a_response_size);
         else
-            log_it(L_ERROR, "NULL request_response_callback for unencrypted  client %p", a_client_internal->client );
+            log_it(L_ERROR, "NULL request_response_callback for unencrypted  client %p", l_client_pvt->client );
     }
 
     //int l_ref2 = dap_client_pvt_get_ref(a_client_internal);
@@ -779,7 +784,7 @@ static void s_request_response(void * a_response, size_t a_response_size, void *
 static void s_enc_init_response(dap_client_t * a_client, void * a_response, size_t a_response_size)
 {
     dap_client_pvt_t * l_client_pvt = a_client ? DAP_CLIENT_PVT(a_client) : NULL;
-    if (!dap_client_pvt_check(l_client_pvt) ){
+    if (! l_client_pvt ||  !dap_client_pvt_check(l_client_pvt) ){
         // Response received after client_pvt was deleted
         return;
     }
@@ -885,6 +890,10 @@ static void s_enc_init_response(dap_client_t * a_client, void * a_response, size
 static void s_enc_init_error(dap_client_t * a_client, int a_err_code)
 {
     dap_client_pvt_t * l_client_pvt = DAP_CLIENT_PVT(a_client);
+    if (! l_client_pvt ||  !dap_client_pvt_check(l_client_pvt) ){
+        // Response received after client_pvt was deleted
+        return;
+    }
 
     //dap_client_internal_t * l_client_internal = dap_CLIENT_INTERNAL(a_client);
     log_it(L_ERROR, "ENC: Can't init ecnryption session, err code %d", a_err_code);
@@ -996,6 +1005,10 @@ static void s_stream_ctl_error(dap_client_t * a_client, int a_error)
     log_it(L_WARNING, "STREAM_CTL error %d", a_error);
 
     dap_client_pvt_t * l_client_pvt = DAP_CLIENT_PVT(a_client);
+    if (! l_client_pvt ||  !dap_client_pvt_check(l_client_pvt) ){
+        // Response received after client_pvt was deleted
+        return;
+    }
 
     if (a_error == ETIMEDOUT) {
         l_client_pvt->last_error = ERROR_NETWORK_CONNECTION_TIMEOUT;
diff --git a/dap-sdk/net/core/dap_events_socket.c b/dap-sdk/net/core/dap_events_socket.c
index 3e40b1524b52d2eb3d5b90701a7cda702640eb49..d9e9d8022c27638e2019f94b81438794b6b49115 100644
--- a/dap-sdk/net/core/dap_events_socket.c
+++ b/dap-sdk/net/core/dap_events_socket.c
@@ -361,6 +361,10 @@ dap_events_socket_t * dap_events_socket_queue_ptr_create_input(dap_events_socket
 dap_events_socket_t * s_create_type_queue_ptr(dap_worker_t * a_w, dap_events_socket_callback_queue_ptr_t a_callback)
 {
     dap_events_socket_t * l_es = DAP_NEW_Z(dap_events_socket_t);
+    if(!l_es){
+        log_it(L_ERROR,"Can't allocate esocket!");
+        return NULL;
+    }
     l_es->type = DESCRIPTOR_TYPE_QUEUE;
     l_es->flags =  DAP_SOCK_QUEUE_PTR;
     if (a_w){
@@ -429,6 +433,7 @@ dap_events_socket_t * s_create_type_queue_ptr(dap_worker_t * a_w, dap_events_soc
         DAP_DELETE(l_es);
         l_es = NULL;
         log_it(L_CRITICAL,"Can't create mqueue descriptor %s: \"%s\" code %d",l_mq_name, l_errbuf, l_errno);
+        return NULL;
     }else{
         l_es->mqd_id = l_mq_last_number;
         l_mq_last_number++;
diff --git a/dap-sdk/net/core/dap_proc_queue.c b/dap-sdk/net/core/dap_proc_queue.c
index 91502bfc2537be0f90aad6bd04d49f53c567cab7..ec98b6881c79a663ba4e06386c371159f42ea3bc 100644
--- a/dap-sdk/net/core/dap_proc_queue.c
+++ b/dap-sdk/net/core/dap_proc_queue.c
@@ -75,14 +75,16 @@ static void s_queue_esocket_callback( dap_events_socket_t * a_es, void * a_msg)
         dap_proc_queue_item_t * l_item = DAP_NEW_Z(dap_proc_queue_item_t);
         l_item->callback = l_msg->callback;
         l_item->callback_arg = l_msg->callback_arg;
-        l_item->next=l_queue->items_last ;
-        if ( l_queue->items_last)
-            l_queue->items_last->prev = l_item;
 
-        l_queue->items_last = l_item->next;
+        if ( l_queue->item_last)
+            l_queue->item_last->prev = l_item;
 
-        if( !l_queue->items_fisrt)
-            l_queue->items_fisrt = l_item;
+        l_item->next=l_queue->item_last ;
+
+        l_queue->item_last = l_item;
+
+        if( !l_queue->item_first)
+            l_queue->item_first = l_item;
 
 
         // Add on top so after call this callback will be executed first
diff --git a/dap-sdk/net/core/dap_proc_thread.c b/dap-sdk/net/core/dap_proc_thread.c
index 4015d0f0d13e3c26b9454650559b7139181dabc0..461a34413b1862b697038a528272f9828552837c 100644
--- a/dap-sdk/net/core/dap_proc_thread.c
+++ b/dap-sdk/net/core/dap_proc_thread.c
@@ -124,26 +124,28 @@ static void s_proc_event_callback(dap_events_socket_t * a_esocket, uint64_t a_va
     (void) a_value;
     //log_it(L_DEBUG, "Proc event callback");
     dap_proc_thread_t * l_thread = (dap_proc_thread_t *) a_esocket->_inheritor;
-    dap_proc_queue_item_t * l_item = l_thread->proc_queue->items_fisrt;
+    dap_proc_queue_item_t * l_item = l_thread->proc_queue->item_first;
     dap_proc_queue_item_t * l_item_old = NULL;
     bool l_is_anybody_for_repeat=false;
     while(l_item){
         bool l_is_finished = l_item->callback(l_thread, l_item->callback_arg);
         if (l_is_finished){
             if(l_item_old){
-                if ( ! l_item->prev )
-                    l_thread->proc_queue->items_last = l_item_old;
-                if ( ! l_item->next )
-                    l_thread->proc_queue->items_fisrt = l_item->prev;
-
-                l_item_old->prev = l_item->prev;
-
+                if ( ! l_item->next ){ // We deleted tail
+                    l_thread->proc_queue->item_last = l_item_old;
+                }
+                l_item_old->prev = l_item->next;
                 DAP_DELETE(l_item);
                 l_item = l_item_old->prev;
             }else{
-                l_thread->proc_queue->items_fisrt = l_item->prev;
+                l_thread->proc_queue->item_first = l_item->next;
+                if (l_thread->proc_queue->item_first)
+                    l_thread->proc_queue->item_first->prev = NULL; // Prev if it was - now its NULL
+                else
+                    l_thread->proc_queue->item_last = NULL; // NULL last item
+
                 DAP_DELETE(l_item);
-                l_item = l_thread->proc_queue->items_fisrt;
+                l_item = l_thread->proc_queue->item_first;
             }
 
         }else{
diff --git a/dap-sdk/net/core/dap_timerfd.c b/dap-sdk/net/core/dap_timerfd.c
index 95d8146c391654eb92ec3edbdd1ee20be511483a..e259e889803c16cc89031ae46411717b55c18131 100644
--- a/dap-sdk/net/core/dap_timerfd.c
+++ b/dap-sdk/net/core/dap_timerfd.c
@@ -195,7 +195,7 @@ static void s_es_callback_timer(struct dap_events_socket *a_event_sock)
 #if defined DAP_OS_WINDOWS
         CloseHandle(l_timerfd->th);
 #endif
-        dap_events_socket_remove_and_delete_unsafe(l_timerfd->events_socket, false);
+        l_timerfd->events_socket->flags |= DAP_SOCK_SIGNAL_CLOSE;
     }
 }
 
diff --git a/dap-sdk/net/core/include/dap_proc_queue.h b/dap-sdk/net/core/include/dap_proc_queue.h
index b204d3692d9d8cd594bd16eb389d288cd1ac3aa9..278a0685e1a1e1c019012e65625ff11145cd2c19 100644
--- a/dap-sdk/net/core/include/dap_proc_queue.h
+++ b/dap-sdk/net/core/include/dap_proc_queue.h
@@ -37,8 +37,8 @@ typedef struct dap_proc_queue_item{
 typedef struct dap_proc_queue{
     dap_proc_thread_t * proc_thread;
     dap_events_socket_t *esocket;
-    dap_proc_queue_item_t * items_last;
-    dap_proc_queue_item_t * items_fisrt;
+    dap_proc_queue_item_t * item_last;
+    dap_proc_queue_item_t * item_first;
 } dap_proc_queue_t;
 
 dap_proc_queue_t * dap_proc_queue_create(dap_proc_thread_t * a_thread);
diff --git a/modules/app-cli/dap_app_cli_net.c b/modules/app-cli/dap_app_cli_net.c
index a472241c029a3b5d19c2547def93fd2cb00a5dac..161aa4008ed006d01fdea1f0b43dcfa024488080 100644
--- a/modules/app-cli/dap_app_cli_net.c
+++ b/modules/app-cli/dap_app_cli_net.c
@@ -95,6 +95,16 @@ static void dap_app_cli_http_read(dap_app_cli_connect_param_t *socket, dap_app_c
                 size_t l_head_size = l_str_ptr - l_cmd->cmd_res;
                 memmove(l_cmd->cmd_res, l_str_ptr, l_cmd->cmd_res_cur - l_head_size);
                 l_cmd->cmd_res_cur -= l_head_size;
+                // read rest of data
+                if(l_cmd->cmd_res_cur < l_cmd->cmd_res_len) {
+                    l_cmd->cmd_res = DAP_REALLOC(l_cmd->cmd_res, l_cmd->cmd_res_len + 1);
+                    while((l_cmd->cmd_res_len - l_cmd->cmd_res_cur) > 0) {
+                        ssize_t l_recv_len = recv(*socket, &l_cmd->cmd_res[l_cmd->cmd_res_cur], l_cmd->cmd_res_len - l_cmd->cmd_res_cur, 0);
+                        if(l_recv_len <= 0)
+                            break;
+                        l_cmd->cmd_res_cur += l_recv_len;
+                    }
+                }
                 s_status++;
             } else {
                 break;
diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c
index 79748f4a8e887ad8fdd3cc155003bb2836b5b64f..4d68717b698a12978760201db76551b8cabacb80 100644
--- a/modules/chain/dap_chain.c
+++ b/modules/chain/dap_chain.c
@@ -93,8 +93,35 @@ void dap_chain_deinit(void)
     dap_chain_item_t * l_item = NULL, *l_tmp = NULL;
     pthread_rwlock_wrlock(&s_chain_items_rwlock);
     HASH_ITER(hh, s_chain_items, l_item, l_tmp) {
-          dap_chain_delete(s_chain_items->chain);
-        }
+          dap_chain_delete(l_item->chain);
+    }
+    pthread_rwlock_unlock(&s_chain_items_rwlock);
+}
+
+
+/**
+ * @brief dap_chain_deinit
+ * note: require dap_chain_enum_unlock() after
+ */
+dap_chain_t* dap_chain_enum(void** a_item)
+{
+    // if a_item == 0x1 then first item
+    dap_chain_item_t *l_item_start = (*a_item == 0x1) ? s_chain_items : (dap_chain_item_t*) *a_item;
+    dap_chain_item_t *l_item = NULL;
+    dap_chain_item_t *l_item_tmp = NULL;
+    pthread_rwlock_wrlock(&s_chain_items_rwlock);
+    HASH_ITER(hh, l_item_start, l_item, l_item_tmp) {
+        *a_item = l_item_tmp;
+        return l_item->chain;
+    }
+    return NULL ;
+}
+
+/**
+ * @brief dap_chain_enum_unlock
+ */
+void dap_chain_enum_unlock(void)
+{
     pthread_rwlock_unlock(&s_chain_items_rwlock);
 }
 
diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c
index a30da0cabcb2f09cefccf3337ae01af9c789b888..4e89caa2e3e3f413492c1f145319fb479fa332d2 100644
--- a/modules/chain/dap_chain_ledger.c
+++ b/modules/chain/dap_chain_ledger.c
@@ -192,6 +192,7 @@ static  dap_chain_ledger_tx_item_t* tx_item_find_by_addr(dap_ledger_t *a_ledger,
 
 static void s_treshold_emissions_proc( dap_ledger_t * a_ledger);
 static void s_treshold_txs_proc( dap_ledger_t * a_ledger);
+static void s_token_tsd_parse(dap_ledger_t * a_ledger, dap_chain_ledger_token_item_t *a_token_item , dap_chain_datum_token_t * a_token, size_t a_token_size);
 
 static size_t s_treshold_emissions_max = 1000;
 static size_t s_treshold_txs_max = 10000;
@@ -333,10 +334,7 @@ int dap_chain_ledger_token_add(dap_ledger_t * a_ledger,  dap_chain_datum_token_t
             break;
             case DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL:
                 log_it( L_NOTICE, "Private token %s type=DAP_CHAIN_DATUM_TOKEN_PRIVATE_DECL )", a_token->ticker);
-                l_token_item->total_supply = a_token->header_private.total_supply;
-                l_token_item->auth_signs= dap_chain_datum_token_signs_parse(a_token,a_token_size,
-                                                                                   &l_token_item->auth_signs_total,
-                                                                                    &l_token_item->auth_signs_valid );
+                s_token_tsd_parse(a_ledger,l_token_item, a_token, a_token_size);
             break;
             default:
                 log_it(L_WARNING,"Unknown token declaration type 0x%04X", a_token->type );
@@ -350,6 +348,152 @@ int dap_chain_ledger_token_add(dap_ledger_t * a_ledger,  dap_chain_datum_token_t
     return  0;
 }
 
+/**
+ * @brief s_token_tsd_parse
+ * @param a_ledger
+ * @param a_token
+ * @param a_token_size
+ */
+static void s_token_tsd_parse(dap_ledger_t * a_ledger, dap_chain_ledger_token_item_t *a_token_item , dap_chain_datum_token_t * a_token, size_t a_token_size)
+{
+    dap_chain_datum_token_tsd_t * l_tsd= dap_chain_datum_token_tsd_get(a_token,a_token_size);
+    size_t l_tsd_size=0;
+    size_t l_tsd_total_size =a_token_size-  (((byte_t*)l_tsd)- (byte_t*) a_token );
+
+    for( size_t l_offset=0; l_tsd && l_offset < l_tsd_total_size;  l_offset += l_tsd_size ){
+        l_tsd = (dap_chain_datum_token_tsd_t *) (((byte_t*)l_tsd ) +l_offset);
+        l_tsd_size =  l_tsd? dap_chain_datum_token_tsd_size(l_tsd): 0;
+        if( l_tsd_size==0 ){
+            log_it(L_ERROR,"Wrong zero TSD size, exiting TSD parse");
+            break;
+        }else if (l_tsd_size + l_offset > l_tsd_total_size ){
+            log_it(L_ERROR,"Wrong %zd TSD size, exiting TSD parse", l_tsd_size);
+            break;
+        }
+        switch (l_tsd->type) {
+           // set flags
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_SET_FLAGS:{
+                a_token_item->flags |= dap_chain_datum_token_tsd_get_scalar(l_tsd,uint16_t);
+            }break;
+
+           // unset flags
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_UNSET_FLAGS:{
+                a_token_item->flags ^= dap_chain_datum_token_tsd_get_scalar(l_tsd,uint16_t);
+            }break;
+
+            // set total supply
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TOTAL_SUPPLY:{
+                a_token_item->total_supply = dap_chain_datum_token_tsd_get_scalar(l_tsd,uint64_t);
+            }break;
+
+            // Set total signs count value to set to be valid
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TOTAL_SIGNS_VALID:{
+                a_token_item->auth_signs_valid = dap_chain_datum_token_tsd_get_scalar(l_tsd,uint16_t);
+            }break;
+
+            // Remove owner signature by pkey fingerprint
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TOTAL_SIGNS_REMOVE:{
+                dap_hash_fast_t l_hash = dap_chain_datum_token_tsd_get_scalar(l_tsd,dap_hash_fast_t);
+                for( size_t i=0; i<a_token_item->auth_signs_total; i++){
+                    if (dap_hash_fast_compare(&l_hash, &a_token_item->auth_signs_pkey_hash[i] )){
+                        if (i+1 != a_token_item->auth_signs_total){
+                            memmove(a_token_item->auth_signs+i,a_token_item->auth_signs+i+1,
+                                   (a_token_item->auth_signs_total-i-1)*sizeof (void*));
+                            memmove(a_token_item->auth_signs_pkey_hash+i,a_token_item->auth_signs_pkey_hash+i+1,
+                                   (a_token_item->auth_signs_total-i-1)*sizeof (void*));
+                        }
+                        a_token_item->auth_signs_total--;
+                        a_token_item->auth_signs = DAP_REALLOC(a_token_item->auth_signs,a_token_item->auth_signs_total*sizeof (void*) );
+                        a_token_item->auth_signs_pkey_hash = DAP_REALLOC(a_token_item->auth_signs_pkey_hash,a_token_item->auth_signs_total*sizeof (void*) );
+                        break;
+                    }
+                }
+            }break;
+
+            // Add owner signature's pkey fingerprint
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TOTAL_SIGNS_ADD:{
+                if(l_tsd->size == sizeof (dap_hash_fast_t) ){
+                    a_token_item->auth_signs_total++;
+                    a_token_item->auth_signs = DAP_REALLOC(a_token_item->auth_signs,a_token_item->auth_signs_total*sizeof (void*) );
+                    a_token_item->auth_signs_pkey_hash = DAP_REALLOC(a_token_item->auth_signs_pkey_hash,a_token_item->auth_signs_total*sizeof (void*) );
+                    a_token_item->auth_signs[a_token_item->auth_signs_total-1] = NULL;
+                    memcpy( &a_token_item->auth_signs_pkey_hash[a_token_item->auth_signs_total-1], l_tsd->data, l_tsd->size ) ;
+                }else{
+                    log_it(L_ERROR,"TSD param DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TOTAL_SIGNS_ADD expected to have %zd bytes data length, not %zd",
+                           sizeof (dap_hash_fast_t), l_tsd_size );
+                }
+            }break;
+
+            /// ------- Permissions list flags, grouped by update-remove-clear operations --------
+            // Blocked datum types list add, remove or clear
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DATUM_TYPE_BLOCKED_ADD:{
+            }break;
+
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DATUM_TYPE_BLOCKED_REMOVE:{
+            }break;
+
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DATUM_TYPE_BLOCKED_CLEAR:{
+            }break;
+
+
+
+            // Allowed datum types list add, remove or clear
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DATUM_TYPE_ALLOWED_ADD:{
+            }break;
+
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DATUM_TYPE_ALLOWED_REMOVE:{
+            }break;
+
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DATUM_TYPE_ALLOWED_CLEAR:{
+            }break;
+
+            //Allowed tx receiver addres list add, remove or clear
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_ALLOWED_ADD:{
+            }break;
+
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_ALLOWED_REMOVE:{
+            }break;
+
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_ALLOWED_CLEAR:{
+            }break;
+
+
+            //Blocked tx receiver addres list add, remove or clear
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_BLOCKED_ADD:{
+            }break;
+
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_BLOCKED_REMOVE:{
+            }break;
+
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_BLOCKED_CLEAR:{
+            }break;
+
+            //Allowed tx sender addres list add, remove or clear
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_SENDER_ALLOWED_ADD:{
+            }break;
+
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_SENDER_ALLOWED_REMOVE:{
+            }break;
+
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_SENDER_ALLOWED_CLEAR:{
+            }break;
+
+
+            //Blocked tx sender addres list add, remove or clear
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_SENDER_BLOCKED_ADD:{
+            }break;
+
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_SENDER_BLOCKED_REMOVE:{
+            }break;
+
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_SENDER_BLOCKED_CLEAR:{
+            }break;
+            default:{}
+        }
+    }
+
+}
+
 int dap_chain_ledger_token_load(dap_ledger_t *a_ledger,  dap_chain_datum_token_t *a_token, size_t a_token_size)
 {
     if (PVT(a_ledger)->last_ticker.found) {
diff --git a/modules/chain/include/dap_chain.h b/modules/chain/include/dap_chain.h
index cf6c1492664526add0905720fd802b14a08355b1..63b32a066797caf11e8403c144c2519acd674e1f 100644
--- a/modules/chain/include/dap_chain.h
+++ b/modules/chain/include/dap_chain.h
@@ -159,6 +159,9 @@ typedef struct dap_chain{
 int dap_chain_init(void);
 void dap_chain_deinit(void);
 
+dap_chain_t* dap_chain_enum(void** a_item);
+void dap_chain_enum_unlock(void);
+
 
 dap_chain_t * dap_chain_create(dap_ledger_t* a_ledger,const char * a_chain_net_name, const char * a_chain_name, dap_chain_net_id_t a_chain_net_id, dap_chain_id_t a_chain_id );
 
diff --git a/modules/global-db/dap_chain_global_db.c b/modules/global-db/dap_chain_global_db.c
index ffdd19273dcf74056ce73b2f1542e08268142140..7ccaa5f4c337e837575895051682fd9a6e89c926 100644
--- a/modules/global-db/dap_chain_global_db.c
+++ b/modules/global-db/dap_chain_global_db.c
@@ -859,8 +859,11 @@ char* dap_chain_global_db_hash(const uint8_t *data, size_t data_size)
 void* dap_db_log_unpack(const void *a_data, size_t a_data_size, size_t *a_store_obj_count)
 {
     const dap_store_obj_pkt_t *l_pkt = (const dap_store_obj_pkt_t*) a_data;
-    if(!l_pkt || l_pkt->data_size != ((size_t) a_data_size - sizeof(dap_store_obj_pkt_t)))
+    if (! l_pkt)
         return NULL;
+    if( (l_pkt->data_size+ sizeof(dap_store_obj_pkt_t)) != ((size_t) a_data_size ))
+        return NULL;
+
     size_t l_store_obj_count = 0;
     dap_store_obj_t *l_obj = dap_store_unpacket_multiple(l_pkt, &l_store_obj_count);
     if(a_store_obj_count)
diff --git a/modules/global-db/dap_chain_global_db_hist.c b/modules/global-db/dap_chain_global_db_hist.c
index 4ac96d14723d9dba34e479c32cba8cfc776cce10..57204af9dbbbcc9a7ea2dc1d04db140760d6ae87 100644
--- a/modules/global-db/dap_chain_global_db_hist.c
+++ b/modules/global-db/dap_chain_global_db_hist.c
@@ -12,7 +12,7 @@
 #include "dap_chain_global_db_hist.h"
 
 #include "uthash.h"
-// for dap_db_history_filter()
+// for dap_db_history()
 typedef struct dap_tx_data{
         dap_chain_hash_fast_t tx_hash;
         char tx_hash_str[70];
@@ -138,7 +138,7 @@ dap_list_t* dap_db_log_pack(dap_global_db_obj_t *a_obj, size_t *a_data_size_out)
 }
 
 
-// for dap_db_history_filter()
+// for dap_db_history()
 static dap_store_obj_t* get_prev_tx(dap_global_db_obj_t *a_objs, dap_tx_data_t *a_tx_data)
 {
     if(!a_objs || !a_tx_data)
@@ -727,7 +727,7 @@ char* dap_db_history_addr(dap_chain_addr_t * a_addr, const char *a_group_mempool
  *
  * return history string
  */
-char* dap_db_history_filter(dap_chain_addr_t * a_addr, const char *a_group_mempool)
+char* dap_db_history(dap_chain_addr_t * a_addr, const char *a_group_mempool)
 {
     dap_string_t *l_str_out = dap_string_new(NULL);
     // load history
diff --git a/modules/global-db/include/dap_chain_global_db.h b/modules/global-db/include/dap_chain_global_db.h
index 76ae0627161424824ce8d44a65eb493be464bcf3..4dc540b2b1c5c25cab95439ab7ee88e11090ec9c 100644
--- a/modules/global-db/include/dap_chain_global_db.h
+++ b/modules/global-db/include/dap_chain_global_db.h
@@ -124,7 +124,7 @@ dap_list_t* dap_db_log_pack(dap_global_db_obj_t *a_obj, size_t *a_data_size_out)
 // Get data according the history log
 //char* dap_db_history_tx(dap_chain_hash_fast_t * a_tx_hash, const char *a_group_mempool);
 //char* dap_db_history_addr(dap_chain_addr_t * a_addr, const char *a_group_mempool);
-//char* dap_db_history_filter(dap_chain_addr_t * a_addr, const char *a_group_mempool);
+//char* dap_db_history(dap_chain_addr_t * a_addr, const char *a_group_mempool);
 
 // Parse data from dap_db_log_pack()
 void* dap_db_log_unpack(const void *a_data, size_t a_data_size, size_t *a_store_obj_count);
diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c
index 14c3284b028de289f7b2236e27b3dfe518cf4db0..24ffdaf0c7db7b27ed7c5d286083fe741a065568 100644
--- a/modules/mempool/dap_chain_mempool.c
+++ b/modules/mempool/dap_chain_mempool.c
@@ -106,7 +106,7 @@ int dap_chain_mempool_datum_add(dap_chain_datum_t * a_datum, dap_chain_t * a_cha
  *
  * return 0 Ok, -2 not enough funds to transfer, -1 other Error
  */
-int dap_chain_mempool_tx_create(dap_chain_t * a_chain, dap_enc_key_t *a_key_from,
+dap_hash_fast_t* dap_chain_mempool_tx_create(dap_chain_t * a_chain, dap_enc_key_t *a_key_from,
         const dap_chain_addr_t* a_addr_from, const dap_chain_addr_t* a_addr_to,
         const dap_chain_addr_t* a_addr_fee,
         const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
@@ -116,7 +116,7 @@ int dap_chain_mempool_tx_create(dap_chain_t * a_chain, dap_enc_key_t *a_key_from
     if(!a_chain | !a_key_from || ! a_addr_from || !a_key_from->priv_key_data || !a_key_from->priv_key_data_size ||
             !dap_chain_addr_check_sum(a_addr_from) || !dap_chain_addr_check_sum(a_addr_to) ||
             (a_addr_fee && !dap_chain_addr_check_sum(a_addr_fee)) || !a_value)
-        return -1;
+        return NULL;
 
     // find the transactions from which to take away coins
     uint64_t l_value_transfer = 0; // how many coins to transfer
@@ -125,7 +125,7 @@ int dap_chain_mempool_tx_create(dap_chain_t * a_chain, dap_enc_key_t *a_key_from
                                                                              a_addr_from, l_value_need, &l_value_transfer);
     if (!l_list_used_out) {
         log_it(L_WARNING,"Not enough funds to transfer");
-        return -2;
+        return NULL;
     }
     // create empty transaction
     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
@@ -151,7 +151,7 @@ int dap_chain_mempool_tx_create(dap_chain_t * a_chain, dap_enc_key_t *a_key_from
         if(l_value_back) {
             if(dap_chain_datum_tx_add_out_item(&l_tx, a_addr_from, l_value_back) != 1) {
                 dap_chain_datum_tx_delete(l_tx);
-                return -1;
+                return NULL;
             }
         }
     }
@@ -164,12 +164,15 @@ int dap_chain_mempool_tx_create(dap_chain_t * a_chain, dap_enc_key_t *a_key_from
 
     size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx);
     dap_chain_datum_t *l_datum = dap_chain_datum_create(DAP_CHAIN_DATUM_TX, l_tx, l_tx_size);
+    dap_hash_fast_t * l_ret = DAP_NEW_Z(dap_hash_fast_t);
+    dap_hash_fast(l_tx, l_tx_size, l_ret);
     DAP_DELETE(l_tx);
     if(dap_chain_mempool_datum_add (l_datum, a_chain) == 0){
-        return 0;
+        return l_ret;
     }else{
         DAP_DELETE( l_datum );
-        return -4;
+        DAP_DELETE(l_ret);
+        return NULL;
     }
 }
 
diff --git a/modules/mempool/include/dap_chain_mempool.h b/modules/mempool/include/dap_chain_mempool.h
index e4db94b8be5e956217b404eddddd4f07fa9f5e33..5fbf3e3d259370754770503aad85bb88f7d64513 100644
--- a/modules/mempool/include/dap_chain_mempool.h
+++ b/modules/mempool/include/dap_chain_mempool.h
@@ -44,7 +44,7 @@ void dap_datum_mempool_free(dap_datum_mempool_t *datum);
 void dap_chain_mempool_add_proc(dap_http_t * a_http_server, const char * a_url);
 
 int dap_chain_mempool_datum_add(dap_chain_datum_t *a_datum, dap_chain_t *a_chain);
-int dap_chain_mempool_tx_create(dap_chain_t * a_chain, dap_enc_key_t *a_key_from,
+dap_hash_fast_t*  dap_chain_mempool_tx_create(dap_chain_t * a_chain, dap_enc_key_t *a_key_from,
         const dap_chain_addr_t* a_addr_from, const dap_chain_addr_t* a_addr_to,
         const dap_chain_addr_t* a_addr_fee,
         const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index 940b411ceb809fc9e4e1466bfcd6a09f3ead25fa..2bcb8c44e484dc147e353bf4c3a2f28d20ef8380 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -526,10 +526,11 @@ static int s_net_states_proc(dap_chain_net_t *a_net)
                 }
                 dap_stream_worker_t *l_worker = dap_client_get_stream_worker(l_node_client->client);
                 dap_stream_ch_chain_sync_request_t l_sync_gdb = {};
-                // Get last timestamp in log
-                l_sync_gdb.id_start = (uint64_t) dap_db_get_last_id_remote(l_node_client->remote_node_addr.uint64);
+                // Get last timestamp in log if wasn't SYNC_FROM_ZERO flag
+                if (! (l_pvt_net->flags & F_DAP_CHAIN_NET_SYNC_FROM_ZERO) )
+                    l_sync_gdb.id_start = (uint64_t) dap_db_get_last_id_remote(l_node_client->remote_node_addr.uint64);
                 l_sync_gdb.node_addr.uint64 = dap_chain_net_get_cur_addr_int(a_net);
-                log_it(L_DEBUG, "Prepared request to gdb sync from %llu to %llu", l_sync_gdb.id_start, l_sync_gdb.id_end);
+                log_it(L_DEBUG, "Prepared request to gdb sync from %llu to %llu", l_sync_gdb.id_start, l_sync_gdb.id_end?l_sync_gdb.id_end:-1 );
                 // find dap_chain_id_t
                 dap_chain_t *l_chain = dap_chain_net_get_chain_by_name(a_net, "gdb");
                 dap_chain_id_t l_chain_id = l_chain ? l_chain->id : (dap_chain_id_t ) {};
@@ -555,7 +556,7 @@ static int s_net_states_proc(dap_chain_net_t *a_net)
                 default:
                     log_it(L_INFO, "Node sync error %d",l_res);
                 }
-                /*
+
                 dap_chain_node_client_reset(l_node_client);
                 l_res = dap_stream_ch_chain_pkt_write_mt(l_worker, l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB_RVRS, a_net->pub.id,
                                                          l_chain_id, a_net->pub.cell_id, &l_sync_gdb, sizeof(l_sync_gdb));
@@ -570,7 +571,7 @@ static int s_net_states_proc(dap_chain_net_t *a_net)
                 default:
                     log_it(L_INFO, "Node reverse sync error %d",l_res);
                 }
-                */
+
                 l_tmp = dap_list_next(l_tmp);
             }
             if (!l_pvt_net->links) {
@@ -578,7 +579,9 @@ static int s_net_states_proc(dap_chain_net_t *a_net)
             } else if (l_pvt_net->state_target >= NET_STATE_SYNC_CHAINS) {
                 l_pvt_net->state = NET_STATE_SYNC_CHAINS;
             } else {    // Synchronization done, go offline
-                log_it(L_INFO, "Synchronization done");
+                log_it(L_INFO, "Synchronization done, go offline");
+                l_pvt_net->flags ^= F_DAP_CHAIN_NET_GO_SYNC;
+                l_pvt_net->flags ^= F_DAP_CHAIN_NET_SYNC_FROM_ZERO;
                 l_pvt_net->state = l_pvt_net->state_target = NET_STATE_OFFLINE;
             }
         }
@@ -601,7 +604,13 @@ static int s_net_states_proc(dap_chain_net_t *a_net)
                 DL_FOREACH (a_net->pub.chains, l_chain) {
                     dap_chain_node_client_reset(l_node_client);
                     dap_stream_ch_chain_sync_request_t l_request = {0};
-                    dap_chain_get_atom_last_hash(l_chain,&l_request.hash_from);
+
+                    // TODO: Uncomment next block when finish with partial updates
+                    /*
+                    if (! (l_pvt_net->flags & F_DAP_CHAIN_NET_SYNC_FROM_ZERO) )
+                        dap_chain_get_atom_last_hash(l_chain,&l_request.hash_from);
+                    */
+
                     if ( !dap_hash_fast_is_blank(&l_request.hash_from) ){
                         if(dap_log_level_get() <= L_DEBUG){
                             char l_hash_str[128]={[0]='\0'};
@@ -666,12 +675,14 @@ static int s_net_states_proc(dap_chain_net_t *a_net)
                 log_it( L_INFO,"Return back to state LINKS_PREPARE ");
                 l_pvt_net->state = NET_STATE_LINKS_PREPARE;
             } else {
-                log_it(L_INFO, "Synchronization done");
                 if (l_pvt_net->state_target == NET_STATE_ONLINE) {
-                    l_pvt_net->flags &= ~F_DAP_CHAIN_NET_GO_SYNC;
+                    l_pvt_net->flags ^= F_DAP_CHAIN_NET_GO_SYNC;
+                    l_pvt_net->flags ^= F_DAP_CHAIN_NET_SYNC_FROM_ZERO;
                     l_pvt_net->state = NET_STATE_ONLINE;
+                    log_it(L_INFO, "Synchronization done, status online");
                 } else {    // Synchronization done, go offline
                     l_pvt_net->state = l_pvt_net->state_target = NET_STATE_OFFLINE;
+                    log_it(L_INFO, "Synchronization done, go offline");
                 }
             }
         }
@@ -849,14 +860,16 @@ void dap_chain_net_delete( dap_chain_net_t * a_net )
 int dap_chain_net_init()
 {
     dap_chain_node_cli_cmd_item_create ("net", s_cli_net, NULL, "Network commands",
-        "net -net <chain net name> go < online | offline >\n"
-            "\tFind and establish links and stay online\n"
+        "net -net <chain net name> [-mode update|all] go < online | offline >\n"
+            "\tFind and establish links and stay online. \n"
+            "\tMode \"update\" is by default when only new chains and gdb are updated. Mode \"all\" updates everything from zero\n"
         "net -net <chain net name> get status\n"
             "\tLook at current status\n"
         "net -net <chain net name> stats tx [-from <From time>] [-to <To time>] [-prev_sec <Seconds>] \n"
             "\tTransactions statistics. Time format is <Year>-<Month>-<Day>_<Hours>:<Minutes>:<Seconds> or just <Seconds> \n"
-        "net -net <chain net name> sync < all | gdb | chains >\n"
+        "net -net <chain net name> [-mode update|all] sync < all | gdb | chains >\n"
             "\tSyncronyze gdb, chains or everything\n"
+            "\tMode \"update\" is by default when only new chains and gdb are updated. Mode \"all\" updates everything from zero\n"
         "net -net <chain net name> link < list | add | del | info | establish >\n"
             "\tList, add, del, dump or establish links\n"
         "net -net <chain net name> ca add {-cert <cert name> | -hash <cert hash>}\n"
@@ -1016,6 +1029,11 @@ static int s_cli_net( int argc, char **argv, void *arg_func, char **a_str_reply)
         dap_chain_node_cli_find_option_val(argv, arg_index, argc, "ca", &l_ca_str);
         dap_chain_node_cli_find_option_val(argv, arg_index, argc, "ledger", &l_ledger_str);
 
+        const char * l_sync_mode_str = "updates";
+        dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-mode", &l_sync_mode_str);
+        if ( !dap_strcmp(l_sync_mode_str,"all") )
+            dap_chain_net_get_flag_sync_from_zero(l_net);
+
         if ( l_stats_str ){
             if ( strcmp(l_stats_str,"tx") == 0 ) {
                 const char *l_to_str = NULL;
@@ -1126,11 +1144,6 @@ static int s_cli_net( int argc, char **argv, void *arg_func, char **a_str_reply)
 
         } else if( l_sync_str) {
 
-            const char * l_sync_mode_str = "updates";
-            dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-mode", &l_sync_mode_str);
-            if ( !dap_strcmp(l_sync_mode_str,"all") )
-                dap_chain_net_get_flag_sync_from_zero(l_net);
-
             if ( strcmp(l_sync_str,"all") == 0 ) {
                 dap_chain_node_cli_set_reply_text(a_str_reply,
                                                   "SYNC_ALL state requested to state machine. Current state: %s\n",
@@ -1790,13 +1803,16 @@ void dap_chain_net_deinit()
 dap_chain_net_t **dap_chain_net_list(uint16_t *a_size)
 {
     *a_size = HASH_COUNT(s_net_items);
-    dap_chain_net_t **l_net_list = DAP_NEW_SIZE(dap_chain_net_t *, (*a_size) * sizeof(dap_chain_net_t *));
-    dap_chain_net_item_t *l_current_item, *l_tmp;
-    int i = 0;
-    HASH_ITER(hh, s_net_items, l_current_item, l_tmp) {
-        l_net_list[i++] = l_current_item->chain_net;
-    }
-    return l_net_list;
+    if(*a_size){
+        dap_chain_net_t **l_net_list = DAP_NEW_SIZE(dap_chain_net_t *, (*a_size) * sizeof(dap_chain_net_t *));
+        dap_chain_net_item_t *l_current_item, *l_tmp;
+        int i = 0;
+        HASH_ITER(hh, s_net_items, l_current_item, l_tmp) {
+            l_net_list[i++] = l_current_item->chain_net;
+        }
+        return l_net_list;
+    }else
+        return NULL;
 }
 
 /**
@@ -2600,11 +2616,12 @@ static uint8_t *dap_chain_net_set_acl(dap_chain_hash_fast_t *a_pkey_hash)
 {
     uint16_t l_net_count;
     dap_chain_net_t **l_net_list = dap_chain_net_list(&l_net_count);
-    if (l_net_count) {
+    if (l_net_count && l_net_list) {
         uint8_t *l_ret = DAP_NEW_SIZE(uint8_t, l_net_count);
         for (uint16_t i = 0; i < l_net_count; i++) {
             l_ret[i] = s_net_check_acl(l_net_list[i], a_pkey_hash);
         }
+        DAP_DELETE(l_net_list);
         return l_ret;
     }
     return NULL;
diff --git a/modules/net/dap_chain_node_cli.c b/modules/net/dap_chain_node_cli.c
index ff8712aab3b8221f0d37574ddc7e72053d40c89f..5c4f91cf18c62d5bfee855d97d71c73d10af5395 100644
--- a/modules/net/dap_chain_node_cli.c
+++ b/modules/net/dap_chain_node_cli.c
@@ -63,6 +63,7 @@
 #include "dap_list.h"
 #include "dap_chain_node_cli_cmd.h"
 #include "dap_chain_node_client.h"
+#include "dap_chain_node_cli_cmd_tx.h"
 #include "dap_chain_node_cli.h"
 
 //#include "dap_chain_node_cli.h"
@@ -341,7 +342,16 @@ static void* thread_one_client_func(void *args)
                                                     "Content-Length: %d\r\n\r\n"
                                                     "%s",
                         strlen(reply_body), reply_body);
-                /*int ret = */ send(newsockfd, reply_str, strlen(reply_str) ,0);
+                size_t l_reply_step = 32768;
+                size_t l_reply_len = strlen(reply_str);
+                size_t l_reply_rest = l_reply_len;
+                while(l_reply_rest) {
+                    size_t l_send_bytes = min(l_reply_step, l_reply_rest);
+                    int ret = send(newsockfd, reply_str + l_reply_len - l_reply_rest, l_send_bytes, 0);
+                    if(ret<=0)
+                        break;
+                    l_reply_rest-=l_send_bytes;
+                };
                 DAP_DELETE(str_reply);
                 DAP_DELETE(reply_str);
                 DAP_DELETE(reply_body);
@@ -989,6 +999,18 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
     dap_chain_node_cli_cmd_item_create("tx_history", com_tx_history, NULL, "Transaction history (for address or by hash)",
             "tx_history  [-addr <addr> | -w <wallet name> | -tx <tx_hash>] -net <net name> -chain <chain name>\n");
 
+    // Ledger info
+    dap_chain_node_cli_cmd_item_create("ledger", com_ledger, NULL, "Ledger info",
+            "ledger list coins -net <network name>\n"
+            "ledger list coins_cond -net <network name>\n"
+            "ledger list addrs -net <network name>\n"
+            "ledger tx [all | -addr <addr> | -w <wallet name> | -tx <tx_hash>] [-chain <chain name>] -net <network name>\n");
+
+    // Token info
+    dap_chain_node_cli_cmd_item_create("token", com_token, NULL, "Token info",
+            "token list -net <network name>\n"
+            "token tx all name <token name> -net <network name> [-page_start <page>] [-page <page>]\n");
+
     // Log
     dap_chain_node_cli_cmd_item_create ("print_log", com_print_log, NULL, "Print log info",
                 "print_log [ts_after <timestamp >] [limit <line numbers>]\n" );
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index 01fb9ae72fd94106692d31f986ae43147a15c01c..af0c9397eaee5a5184b3d375a2c3bb8be12031bd 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -3743,18 +3743,29 @@ int com_tx_create(int argc, char ** argv, void *arg_func, char **str_reply)
     dap_string_t *string_ret = dap_string_new(NULL);
     //g_string_printf(string_ret, "from=%s\nto=%s\nval=%lld\nfee=%s\nval_fee=%lld\n\n",
     //        addr_base58_from, addr_base58_to, value, addr_base58_fee, value_fee);
-
-    int res =
-            l_tx_num ?
-                       dap_chain_mempool_tx_create_massive(l_chain, dap_chain_wallet_get_key(l_wallet, 0), addr_from,
+    int res = 0;
+    if(l_tx_num){
+        res = dap_chain_mempool_tx_create_massive(l_chain, dap_chain_wallet_get_key(l_wallet, 0), addr_from,
                                addr_to, addr_fee,
-                               l_token_ticker, value, value_fee, l_tx_num)
-                               :
-                       dap_chain_mempool_tx_create(l_chain, dap_chain_wallet_get_key(l_wallet, 0), addr_from, addr_to,
-                               addr_fee,
-                               l_token_ticker, value, value_fee);
-    dap_string_append_printf(string_ret, "transfer=%s\n",
-            (res == 0) ? "Ok" : (res == -2) ? "False, not enough funds for transfer" : "False");
+                               l_token_ticker, value, value_fee, l_tx_num);
+
+        dap_string_append_printf(string_ret, "transfer=%s\n",
+                (res == 0) ? "Ok" : (res == -2) ? "False, not enough funds for transfer" : "False");
+    }else{
+        dap_hash_fast_t * l_tx_hash = dap_chain_mempool_tx_create(l_chain, dap_chain_wallet_get_key(l_wallet, 0), addr_from, addr_to,
+                addr_fee,
+                l_token_ticker, value, value_fee);
+        if (l_tx_hash){
+            char l_tx_hash_str[80]={[0]='\0'};
+            dap_chain_hash_fast_to_str(l_tx_hash,l_tx_hash_str,sizeof (l_tx_hash_str)-1);
+            dap_string_append_printf(string_ret, "transfer=Ok\ntx_hash=%s\n",l_tx_hash_str);
+            DAP_DELETE(l_tx_hash);
+        }else{
+            dap_string_append_printf(string_ret, "transfer=False\n");
+            res = -1;
+        }
+
+    }
 
     dap_chain_node_cli_set_reply_text(str_reply, string_ret->str);
     dap_string_free(string_ret, false);
diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c
index 67cc3f80663625ed6ce8a5c3fb227ba05430c2e9..4882751ee5de8ae28b4a16426ca26a0adbb0dc8f 100644
--- a/modules/net/dap_chain_node_cli_cmd_tx.c
+++ b/modules/net/dap_chain_node_cli_cmd_tx.c
@@ -26,15 +26,18 @@
 #include <stddef.h>
 #include <pthread.h>
 
-#include <dap_common.h>
-#include <dap_enc_base58.h>
-#include <dap_strfuncs.h>
-#include <dap_string.h>
-#include <dap_list.h>
-#include <dap_hash.h>
+#include "dap_common.h"
+#include "dap_enc_base58.h"
+#include "dap_strfuncs.h"
+#include "dap_string.h"
+#include "dap_list.h"
+#include "dap_hash.h"
 
+#include "dap_chain_wallet.h"
+#include "dap_chain_datum.h"
+#include "dap_chain_datum_token.h"
 #include "dap_chain_datum_tx_items.h"
-
+#include "dap_chain_node_cli.h"
 #include "dap_chain_node_cli_cmd_tx.h"
 
 #define LOG_TAG "chain_node_cli_cmd_tx"
@@ -683,3 +686,918 @@ char* dap_db_history_addr(dap_chain_addr_t * a_addr, dap_chain_t * a_chain, cons
     char *l_ret_str = l_str_out ? dap_string_free(l_str_out, false) : NULL;
     return l_ret_str;
 }
+
+static char* dap_db_history_token_list(dap_chain_t * a_chain, const char *a_token_name, const char *a_hash_out_type, size_t *a_token_num)
+{
+    dap_string_t *l_str_out = dap_string_new(NULL);
+    *a_token_num  = 0;
+    bool l_tx_hash_found = false;
+    // list all transactions
+    dap_tx_data_t *l_tx_data_hash = NULL;
+    // load transactions
+    size_t l_atom_size = 0;
+    dap_chain_atom_iter_t *l_atom_iter = a_chain->callback_atom_iter_create(a_chain);
+    dap_chain_atom_ptr_t *l_atom = a_chain->callback_atom_iter_get_first(l_atom_iter, &l_atom_size);
+    size_t l_datums_count = 0;
+    dap_chain_datum_t **l_datums = (a_chain->callback_atom_get_datums && l_atom && l_atom_size) ?
+                    a_chain->callback_atom_get_datums(l_atom, l_atom_size, &l_datums_count) : NULL;
+    if(!l_datums) {
+        log_it(L_WARNING, "Not defined callback_atom_get_datums for chain \"%s\"", a_chain->name);
+        return NULL ;
+    }
+    for(size_t l_datum_n = 0; l_datum_n < l_datums_count; l_datum_n++) {
+
+        dap_chain_datum_t *l_datum = l_datums[l_datum_n];
+        if(!l_datum ) {// || l_datum->header.type_id != DAP_CHAIN_DATUM_TX) {
+            // go to next atom
+            //l_atom = a_chain->callback_atom_iter_get_next(l_atom_iter, &l_atom_size);
+            continue;
+        }
+        /*
+            // transaction
+            dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t*) l_datum->data;
+            dap_list_t *l_records_out = NULL;
+
+
+        dap_chain_datum_t *l_datum =
+                a_chain->callback_atom_get_datum ?
+                        a_chain->callback_atom_get_datum(l_atom) : (dap_chain_datum_t*) l_atom;
+        if(!l_datum) {
+            // go to next transaction
+            l_atom = a_chain->callback_atom_iter_get_next(l_atom_iter);
+            l_atom_size = a_chain->callback_atom_get_size(l_atom);
+            log_it(L_ERROR, "datum=NULL for atom=0x%x", l_atom);
+            continue;
+        }
+*/
+        char l_time_str[70];
+        // get time of create datum
+        if(dap_time_to_str_rfc822(l_time_str, 71, l_datum->header.ts_create) < 1)
+            l_time_str[0] = '\0';
+        if(l_datum->header.type_id==DAP_CHAIN_DATUM_TOKEN_DECL) {
+            dap_chain_datum_token_t *l_token = (dap_chain_datum_token_t*) l_datum->data;
+            if(!a_token_name || !dap_strcmp(l_token->ticker, a_token_name)) {
+                dap_string_append_printf(l_str_out, "token %s, created: %s\n", l_token->ticker, l_time_str);
+                switch (l_token->type) {
+                // Simple private token decl
+                case DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE:
+                    dap_string_append_printf(l_str_out, "  total_supply: %.0llf(%llu), signs: valid/total %02d/%02d \n",
+                            l_token->header_private.total_supply / DATOSHI_LD,
+                            l_token->header_private.total_supply,
+                            l_token->header_private.signs_valid, l_token->header_private.signs_total);
+                    break;
+                case DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL:
+                    dap_string_append_printf(l_str_out, "  tsd_total_size: %llu, flags: 0x%x \n",
+                            l_token->header_private_decl.tsd_total_size,
+                            l_token->header_private_decl.flags);
+                    break;
+                case DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE:
+                    dap_string_append_printf(l_str_out, "  tsd_total_size: %llu, padding: 0x%x \n",
+                            l_token->header_private_update.tsd_total_size,
+                            l_token->header_private_update.padding);
+                    break;
+                case DAP_CHAIN_DATUM_TOKEN_TYPE_PUBLIC: {
+                    char *l_addr = dap_chain_addr_to_str(&l_token->header_public.premine_address);
+                    dap_string_append_printf(l_str_out,
+                            " total_supply: %.0llf(%llu), flags: 0x%x\n, premine_supply: %llu, premine_address '%s'\n",
+                            l_token->header_public.total_supply / DATOSHI_LD,
+                            l_token->header_public.total_supply,
+                            l_token->header_public.flags,
+                            l_token->header_public.premine_supply,
+                            l_addr ? l_addr : "-");
+                    DAP_DELETE(l_addr);
+                }
+                    break;
+                default:
+                    dap_string_append_printf(l_str_out, "unknown token type: 0x%x\n", l_token->type);
+                    break;
+
+                }
+                dap_string_append_printf(l_str_out, "\n");
+                (*a_token_num)++;
+            }
+        }
+
+        // go to next transaction
+        //l_atom = a_chain->callback_atom_iter_get_next(l_atom_iter);
+        //l_atom_size = a_chain->callback_atom_get_size(l_atom);
+    }
+
+    a_chain->callback_atom_iter_delete(l_atom_iter);
+    char *l_ret_str = l_str_out ? dap_string_free(l_str_out, false) : NULL;
+    return l_ret_str;
+}
+
+/**
+ * Get data according the history log
+ *
+ * return history string
+ */
+static char* dap_db_history_filter(dap_chain_t * a_chain, const char *a_filter_token_name, const char *a_filtr_addr_base58, const char *a_hash_out_type, long a_datum_start, long a_datum_end, long *a_total_datums)
+{
+    dap_string_t *l_str_out = dap_string_new(NULL);
+
+    bool l_tx_hash_found = false;
+    // list all transactions
+    dap_tx_data_t *l_tx_data_hash = NULL;
+    // load transactions
+    size_t l_atom_size = 0;
+    dap_chain_atom_iter_t *l_atom_iter = a_chain->callback_atom_iter_create(a_chain);
+    dap_chain_atom_ptr_t *l_atom = a_chain->callback_atom_iter_get_first(l_atom_iter, &l_atom_size);
+    size_t l_datum_num = 0, l_token_num = 0, l_emission_num = 0, l_tx_num = 0;
+    size_t l_datum_num_global = a_total_datums ? *a_total_datums : 0;
+    while(l_atom && l_atom_size) {
+    size_t l_datums_count = 0;
+    dap_chain_datum_t **l_datums =
+            (a_chain->callback_atom_get_datums && l_atom && l_atom_size) ?
+                    a_chain->callback_atom_get_datums(l_atom, l_atom_size, &l_datums_count) : NULL;
+    if(!l_datums) {
+        log_it(L_WARNING, "Not defined callback_atom_get_datums for chain \"%s\"", a_chain->name);
+        return NULL ;
+    }
+    for(size_t l_datum_n = 0; l_datum_n < l_datums_count; l_datum_n++) {
+
+        dap_chain_datum_t *l_datum = l_datums[l_datum_n];
+        if(!l_datum) { // || l_datum->header.type_id != DAP_CHAIN_DATUM_TX) {
+            // go to next atom
+            //l_atom = a_chain->callback_atom_iter_get_next(l_atom_iter, &l_atom_size);
+            continue;
+        }
+
+    /*dap_chain_atom_iter_t *l_atom_iter = a_chain->callback_atom_iter_create(a_chain);
+    dap_chain_atom_ptr_t *l_atom = a_chain->callback_atom_iter_get_first(l_atom_iter);
+    size_t l_atom_size = a_chain->callback_atom_get_size(l_atom);
+    size_t l_datum_num = 0, l_token_num = 0, l_emission_num = 0, l_tx_num = 0;
+    while(l_atom && l_atom_size) {
+        dap_chain_datum_t *l_datum =
+                a_chain->callback_atom_get_datum ?
+                        a_chain->callback_atom_get_datum(l_atom) : (dap_chain_datum_t*) l_atom;
+        if(!l_datum) {
+            // go to next transaction
+            l_atom = a_chain->callback_atom_iter_get_next(l_atom_iter);
+            l_atom_size = a_chain->callback_atom_get_size(l_atom);
+            log_it(L_ERROR, "datum=NULL for atom=0x%x", l_atom);
+            continue;
+        }*/
+        char l_time_str[70];
+        // get time of create datum
+        if(dap_time_to_str_rfc822(l_time_str, 71, l_datum->header.ts_create) < 1)
+            l_time_str[0] = '\0';
+        switch (l_datum->header.type_id) {
+
+        // token
+        case DAP_CHAIN_DATUM_TOKEN_DECL: {
+
+            // no token necessary for addr
+            if(a_filtr_addr_base58) {
+                    break;
+            }
+
+            dap_chain_datum_token_t *l_token = (dap_chain_datum_token_t*) l_datum->data;
+            //if(a_datum_start < 0 || (l_datum_num >= a_datum_start && l_datum_num < a_datum_end))
+            // datum out of page
+            if(a_datum_start >= 0 && (l_datum_num+l_datum_num_global < a_datum_start || l_datum_num+l_datum_num_global >= a_datum_end)){
+                l_token_num++;
+                break;
+            }
+            if(!a_filter_token_name || !dap_strcmp(l_token->ticker, a_filter_token_name)) {
+                dap_string_append_printf(l_str_out, "token %s, created: %s\n", l_token->ticker, l_time_str);
+                switch (l_token->type) {
+                // Simple private token decl
+                case DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE:
+                    dap_string_append_printf(l_str_out, "  total_supply: %.0llf(%llu), signs: valid/total %02d/%02d \n",
+                            l_token->header_private.total_supply / DATOSHI_LD,
+                            l_token->header_private.total_supply,
+                            l_token->header_private.signs_valid, l_token->header_private.signs_total);
+                    break;
+                case DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL:
+                    dap_string_append_printf(l_str_out, "  tsd_total_size: %llu, flags: 0x%x \n",
+                            l_token->header_private_decl.tsd_total_size,
+                            l_token->header_private_decl.flags);
+                    break;
+                case DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE:
+                    dap_string_append_printf(l_str_out, "  tsd_total_size: %llu, padding: 0x%x \n",
+                            l_token->header_private_update.tsd_total_size,
+                            l_token->header_private_update.padding);
+                    break;
+                case DAP_CHAIN_DATUM_TOKEN_TYPE_PUBLIC: {
+                    char *l_addr = dap_chain_addr_to_str(&l_token->header_public.premine_address);
+                    dap_string_append_printf(l_str_out,
+                            " total_supply: %.0llf(%llu), flags: 0x%x\n, premine_supply: %llu, premine_address '%s'\n",
+                            l_token->header_public.total_supply / DATOSHI_LD,
+                            l_token->header_public.total_supply,
+                            l_token->header_public.flags,
+                            l_token->header_public.premine_supply,
+                            l_addr ? l_addr : "-");
+                    DAP_DELETE(l_addr);
+                }
+                    break;
+                default:
+                    dap_string_append_printf(l_str_out, "unknown token type: 0x%x\n", l_token->type);
+                    break;
+
+                }
+                dap_string_append_printf(l_str_out, "\n");
+                l_token_num++;
+            }
+        }
+            break;
+
+            // emission
+        case DAP_CHAIN_DATUM_TOKEN_EMISSION: {
+            // datum out of page
+            if(a_datum_start >= 0 && (l_datum_num+l_datum_num_global < a_datum_start || l_datum_num+l_datum_num_global >= a_datum_end)) {
+                 l_token_num++;
+                 break;
+            }
+            dap_chain_datum_token_emission_t *l_token_em = (dap_chain_datum_token_emission_t*) l_datum->data;
+            if(!a_filter_token_name || !dap_strcmp(l_token_em->hdr.ticker, a_filter_token_name)) {
+                char * l_token_emission_address_str = dap_chain_addr_to_str(&(l_token_em->hdr.address));
+                // filter for addr
+                if(dap_strcmp(a_filtr_addr_base58,l_token_emission_address_str)) {
+                     break;
+                }
+
+                dap_string_append_printf(l_str_out, "emission: %.0llf(%llu) %s, type: %s, version: %d\n",
+                        l_token_em->hdr.value / DATOSHI_LD, l_token_em->hdr.value, l_token_em->hdr.ticker,
+                        c_dap_chain_datum_token_emission_type_str[l_token_em->hdr.type],
+                        l_token_em->hdr.version);
+                dap_string_append_printf(l_str_out, "  to addr: %s\n", l_token_emission_address_str);
+
+                DAP_DELETE(l_token_emission_address_str);
+                switch (l_token_em->hdr.type) {
+                case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_UNDEFINED:
+                    break;
+                case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_AUTH:
+                    dap_string_append_printf(l_str_out, "  signs_count: %d\n", l_token_em->data.type_auth.signs_count);
+                    break;
+                case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_ALGO:
+                    dap_string_append_printf(l_str_out, "  codename: %s\n", l_token_em->data.type_algo.codename);
+                    break;
+                case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_ATOM_OWNER:
+                    dap_string_append_printf(l_str_out, " value_start: %.0llf(%llu), codename: %s\n",
+                            l_token_em->data.type_atom_owner.value_start / DATOSHI_LD,
+                            l_token_em->data.type_atom_owner.value_start,
+                            l_token_em->data.type_atom_owner.value_change_algo_codename);
+                    break;
+                case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_SMART_CONTRACT: {
+                    char *l_addr = dap_chain_addr_to_str(&l_token_em->data.type_presale.addr);
+                    // get time of create datum
+                    if(dap_time_to_str_rfc822(l_time_str, 71, l_token_em->data.type_presale.lock_time) < 1)
+                            l_time_str[0] = '\0';
+                    dap_string_append_printf(l_str_out, "  flags: 0x%x, lock_time: %s\n", l_token_em->data.type_presale.flags, l_time_str);
+                    dap_string_append_printf(l_str_out, "  addr: %s\n", l_addr);
+                    DAP_DELETE(l_addr);
+                }
+                    break;
+                }
+                dap_string_append_printf(l_str_out, "\n");
+                l_emission_num++;
+            }
+        }
+            break;
+
+            // transaction
+        case DAP_CHAIN_DATUM_TX:{
+
+            // datum out of page
+            if(a_datum_start >= 0 && (l_datum_num+l_datum_num_global < a_datum_start || l_datum_num+l_datum_num_global >= a_datum_end)) {
+                l_tx_num++;
+                break;
+            }
+            dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t*) l_datum->data;
+
+            // find Token items - present in emit transaction
+            dap_list_t *l_list_tx_token = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_TOKEN, NULL);
+            // find OUT items
+            dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT, NULL);
+
+            dap_tx_data_t *l_tx_data = NULL;
+
+             // calc tx hash
+             dap_chain_hash_fast_t l_tx_hash;
+            dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_tx_hash);
+            char *tx_hash_str;
+            char l_tx_hash_str[70];
+            dap_chain_hash_fast_to_str(&l_tx_hash, l_tx_hash_str, 70);
+            if(!dap_strcmp(a_hash_out_type, "hex"))
+                tx_hash_str = dap_strdup(l_tx_hash_str);
+            else
+                tx_hash_str = dap_enc_base58_from_hex_str_to_str(l_tx_hash_str);
+
+            dap_string_append_printf(l_str_out, "transaction: %s hash: %s\n", l_list_tx_token ? "(emit)" : "", tx_hash_str);
+            DAP_DELETE(tx_hash_str);
+
+            dap_list_t *l_list_tmp = l_list_out_items;
+            while(l_list_tmp) {
+                const dap_chain_tx_out_t *l_tx_out = (const dap_chain_tx_out_t*) l_list_tmp->data;
+                // save OUT item l_tx_out - only for first OUT item
+                if(!l_tx_data)
+                {
+                    // save tx hash
+                    l_tx_data = DAP_NEW_Z(dap_tx_data_t);
+                    dap_chain_hash_fast_t l_tx_hash;
+                    dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_tx_hash);
+                    memcpy(&l_tx_data->tx_hash, &l_tx_hash, sizeof(dap_chain_hash_fast_t));
+                    memcpy(&l_tx_data->addr, &l_tx_out->addr, sizeof(dap_chain_addr_t));
+                    dap_chain_hash_fast_to_str(&l_tx_data->tx_hash, l_tx_data->tx_hash_str,
+                            sizeof(l_tx_data->tx_hash_str));
+                    l_tx_data->datum = DAP_NEW_SIZE(dap_chain_datum_t, l_atom_size);
+                    memcpy(l_tx_data->datum, l_datum, l_atom_size);
+                    // save token name
+                    if(l_list_tx_token) {
+                        dap_chain_tx_token_t *tk = l_list_tx_token->data;
+                        memcpy(l_tx_data->token_ticker, tk->header.ticker, sizeof(l_tx_data->token_ticker));
+                    }
+                    // take token from prev out item
+                    else {
+
+                        // find IN items
+                        dap_list_t *l_list_in_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN, NULL);
+                        dap_list_t *l_list_tmp_in = l_list_in_items;
+                        // find token_ticker in prev OUT items
+                        while(l_list_tmp_in) {
+                            const dap_chain_tx_in_t *l_tx_in =
+                                    (const dap_chain_tx_in_t*) l_list_tmp_in->data;
+                            dap_chain_hash_fast_t tx_prev_hash = l_tx_in->header.tx_prev_hash;
+
+                            //find prev OUT item
+                            dap_tx_data_t *l_tx_data_prev = NULL;
+                            HASH_FIND(hh, l_tx_data_hash, &tx_prev_hash, sizeof(dap_chain_hash_fast_t), l_tx_data_prev);
+                            if(l_tx_data_prev != NULL) {
+                                // fill token in l_tx_data from prev transaction
+                                if(l_tx_data) {
+                                    // get token from prev tx
+                                    memcpy(l_tx_data->token_ticker, l_tx_data_prev->token_ticker,
+                                            sizeof(l_tx_data->token_ticker));
+                                    break;
+                                }
+                            }
+                            l_list_tmp_in = dap_list_next(l_list_tmp_in);
+                        }
+                        if(l_list_in_items)
+                            dap_list_free(l_list_in_items);
+                    }
+                    HASH_ADD(hh, l_tx_data_hash, tx_hash, sizeof(dap_chain_hash_fast_t), l_tx_data);
+                }
+                l_list_tmp = dap_list_next(l_list_tmp);
+            }
+            if(l_list_out_items)
+                dap_list_free(l_list_out_items);
+
+            // found a_tx_hash now
+            // transaction time
+            if(l_tx->header.ts_created > 0) {
+                time_t rawtime = (time_t) l_tx->header.ts_created;
+                struct tm l_timeinfo = { 0 };
+                localtime_r(&rawtime, &l_timeinfo);
+                dap_string_append_printf(l_str_out, " %s", asctime(&l_timeinfo));
+            }
+
+            // find all OUT items in transaction
+            l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT, NULL);
+            l_list_tmp = l_list_out_items;
+            while(l_list_tmp) {
+                const dap_chain_tx_out_t *l_tx_out = (const dap_chain_tx_out_t*) l_list_tmp->data;
+                dap_tx_data_t *l_tx_data_prev = NULL;
+
+                const char *l_token_str = NULL;
+                if(l_tx_data)
+                    l_token_str = l_tx_data->token_ticker;
+                char *l_dst_to_str =
+                        (l_tx_out) ? dap_chain_addr_to_str(&l_tx_out->addr) :
+                        NULL;
+                dap_string_append_printf(l_str_out, " OUT item %lld %s to %s\n",
+                        l_tx_out->header.value,
+                        dap_strlen(l_token_str) > 0 ? l_token_str : "?",
+                        l_dst_to_str ? l_dst_to_str : "?"
+                                       );
+                DAP_DELETE(l_dst_to_str);
+                l_list_tmp = dap_list_next(l_list_tmp);
+            }
+
+            // find all IN items in transaction
+            dap_list_t *l_list_in_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN, NULL);
+            l_list_tmp = l_list_in_items;
+            // find cur addr in prev OUT items
+            while(l_list_tmp) {
+                const dap_chain_tx_in_t *l_tx_in = (const dap_chain_tx_in_t*) l_list_tmp->data;
+                dap_chain_hash_fast_t tx_prev_hash = l_tx_in->header.tx_prev_hash;
+                char l_tx_hash_str[70];
+                char *tx_hash_base58_str = NULL;
+                if(!dap_hash_fast_is_blank(&tx_prev_hash)) {
+                    tx_hash_base58_str = dap_enc_base58_from_hex_str_to_str(l_tx_data->tx_hash_str);
+                    dap_chain_hash_fast_to_str(&tx_prev_hash, l_tx_hash_str, sizeof(l_tx_hash_str));
+                }
+                else {
+                    strcpy(l_tx_hash_str, "Null");
+                    tx_hash_base58_str = dap_strdup("Null");
+                }
+                if(!dap_strcmp(a_hash_out_type, "hex"))
+                    dap_string_append_printf(l_str_out, " IN item \n  prev tx_hash %s\n", l_tx_hash_str);
+                else
+                    dap_string_append_printf(l_str_out, " IN item \n  prev tx_hash %s\n", tx_hash_base58_str);
+                DAP_DELETE(tx_hash_base58_str);
+
+                //find prev OUT item
+                dap_tx_data_t *l_tx_data_prev = NULL;
+                HASH_FIND(hh, l_tx_data_hash, &tx_prev_hash, sizeof(dap_chain_hash_fast_t), l_tx_data_prev);
+                if(l_tx_data_prev != NULL) {
+
+                    dap_chain_datum_t *l_datum_prev = get_prev_tx(l_tx_data_prev);
+                    dap_chain_datum_tx_t *l_tx_prev =
+                            l_datum_prev ? (dap_chain_datum_tx_t*) l_datum_prev->data : NULL;
+
+                    // find OUT items in prev datum
+                    dap_list_t *l_list_out_prev_items = dap_chain_datum_tx_items_get(l_tx_prev,
+                            TX_ITEM_TYPE_OUT, NULL);
+                    // find OUT item for IN item;
+                    dap_list_t *l_list_out_prev_item = dap_list_nth(l_list_out_prev_items,
+                            l_tx_in->header.tx_out_prev_idx);
+                    dap_chain_tx_out_t *l_tx_prev_out =
+                            l_list_out_prev_item ?
+                                                   (dap_chain_tx_out_t*) l_list_out_prev_item->data :
+                                                   NULL;
+                    // print value from prev out item
+                    dap_string_append_printf(l_str_out, "  prev OUT item value=%lld",
+                            l_tx_prev_out ? l_tx_prev_out->header.value : 0);
+                }
+                dap_string_append_printf(l_str_out, "\n");
+                l_list_tmp = dap_list_next(l_list_tmp);
+            }
+
+            if(l_list_tx_token)
+                dap_list_free(l_list_tx_token);
+            if(l_list_out_items)
+                dap_list_free(l_list_out_items);
+            if(l_list_in_items)
+                dap_list_free(l_list_in_items);
+            l_tx_hash_found = true;
+            l_tx_num++;
+        }
+            break;
+        default:
+            dap_string_append_printf(l_str_out, "unknown datum type=%d %lld %s to %s\n", l_datum->header.type_id);
+            break;
+        }
+        l_datum_num++;
+    }
+        // go to next transaction
+        l_atom = a_chain->callback_atom_iter_get_next(l_atom_iter, &l_atom_size);
+        //l_atom = a_chain->callback_atom_iter_get_next(l_atom_iter);
+        //l_atom_size = a_chain->callback_atom_get_size(l_atom);
+    }
+    a_chain->callback_atom_iter_delete(l_atom_iter);
+    //total
+    dap_string_append_printf(l_str_out,
+            "---------------\ntokens: %u\nemissions: %u\ntransactions: %u\ntotal datums: %u", l_token_num,
+            l_emission_num, l_tx_num, l_datum_num);
+
+    // return total datums
+    if(a_total_datums)
+        *a_total_datums = l_datum_num;
+    // delete hashes
+    dap_tx_data_t *l_iter_current, *l_item_tmp;
+    HASH_ITER(hh, l_tx_data_hash , l_iter_current, l_item_tmp)
+    {
+        HASH_DEL(l_tx_data_hash, l_iter_current);
+        // delete datum
+        DAP_DELETE(l_iter_current->datum);
+        // delete struct
+        DAP_DELETE(l_iter_current);
+    }
+
+    // if no history
+    if(!l_str_out->len)
+        dap_string_append(l_str_out, "empty");
+    char *l_ret_str = l_str_out ? dap_string_free(l_str_out, false) : NULL;
+    return l_ret_str;
+}
+
+
+
+
+/**
+ * ledger command
+ *
+ */
+int com_ledger(int a_argc, char ** a_argv, void *a_arg_func, char **a_str_reply)
+{
+    enum { CMD_NONE, CMD_LIST, CMD_TX_HISTORY };
+    int arg_index = 1;
+    const char *l_addr_base58 = NULL;
+    const char *l_wallet_name = NULL;
+    const char *l_net_str = NULL;
+    const char *l_chain_str = NULL;
+    const char *l_tx_hash_str = NULL;
+
+    dap_chain_t * l_chain = NULL;
+    dap_chain_net_t * l_net = NULL;
+
+    const char * l_hash_out_type = NULL;
+    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-H", &l_hash_out_type);
+    if(!l_hash_out_type)
+        l_hash_out_type = "base58";
+    if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type,"base58")) {
+        dap_chain_node_cli_set_reply_text(a_str_reply, "invalid parameter -H, valid values: -H <hex | base58>");
+        return -1;
+    }
+
+    int l_cmd = CMD_NONE;
+    if (dap_chain_node_cli_find_option_val(a_argv, 1, 2, "list", NULL))
+        l_cmd = CMD_LIST;
+    else if (dap_chain_node_cli_find_option_val(a_argv, 1, 2, "tx", NULL))
+        l_cmd = CMD_TX_HISTORY;
+    // command tx_history
+    if(l_cmd == CMD_TX_HISTORY) {
+        bool l_is_all = dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-all", NULL);
+        dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-addr", &l_addr_base58);
+        dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_name);
+        dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str);
+        dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-chain", &l_chain_str);
+        dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-tx", &l_tx_hash_str);
+
+        if(!l_is_all && !l_addr_base58 && !l_wallet_name && !l_tx_hash_str) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "command requires parameter '-all' or '-addr' or '-w'");
+            return -1;
+        }
+
+        // Select chain network
+        if(!l_net_str) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "command requires parameter '-net'");
+            return -2;
+        } else {
+            if((l_net = dap_chain_net_by_name(l_net_str)) == NULL) { // Can't find such network
+                dap_chain_node_cli_set_reply_text(a_str_reply,
+                        "command requires parameter '-net' to be valid chain network name");
+                return -3;
+            }
+        }
+        //Select chain emission
+        if(!l_chain_str) { // chain may be null -> then all chain use
+            //dap_chain_node_cli_set_reply_text(a_str_reply, "command requires parameter '-chain'");
+            //return -4;
+        } else {
+            if((l_chain = dap_chain_net_get_chain_by_name(l_net, l_chain_str)) == NULL) { // Can't find such chain
+                dap_chain_node_cli_set_reply_text(a_str_reply,
+                        "command requires parameter '-chain' to be valid chain name in chain net %s",
+                        l_net_str);
+                return -5;
+            }
+        }
+        //char *l_group_mempool = dap_chain_net_get_gdb_group_mempool(l_chain);
+        //const char *l_chain_group = dap_chain_gdb_get_group(l_chain);
+
+        dap_chain_hash_fast_t l_tx_hash;
+        if(l_tx_hash_str) {
+            if(dap_chain_hash_fast_from_str(l_tx_hash_str, &l_tx_hash) < 0) {
+                l_tx_hash_str = NULL;
+                dap_chain_node_cli_set_reply_text(a_str_reply, "tx hash not recognized");
+                return -1;
+            }
+//        char hash_str[99];
+//        dap_chain_hash_fast_to_str(&l_tx_hash, hash_str,99);
+//        int gsdgsd=523;
+        }
+        dap_chain_addr_t *l_addr = NULL;
+        // if need addr
+        if(l_wallet_name || l_addr_base58) {
+            if(l_wallet_name) {
+                const char *c_wallets_path = dap_chain_wallet_get_path(g_config);
+                dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_wallet_name, c_wallets_path);
+                if(l_wallet) {
+                    dap_chain_addr_t *l_addr_tmp = (dap_chain_addr_t *) dap_chain_wallet_get_addr(l_wallet,
+                            l_net->pub.id);
+                    l_addr = DAP_NEW_SIZE(dap_chain_addr_t, sizeof(dap_chain_addr_t));
+                    memcpy(l_addr, l_addr_tmp, sizeof(dap_chain_addr_t));
+                    dap_chain_wallet_close(l_wallet);
+                }
+            }
+            if(!l_addr && l_addr_base58) {
+                l_addr = dap_chain_addr_from_str(l_addr_base58);
+            }
+            if(!l_addr && !l_tx_hash_str) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "wallet address not recognized");
+                return -1;
+            }
+        }
+
+        dap_string_t *l_str_ret = dap_string_new(NULL); //char *l_str_ret = NULL;
+        dap_chain_t *l_chain_cur;
+        void *l_chain_tmp = (void*)0x1;
+        int l_num = 0;
+        // only one chain
+        if(l_chain)
+            l_chain_cur = l_chain;
+        // all chain
+        else
+            l_chain_cur = dap_chain_enum(&l_chain_tmp);
+        while(l_chain_cur) {
+            // only selected net
+            if(l_net->pub.id.uint64 == l_chain_cur->net_id.uint64) {
+                // separator between chains
+                if(l_num>0 && !l_chain)
+                    dap_string_append(l_str_ret, "---------------\n");
+
+                char *l_str_out = NULL;
+                dap_string_append_printf(l_str_ret, "chain: %s\n", l_chain_cur->name);
+                if(l_is_all) {
+                    // without filters
+                    l_str_out = dap_db_history_filter(l_chain_cur, NULL, NULL, l_hash_out_type, -1, 0, NULL);
+                    dap_string_append_printf(l_str_ret, "all history:\n%s\n", l_str_out ? l_str_out : " empty");
+                }
+                else {
+                    l_str_out = l_tx_hash_str ?
+                                                dap_db_history_tx(&l_tx_hash, l_chain_cur, l_hash_out_type) :
+                                                dap_db_history_addr(l_addr, l_chain_cur, l_hash_out_type);
+
+                    if(l_tx_hash_str) {
+                        dap_string_append_printf(l_str_ret, "history for tx hash %s:\n%s\n", l_tx_hash_str,
+                                l_str_out ? l_str_out : " empty");
+                    }
+                    else if(l_addr) {
+                        char *l_addr_str = dap_chain_addr_to_str(l_addr);
+                        dap_string_append_printf(l_str_ret, "history for addr %s:\n%s\n", l_addr_str,
+                                l_str_out ? l_str_out : " empty");
+                        DAP_DELETE(l_addr_str);
+                    }
+                }
+                DAP_DELETE(l_str_out);
+                l_num++;
+            }
+            // only one chain use
+            if(l_chain)
+                break;
+            dap_chain_enum_unlock();
+            l_chain_cur = dap_chain_enum(&l_chain_tmp);
+        }
+        // all chain
+        if(!l_chain)
+            dap_chain_enum_unlock();
+        dap_chain_node_cli_set_reply_text(a_str_reply, l_str_ret->str);
+        dap_string_free(l_str_ret, true);
+        return 0;
+    }
+    else{
+        dap_chain_node_cli_set_reply_text(a_str_reply, "command requires parameter 'list' or 'tx' or 'info'");
+        return -1;
+    }
+}
+
+/**
+ * token command
+ *
+ */
+int com_token(int a_argc, char ** a_argv, void *a_arg_func, char **a_str_reply)
+{
+    enum { CMD_NONE, CMD_LIST, CMD_INFO, CMD_TX };
+    int arg_index = 1;
+    //const char *l_addr_base58 = NULL;
+    //const char *l_wallet_name = NULL;
+    const char *l_net_str = NULL;
+    const char *l_chain_str = NULL;
+
+    dap_chain_t * l_chain = NULL;
+    dap_chain_net_t * l_net = NULL;
+
+    const char * l_hash_out_type = NULL;
+    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-H", &l_hash_out_type);
+    if(!l_hash_out_type)
+        l_hash_out_type = "base58";
+    if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type,"base58")) {
+        dap_chain_node_cli_set_reply_text(a_str_reply, "invalid parameter -H, valid values: -H <hex | base58>");
+        return -1;
+    }
+
+    //bool l_is_all = dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-all", NULL);
+    //dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-addr", &l_addr_base58);
+    //dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-w", &l_wallet_name);
+    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str);
+    //dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-chain", &l_chain_str);
+    //dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-tx", &l_tx_hash_str);
+
+    // Select chain network
+    if(!l_net_str) {
+        dap_chain_node_cli_set_reply_text(a_str_reply, "command requires parameter '-net'");
+        return -2;
+    } else {
+        if((l_net = dap_chain_net_by_name(l_net_str)) == NULL) { // Can't find such network
+            dap_chain_node_cli_set_reply_text(a_str_reply,
+                    "command requires parameter '-net' to be valid chain network name");
+            return -3;
+        }
+    }
+
+    int l_cmd = CMD_NONE;
+    if (dap_chain_node_cli_find_option_val(a_argv, 1, 2, "list", NULL))
+        l_cmd = CMD_LIST;
+    else if (dap_chain_node_cli_find_option_val(a_argv, 1, 2, "info", NULL))
+        l_cmd = CMD_INFO;
+    else if (dap_chain_node_cli_find_option_val(a_argv, 1, 2, "tx", NULL))
+            l_cmd = CMD_TX;
+    // token list
+    if(l_cmd == CMD_LIST) {
+        dap_string_t *l_str_out = dap_string_new(NULL);
+        size_t l_token_num_total = 0;
+        // get first chain
+        void *l_chain_tmp = (void*)0x1;
+        dap_chain_t *l_chain_cur = dap_chain_enum(&l_chain_tmp);
+        while(l_chain_cur) {
+            // only selected net
+            if(l_net->pub.id.uint64 == l_chain_cur->net_id.uint64) {
+                size_t l_token_num = 0;
+                char *token_list_str = dap_db_history_token_list(l_chain_cur, NULL, l_hash_out_type, &l_token_num);
+                if(token_list_str)
+                    dap_string_append(l_str_out, token_list_str);
+                l_token_num_total += l_token_num;
+            }
+            // next chain
+            dap_chain_enum_unlock();
+            l_chain_cur = dap_chain_enum(&l_chain_tmp);
+        }
+        dap_chain_enum_unlock();
+        //total
+        dap_string_append_printf(l_str_out, "---------------\ntokens: %u\n", l_token_num_total);
+        dap_chain_node_cli_set_reply_text(a_str_reply, l_str_out->str);
+        dap_string_free(l_str_out, true);
+        return 0;
+
+    }
+    // token info
+    else if(l_cmd == CMD_INFO) {
+        const char *l_token_name_str = NULL;
+        dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-name", &l_token_name_str);
+        if(!l_token_name_str) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "command requires parameter '-name' <token name>");
+                return -4;
+            }
+
+            dap_string_t *l_str_out = dap_string_new(NULL);
+            size_t l_token_num_total = 0;
+            // get first chain
+            void *l_chain_tmp = (void*)0x1;
+            dap_chain_t *l_chain_cur = dap_chain_enum(&l_chain_tmp);
+            while(l_chain_cur) {
+                // only selected net
+                if(l_net->pub.id.uint64 == l_chain_cur->net_id.uint64) {
+                    size_t l_token_num = 0;
+                    // filter - token name
+                    char *token_list_str = dap_db_history_token_list(l_chain_cur, l_token_name_str, l_hash_out_type, &l_token_num);
+                    if(token_list_str)
+                        dap_string_append(l_str_out, token_list_str);
+                    l_token_num_total += l_token_num;
+                }
+                // next chain
+                dap_chain_enum_unlock();
+                l_chain_cur = dap_chain_enum(&l_chain_tmp);
+            }
+            dap_chain_enum_unlock();
+            if(!l_token_num_total)
+                dap_string_append_printf(l_str_out, "token '%s' not found\n", l_token_name_str);
+            dap_chain_node_cli_set_reply_text(a_str_reply, l_str_out->str);
+            dap_string_free(l_str_out, true);
+            return 0;
+
+    }
+    // command tx history
+    else if(l_cmd == CMD_TX) {
+
+        enum { SUBCMD_TX_NONE, SUBCMD_TX_ALL, SUBCMD_TX_ADDR };
+        // find subcommand
+        int l_subcmd = CMD_NONE;
+        const char *l_addr_base58_str = NULL;
+        const char *l_wallet_name = NULL;
+        if(dap_chain_node_cli_find_option_val(a_argv, 2, a_argc, "-all", NULL))
+            l_subcmd = SUBCMD_TX_ALL;
+        else if(dap_chain_node_cli_find_option_val(a_argv, 2, a_argc, "-addr", &l_addr_base58_str))
+            l_subcmd = SUBCMD_TX_ADDR;
+        else if(dap_chain_node_cli_find_option_val(a_argv, 2, a_argc, "-wallet", &l_wallet_name))
+            l_subcmd = SUBCMD_TX_ADDR;
+
+        const char *l_token_name_str = NULL;
+        const char *l_page_start_str = NULL;
+        const char *l_page_size_str = NULL;
+        const char *l_page_str = NULL;
+        dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-name", &l_token_name_str);
+        dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-page_start", &l_page_start_str);
+        dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-page_size", &l_page_size_str);
+        dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-page", &l_page_str);
+        if(!l_token_name_str) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "command requires parameter '-name' <token name>");
+            return -4;
+        }
+        long l_page_start = -1;// not used if =-1
+        long l_page_size = 10;
+        long l_page = 2;
+        long l_cur_datum = 0;
+        if(l_page_start_str)
+            l_page_start = strtol(l_page_start_str, NULL, 10);
+        if(l_page_size_str) {
+            l_page_size = strtol(l_page_size_str, NULL, 10);
+            if(l_page_size < 1)
+                l_page_size = 1;
+        }
+        if(l_page_str) {
+            l_page = strtol(l_page_str, NULL, 10);
+            if(l_page < 1)
+                l_page = 1;
+        }
+
+
+         // tx all
+        if(l_subcmd == SUBCMD_TX_ALL) {
+            dap_string_t *l_str_out = dap_string_new(NULL);
+            // get first chain
+            void *l_chain_tmp = (void*) 0x1;
+            dap_chain_t *l_chain_cur = dap_chain_enum(&l_chain_tmp);
+            while(l_chain_cur) {
+                // only selected net
+                if(l_net->pub.id.uint64 == l_chain_cur->net_id.uint64) {
+                    long l_chain_datum = l_cur_datum;
+                    char *l_datum_list_str = dap_db_history_filter(l_chain_cur, l_token_name_str, NULL,
+                            l_hash_out_type, l_page_start * l_page_size, (l_page_start+l_page)*l_page_size, &l_chain_datum);
+                    if(l_datum_list_str) {
+                        l_cur_datum += l_chain_datum;
+                        dap_string_append_printf(l_str_out, "Chain: %s\n", l_chain_cur->name);
+                        dap_string_append_printf(l_str_out, "%s\n\n", l_datum_list_str);
+                        DAP_DELETE(l_datum_list_str);
+                    }
+                }
+                // next chain
+                dap_chain_enum_unlock();
+                l_chain_cur = dap_chain_enum(&l_chain_tmp);
+            }
+            dap_chain_enum_unlock();
+            dap_chain_node_cli_set_reply_text(a_str_reply, l_str_out->str);
+            dap_string_free(l_str_out, true);
+            return 0;
+        }
+        // tx -addr or tx -wallet
+        else if(l_subcmd == SUBCMD_TX_ADDR) {
+            // parse addr from -addr <addr> or -wallet <wallet>
+            dap_chain_addr_t *l_addr_base58 = NULL;
+            if(l_addr_base58_str) {
+                //l_addr_base58 = dap_strdup(l_addr_base58_str);
+                l_addr_base58 = dap_chain_addr_from_str(l_addr_base58_str);
+            }
+            else if(l_wallet_name) {
+                const char *c_wallets_path = dap_chain_wallet_get_path(g_config);
+                dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_wallet_name, c_wallets_path);
+                if(l_wallet) {
+                    dap_chain_addr_t *l_addr_tmp = (dap_chain_addr_t *) dap_chain_wallet_get_addr(l_wallet,
+                            l_net->pub.id);
+                    l_addr_base58 = DAP_NEW_SIZE(dap_chain_addr_t, sizeof(dap_chain_addr_t));
+                    memcpy(l_addr_base58, l_addr_tmp, sizeof(dap_chain_addr_t));
+                    dap_chain_wallet_close(l_wallet);
+                    char *ffl_addr_base58 = dap_chain_addr_to_str(l_addr_base58);
+                    ffl_addr_base58 = 0;
+                }
+                else {
+                    dap_chain_node_cli_set_reply_text(a_str_reply, "wallet '%s' not found", l_wallet_name);
+                    return -2;
+                }
+            }
+            if(!l_addr_base58) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "address not recognized");
+                return -3;
+            }
+
+            dap_string_t *l_str_out = dap_string_new(NULL);
+            // get first chain
+            void *l_chain_tmp = (void*) 0x1;
+            dap_chain_t *l_chain_cur = dap_chain_enum(&l_chain_tmp);
+            while(l_chain_cur) {
+                // only selected net
+                if(l_net->pub.id.uint64 == l_chain_cur->net_id.uint64) {
+                    long l_chain_datum = l_cur_datum;
+                    char *l_datum_list_str = dap_db_history_addr(l_addr_base58, l_chain_cur, l_hash_out_type);
+                    if(l_datum_list_str) {
+                        l_cur_datum += l_chain_datum;
+                        dap_string_append_printf(l_str_out, "Chain: %s\n", l_chain_cur->name);
+                        dap_string_append_printf(l_str_out, "%s\n\n", l_datum_list_str);
+                        DAP_DELETE(l_datum_list_str);
+                    }
+                }
+                // next chain
+                dap_chain_enum_unlock();
+                l_chain_cur = dap_chain_enum(&l_chain_tmp);
+            }
+            dap_chain_enum_unlock();
+            dap_chain_node_cli_set_reply_text(a_str_reply, l_str_out->str);
+            dap_string_free(l_str_out, true);
+            DAP_DELETE(l_addr_base58);
+            return 0;
+
+        }
+        else{
+            dap_chain_node_cli_set_reply_text(a_str_reply, "not found parameter '-all', '-wallet' or '-addr'");
+            return -1;
+        }
+        return 0;
+    }
+
+    dap_chain_node_cli_set_reply_text(a_str_reply, "unknown command code %d", l_cmd);
+    return -5;
+}
+
+
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 64fb1fbc0c12fe905efac4c8185075945b73a13d..a7a1a4a317cd9bd34e74e437e3d28771e03c0499 100644
--- a/modules/net/include/dap_chain_node_cli_cmd_tx.h
+++ b/modules/net/include/dap_chain_node_cli_cmd_tx.h
@@ -31,3 +31,16 @@
  */
 char* dap_db_history_tx(dap_chain_hash_fast_t* a_tx_hash, dap_chain_t * a_chain, const char *a_hash_out_type);
 char* dap_db_history_addr(dap_chain_addr_t * a_addr, dap_chain_t * a_chain, const char *a_hash_out_type);
+
+/**
+ * ledger command
+ *
+ */
+int com_ledger(int a_argc, char ** a_argv, void *a_arg_func, char **a_str_reply);
+
+/**
+ * token command
+ *
+ */
+int com_token(int a_argc, char ** a_argv, void *a_arg_func, char **a_str_reply);
+