diff --git a/3rdparty/cuttdb/CMakeLists.txt b/3rdparty/cuttdb/CMakeLists.txt
index 948b986642c799003bfa48b0893c3b022f6805b0..2fb2bf49fcd21fd80fb7fa7f79a133ffcb2775fc 100755
--- a/3rdparty/cuttdb/CMakeLists.txt
+++ b/3rdparty/cuttdb/CMakeLists.txt
@@ -23,9 +23,5 @@ endif()
 add_library(${PROJECT_NAME} STATIC ${cuttdb_src})
 set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE C)
 set_target_properties(${PROJECT_NAME} PROPERTIES COMPILER_LANGUAGE C)
-
-set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE C)
-
-target_link_libraries(${PROJECT_NAME})
-
 target_include_directories(${PROJECT_NAME} INTERFACE src)
+target_compile_options(${PROJECT_NAME} PRIVATE -Wno-sign-compare)
diff --git a/3rdparty/cuttdb/src/cdb_core.c b/3rdparty/cuttdb/src/cdb_core.c
index 62c35371b3d26b07d6a275e6f1bb87706b2b6153..75aabebe36dd7a12e0101d14a2229e0824d4ee64 100644
--- a/3rdparty/cuttdb/src/cdb_core.c
+++ b/3rdparty/cuttdb/src/cdb_core.c
@@ -41,6 +41,9 @@ static void _cdb_pagewarmup(CDB *db, bool loadbf);
 /* it isn't necessary to rehash bid in hash table cache */
 static uint32_t _pagehash(const void *key, int len)
 {
+    uint32_t tst = 0;
+    if (len < tst)
+        return 0;
     (void) len;
     return *(uint32_t*)key;
 }
diff --git a/3rdparty/libmaxminddb/CMakeLists.txt b/3rdparty/libmaxminddb/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e9ae197bd4727e21acbbafec2c0f3310aaad83bb
--- /dev/null
+++ b/3rdparty/libmaxminddb/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.10)
+
+project(maxminddb C)
+
+add_definitions ("-D_GNU_SOURCE")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
+
+file(GLOB maxminddb_src ${CMAKE_CURRENT_SOURCE_DIR} *.c)
+file(GLOB maxminddb_h ${CMAKE_CURRENT_SOURCE_DIR} *.h)
+
+add_library(${PROJECT_NAME} STATIC ${maxminddb_src} ${maxminddb_h})
+set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE C)
+set_target_properties(${PROJECT_NAME} PROPERTIES COMPILER_LANGUAGE C)
+target_include_directories(${PROJECT_NAME} INTERFACE .)
+target_compile_options(${PROJECT_NAME} PRIVATE -Wno-sign-compare)
diff --git a/modules/net/srv/libmaxminddb/data-pool.c b/3rdparty/libmaxminddb/data-pool.c
similarity index 100%
rename from modules/net/srv/libmaxminddb/data-pool.c
rename to 3rdparty/libmaxminddb/data-pool.c
diff --git a/modules/net/srv/libmaxminddb/data-pool.h b/3rdparty/libmaxminddb/data-pool.h
similarity index 100%
rename from modules/net/srv/libmaxminddb/data-pool.h
rename to 3rdparty/libmaxminddb/data-pool.h
diff --git a/modules/net/srv/libmaxminddb/maxminddb-compat-util.h b/3rdparty/libmaxminddb/maxminddb-compat-util.h
similarity index 100%
rename from modules/net/srv/libmaxminddb/maxminddb-compat-util.h
rename to 3rdparty/libmaxminddb/maxminddb-compat-util.h
diff --git a/modules/net/srv/libmaxminddb/maxminddb.c b/3rdparty/libmaxminddb/maxminddb.c
similarity index 100%
rename from modules/net/srv/libmaxminddb/maxminddb.c
rename to 3rdparty/libmaxminddb/maxminddb.c
diff --git a/modules/net/srv/libmaxminddb/maxminddb.h b/3rdparty/libmaxminddb/maxminddb.h
similarity index 100%
rename from modules/net/srv/libmaxminddb/maxminddb.h
rename to 3rdparty/libmaxminddb/maxminddb.h
diff --git a/modules/net/srv/libmaxminddb/maxminddb_config.h b/3rdparty/libmaxminddb/maxminddb_config.h
similarity index 100%
rename from modules/net/srv/libmaxminddb/maxminddb_config.h
rename to 3rdparty/libmaxminddb/maxminddb_config.h
diff --git a/modules/net/srv/libmaxminddb/mmdblookup.c b/3rdparty/libmaxminddb/mmdblookup.c
similarity index 100%
rename from modules/net/srv/libmaxminddb/mmdblookup.c
rename to 3rdparty/libmaxminddb/mmdblookup.c
diff --git a/3rdparty/libmdbx/config.h b/3rdparty/libmdbx/config.h
new file mode 100644
index 0000000000000000000000000000000000000000..b8983250d7e7eccd96e832d50ebb0aca5ad225d2
--- /dev/null
+++ b/3rdparty/libmdbx/config.h
@@ -0,0 +1,63 @@
+/* This is CMake-template for libmdbx's config.h
+ ******************************************************************************/
+
+/* *INDENT-OFF* */
+/* clang-format off */
+
+/* #undef LTO_ENABLED */
+/* #undef MDBX_USE_VALGRIND */
+/* #undef ENABLE_GPROF */
+/* #undef ENABLE_GCOV */
+/* #undef ENABLE_ASAN */
+/* #undef ENABLE_UBSAN */
+#define MDBX_FORCE_ASSERTIONS 0
+
+/* Common */
+#define MDBX_TXN_CHECKOWNER 1
+#define MDBX_ENV_CHECKPID_AUTO
+#ifndef MDBX_ENV_CHECKPID_AUTO
+#define MDBX_ENV_CHECKPID 0
+#endif
+#define MDBX_LOCKING_AUTO
+#ifndef MDBX_LOCKING_AUTO
+/* #undef MDBX_LOCKING */
+#endif
+#define MDBX_TRUST_RTC_AUTO
+#ifndef MDBX_TRUST_RTC_AUTO
+#define MDBX_TRUST_RTC 0
+#endif
+#define MDBX_DISABLE_PAGECHECKS 0
+
+/* Windows */
+#define MDBX_WITHOUT_MSVC_CRT 0
+
+/* MacOS & iOS */
+#define MDBX_OSX_SPEED_INSTEADOF_DURABILITY 0
+
+/* POSIX */
+#define MDBX_DISABLE_GNU_SOURCE 0
+#define MDBX_USE_OFDLOCKS_AUTO
+#ifndef MDBX_USE_OFDLOCKS_AUTO
+#define MDBX_USE_OFDLOCKS 0
+#endif
+
+/* Build Info */
+#ifndef MDBX_BUILD_TIMESTAMP
+#define MDBX_BUILD_TIMESTAMP "2022-11-07T16:21:48Z"
+#endif
+#ifndef MDBX_BUILD_TARGET
+#define MDBX_BUILD_TARGET "x86_64-ELF-Linux"
+#endif
+#ifndef MDBX_BUILD_TYPE
+#define MDBX_BUILD_TYPE "Debug"
+#endif
+#ifndef MDBX_BUILD_COMPILER
+#define MDBX_BUILD_COMPILER "gcc (Debian 10.2.1-6) 10.2.1 20210110"
+#endif
+#ifndef MDBX_BUILD_FLAGS
+#define MDBX_BUILD_FLAGS "-g MDBX_BUILD_SHARED_LIBRARY=0 -ffast-math -fvisibility=hidden"
+#endif
+/* #undef MDBX_BUILD_SOURCERY */
+
+/* *INDENT-ON* */
+/* clang-format on */
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7ee58dc40662dd89668b818460671143adf6a004..f07a3c7600feae3ffa59c913f06daf89a0a8fc9c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -105,10 +105,6 @@ endif()
 
 add_subdirectory(dap-sdk)
 add_subdirectory(3rdparty/monero_crypto)
-add_subdirectory(3rdparty/cuttdb)
-if (BUILD_WITH_GDB_DRIVER_MDBX)
-add_subdirectory(3rdparty/libmdbx)
-endif()
 if(DAPSDK_MODULES MATCHES "ssl-support")
     add_subdirectory(3rdparty/wolfssl)
 endif()
@@ -250,7 +246,7 @@ endif()
 if (WIN32)
     set(CELLFRAME_LIBS ${CELLFRAME_LIBS} kernel32 user32 shell32 winmm gdi32 advapi32
 					 ole32 version imm32 oleaut32 ws2_32 ntdll psapi 
-                                         shlwapi bcrypt crypt32 secur32 userenv mqrt)
+                                         shlwapi bcrypt crypt32 secur32 userenv) #mqrt)
 endif()
 
 if (DARWIN)
diff --git a/dap-sdk/core/include/dap_common.h b/dap-sdk/core/include/dap_common.h
index c7dfb5a5d13eadb58d1a657ae2346f63e8dae941..5e8a7888323f654a21843a33407ab1809af0aa66 100755
--- a/dap-sdk/core/include/dap_common.h
+++ b/dap-sdk/core/include/dap_common.h
@@ -28,6 +28,16 @@
 #ifndef __STDC_WANT_LIB_EXT1__
 #define __STDC_WANT_LIB_EXT1__ 1
 #endif
+
+#ifdef DAP_OS_WINDOWS
+#ifndef _INC_WINDOWS
+#include <winsock2.h>
+#endif
+#include <fcntl.h>
+#define pipe(pfds) _pipe(pfds, 4096, _O_BINARY)
+#define strerror_r(arg1, arg2, arg3) strerror_s(arg2, arg3, arg1)
+#endif
+
 #include <string.h>
 #include <stdarg.h>
 #include <stddef.h>
@@ -45,12 +55,6 @@
 #define atomic_uint _Atomic(uint)
 #endif
 
-#include <time.h>
-#ifdef DAP_OS_WINDOWS
-#include <fcntl.h>
-#define pipe(pfds) _pipe(pfds, 4096, _O_BINARY)
-#define strerror_r(arg1, arg2, arg3) strerror_s(arg2, arg3, arg1)
-#endif
 #ifdef __MACH__
 #include <dispatch/dispatch.h>
 #endif
diff --git a/dap-sdk/core/src/dap_list.c b/dap-sdk/core/src/dap_list.c
index 86a93a231892432b3f53f13fcc3d7c7c7252e419..3cbdaa944f8ae8c5da5f9bd5d9a70ca152fde4e7 100755
--- a/dap-sdk/core/src/dap_list.c
+++ b/dap-sdk/core/src/dap_list.c
@@ -494,32 +494,20 @@ dap_list_t *dap_list_copy(dap_list_t *list)
  */
 dap_list_t *dap_list_copy_deep(dap_list_t *list, dap_callback_copy_t func, void* user_data)
 {
-    dap_list_t *new_list = NULL;
+    dap_list_t *last, *new_list = NULL;
 
-    if(list)
-    {
-        dap_list_t *last;
-
-        new_list = dap_list_alloc();
-        if(func)
-            new_list->data = func(list->data, user_data);
-        else
-            new_list->data = list->data;
-        new_list->prev = NULL;
-        last = new_list;
-        list = list->next;
-        while(list)
-        {
+    while (list) {
+        if (new_list) {
             last->next = dap_list_alloc();
             last->next->prev = last;
             last = last->next;
-            if(func)
-                last->data = func(list->data, user_data);
-            else
-                last->data = list->data;
-            list = list->next;
-        }
-        last->next = NULL;
+        } else
+            new_list = last = dap_list_alloc();
+        if (func)
+            last->data = func(list->data, user_data);
+        else
+            last->data = list->data;
+        list = list->next;
     }
 
     return new_list;
diff --git a/dap-sdk/core/src/win32/dap_cpu_monitor.c b/dap-sdk/core/src/win32/dap_cpu_monitor.c
index 68e80f290c8a1620344a5733dea4d431dfdf3b59..0b843282305111b0278260139d40848cca6f8837 100644
--- a/dap-sdk/core/src/win32/dap_cpu_monitor.c
+++ b/dap-sdk/core/src/win32/dap_cpu_monitor.c
@@ -18,14 +18,13 @@
     along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include <windows.h>
-//#include <winnt.h>
-#include <winternl.h>
-
 #include <stdio.h>
 #include <stdint.h>
 #include <string.h>
 #include <stdlib.h>
+#include <windows.h>
+//#include <winnt.h>
+#include <winternl.h>
 
 #include "dap_cpu_monitor.h"
 #include "dap_common.h"
diff --git a/dap-sdk/core/src/win32/dap_cpu_monitor.h b/dap-sdk/core/src/win32/dap_cpu_monitor.h
index efec16511a597a4bb970d20f463d55f64c76a2aa..a8f39ae5517478cf915f2431532b8fe0d9be8b65 100644
--- a/dap-sdk/core/src/win32/dap_cpu_monitor.h
+++ b/dap-sdk/core/src/win32/dap_cpu_monitor.h
@@ -1,5 +1,7 @@
 #pragma once
 
+#include <stdint.h>
+
 #define MAX_CPU_COUNT 64
 
 typedef struct dap_cpu {
diff --git a/dap-sdk/core/src/win32/dap_process_memory.h b/dap-sdk/core/src/win32/dap_process_memory.h
index d2f13c86a851a6e9654d6317ff16454d283bef26..78659cc2d7c52e4ee2cc4701ab7fbd132d8886cd 100644
--- a/dap-sdk/core/src/win32/dap_process_memory.h
+++ b/dap-sdk/core/src/win32/dap_process_memory.h
@@ -1,6 +1,6 @@
 
-//#include <stdint.h>
-//#include <sys/types.h>
+#include <stdint.h>
+#include <sys/types.h>
 
 
 typedef struct dap_process_memory {
diff --git a/dap-sdk/io/dap_context.c b/dap-sdk/io/dap_context.c
index f7cd5f11ae9da2b273cd46b11f7e856dacbf0c66..d843236ff9b06706b5009be22d4a0bb6fbabaf46 100644
--- a/dap-sdk/io/dap_context.c
+++ b/dap-sdk/io/dap_context.c
@@ -887,6 +887,8 @@ static int s_thread_loop(dap_context_t * a_context)
 #elif defined (DAP_EVENTS_CAPS_QUEUE_POSIX)
                                     l_bytes_sent = mq_send(a_es->mqd, (const char *)&a_arg,sizeof (a_arg),0);
 #elif defined DAP_EVENTS_CAPS_MSMQ
+                                    /* TODO: Windows-way message waiting and handling
+                                     *
                                     DWORD l_mp_id = 0;
                                     MQMSGPROPS    l_mps;
                                     MQPROPVARIANT l_mpvar[1];
@@ -916,6 +918,11 @@ static int s_thread_loop(dap_context_t * a_context)
                                         }
                                         l_bytes_sent = sizeof(void*);
                                     }
+                                    */
+                                    l_bytes_sent = dap_sendto(l_cur->socket, l_cur->port, l_cur->buf_out, l_cur->buf_out_size);
+                                    if (l_bytes_sent == SOCKET_ERROR) {
+                                        log_it(L_ERROR, "Write to socket error: %d", WSAGetLastError());
+                                    }
 #elif defined (DAP_EVENTS_CAPS_QUEUE_MQUEUE)
                                     l_bytes_sent = mq_send(l_cur->mqd , (const char *)l_cur->buf_out,sizeof (void*),0);
                                     if(l_bytes_sent == 0)
@@ -1610,13 +1617,7 @@ dap_events_socket_t *dap_context_find(dap_context_t * a_context, dap_events_sock
     unsigned long l_mode = 1;
     ioctlsocket(l_es->socket, FIONBIO, &l_mode);
 
-    int l_addr_len;
-    struct sockaddr_in l_addr;
-    l_addr.sin_family = AF_INET;
-    IN_ADDR _in_addr = { { .S_addr = htonl(INADDR_LOOPBACK) } };
-    l_addr.sin_addr = _in_addr;
-    l_addr.sin_port = 0; //l_es->socket  + 32768;
-    l_addr_len = sizeof(struct sockaddr_in);
+    struct sockaddr_in l_addr = { .sin_family = AF_INET, .sin_port = 0, .sin_addr = {{ .S_addr = htonl(INADDR_LOOPBACK) }} };
 
     if (bind(l_es->socket, (struct sockaddr*)&l_addr, sizeof(l_addr)) < 0) {
         log_it(L_ERROR, "Bind error: %d", WSAGetLastError());
@@ -1624,9 +1625,8 @@ dap_events_socket_t *dap_context_find(dap_context_t * a_context, dap_events_sock
         int dummy = 100;
         getsockname(l_es->socket, (struct sockaddr*)&l_addr, &dummy);
         l_es->port = l_addr.sin_port;
-        //log_it(L_DEBUG, "Bound to port %d", l_addr.sin_port);
     }
-
+    /*
     MQQUEUEPROPS   l_qps;
     MQPROPVARIANT  l_qp_var[1];
     QUEUEPROPID    l_qp_id[1];
@@ -1691,6 +1691,7 @@ dap_events_socket_t *dap_context_find(dap_context_t * a_context, dap_events_sock
     if (hr != MQ_OK) {
         log_it(L_DEBUG, "Message queue %u NOT purged, possible data corruption, err %ld", l_es->mq_num, hr);
     }
+    */
 #elif defined (DAP_EVENTS_CAPS_KQUEUE)
     // We don't create descriptor for kqueue at all
 #else
@@ -1779,13 +1780,7 @@ dap_events_socket_t * dap_context_create_event(dap_context_t * a_context, dap_ev
     if (setsockopt(l_es->socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0)
         log_it(L_WARNING, "Can't set up REUSEADDR flag to the socket, err: %d", WSAGetLastError());
 
-    int l_addr_len;
-    struct sockaddr_in l_addr;
-    l_addr.sin_family = AF_INET;
-    IN_ADDR _in_addr = { { .S_addr = htonl(INADDR_LOOPBACK) } };
-    l_addr.sin_addr = _in_addr;
-    l_addr.sin_port = 0; //l_es->socket + 32768;
-    l_addr_len = sizeof(struct sockaddr_in);
+    struct sockaddr_in l_addr = { .sin_family = AF_INET, .sin_port = 0, .sin_addr = {{ .S_addr = htonl(INADDR_LOOPBACK) }} };
 
     if (bind(l_es->socket, (struct sockaddr*)&l_addr, sizeof(l_addr)) < 0) {
         log_it(L_ERROR, "Bind error: %d", WSAGetLastError());
@@ -1793,7 +1788,6 @@ dap_events_socket_t * dap_context_create_event(dap_context_t * a_context, dap_ev
         int dummy = 100;
         getsockname(l_es->socket, (struct sockaddr*)&l_addr, &dummy);
         l_es->port = l_addr.sin_port;
-        //log_it(L_DEBUG, "Bound to port %d", l_addr.sin_port);
     }
 #elif defined(DAP_EVENTS_CAPS_KQUEUE)
     // nothing to do
diff --git a/dap-sdk/io/dap_events.c b/dap-sdk/io/dap_events.c
index 062d32dba5da53b25d75ea09a1816195cfdcfbfa..638be0c9a44dee0cd04ad13fd8c31384248a2742 100644
--- a/dap-sdk/io/dap_events.c
+++ b/dap-sdk/io/dap_events.c
@@ -221,7 +221,6 @@ void dap_cpu_assign_thread_on(uint32_t a_cpu_id)
  */
 int dap_events_init( uint32_t a_threads_count, size_t a_conn_timeout )
 {
-
     g_debug_reactor = g_config ? dap_config_get_item_bool_default(g_config, "general", "debug_reactor", false) : false;
 
     uint32_t l_cpu_count = dap_get_cpu_count();
@@ -237,7 +236,6 @@ int dap_events_init( uint32_t a_threads_count, size_t a_conn_timeout )
     if(dap_context_init() != 0){
         log_it( L_CRITICAL, "Can't init client submodule dap_context( )" );
         goto err;
-
     }
 
     dap_worker_init(a_conn_timeout);
diff --git a/dap-sdk/io/dap_events_socket.c b/dap-sdk/io/dap_events_socket.c
index 7bf7a0bb04cb19b4aff6cca5b8334058f2a9a91c..30f0ded9065cd24bd230d326203b61098b08d3ab 100644
--- a/dap-sdk/io/dap_events_socket.c
+++ b/dap-sdk/io/dap_events_socket.c
@@ -468,7 +468,7 @@ dap_events_socket_t * dap_events_socket_queue_ptr_create_input(dap_events_socket
     l_es->socket        = a_es->socket;
     l_es->port          = a_es->port;
     l_es->mq_num        = a_es->mq_num;
-
+    /*
     WCHAR l_direct_name[MQ_MAX_Q_NAME_LEN] = { 0 };
     int pos = 0;
 #ifdef DAP_BRAND
@@ -497,6 +497,7 @@ dap_events_socket_t * dap_events_socket_queue_ptr_create_input(dap_events_socket
         log_it(L_ERROR, "Can't open message queue for queue type, error: %ld", hr);
         return NULL;
     }
+    */
 #elif defined (DAP_EVENTS_CAPS_KQUEUE)
     // We don't create descriptor for kqueue at all
 #else
@@ -532,9 +533,10 @@ dap_events_socket_t * dap_events_socket_create_type_queue_ptr_mt(dap_worker_t *
 int dap_events_socket_queue_proc_input_unsafe(dap_events_socket_t * a_esocket)
 {
 #ifdef DAP_OS_WINDOWS
-    int l_read = dap_recvfrom(a_esocket->socket, a_esocket->buf_in, a_esocket->buf_in_size_max);
+    ssize_t l_read = dap_recvfrom(a_esocket->socket, a_esocket->buf_in, a_esocket->buf_in_size_max);
+    int l_errno = WSAGetLastError();
     if (l_read == SOCKET_ERROR) {
-        log_it(L_ERROR, "Queue socket %zu received invalid data, error %d", a_esocket->socket, WSAGetLastError());
+        log_it(L_ERROR, "Queue socket %zu received invalid data, error %d", a_esocket->socket, l_errno);
         return -1;
     }
 #endif
@@ -638,6 +640,7 @@ int dap_events_socket_queue_proc_input_unsafe(dap_events_socket_t * a_esocket)
             #endif
             a_esocket->callbacks.queue_ptr_callback (a_esocket, l_queue_ptr);
 #elif defined DAP_EVENTS_CAPS_MSMQ
+            /*
             DWORD l_mp_id = 0;
             MQMSGPROPS    l_mps;
             MQPROPVARIANT l_mpvar[2];
@@ -675,6 +678,16 @@ int dap_events_socket_queue_proc_input_unsafe(dap_events_socket_t * a_esocket)
                     }
                 }
             }
+            */
+            if(l_read > 0) {
+                debug_if(g_debug_reactor, L_NOTICE, "Got %ld bytes from socket", l_read);
+                for (long shift = 0; shift < l_read; shift += sizeof(void*)) {
+                    l_queue_ptr = *(void **)(a_esocket->buf_in + shift);
+                    a_esocket->callbacks.queue_ptr_callback(a_esocket, l_queue_ptr);
+                }
+            }
+            else if ((l_errno != EAGAIN) && (l_errno != EWOULDBLOCK))  // we use blocked socket for now but who knows...
+                log_it(L_ERROR, "Can't read message from socket");
 #elif defined DAP_EVENTS_CAPS_KQUEUE
         l_queue_ptr = (void*) a_esocket->kqueue_event_catched_data.data;
         if(g_debug_reactor)
@@ -757,14 +770,13 @@ void dap_events_socket_event_proc_input_unsafe(dap_events_socket_t *a_esocket)
 #elif defined DAP_OS_WINDOWS
         u_short l_value;
         int l_ret;
-        switch (l_ret = dap_recvfrom(a_esocket->socket, a_esocket->buf_in, a_esocket->buf_in_size)) {
+        switch (l_ret = dap_recvfrom(a_esocket->socket, &l_value, sizeof(char))) {
         case SOCKET_ERROR:
             log_it(L_CRITICAL, "Can't read from event socket, error: %d", WSAGetLastError());
             break;
         case 0:
             return;
         default:
-            l_value = a_esocket->buf_out[0];
             a_esocket->callbacks.event_callback(a_esocket, l_value);
             return;
         }
@@ -1041,8 +1053,8 @@ int dap_events_socket_queue_ptr_send( dap_events_socket_t *a_es, void *a_arg)
         return l_errno;
 #elif defined DAP_EVENTS_CAPS_MSMQ
 
-    char *pbuf = (char *)&a_arg;
-
+    /* TODO: Windows-way message waiting and handling
+     *
     DWORD l_mp_id = 0;
     MQMSGPROPS    l_mps;
     MQPROPVARIANT l_mpvar[1];
@@ -1051,7 +1063,7 @@ int dap_events_socket_queue_ptr_send( dap_events_socket_t *a_es, void *a_arg)
 
     l_p_id[l_mp_id] = PROPID_M_BODY;
     l_mpvar[l_mp_id].vt = VT_VECTOR | VT_UI1;
-    l_mpvar[l_mp_id].caub.pElems = (unsigned char*)(pbuf);
+    l_mpvar[l_mp_id].caub.pElems = (unsigned char*)(&a_arg);
     l_mpvar[l_mp_id].caub.cElems = sizeof(void*);
     l_mp_id++;
 
@@ -1065,12 +1077,8 @@ int dap_events_socket_queue_ptr_send( dap_events_socket_t *a_es, void *a_arg)
         log_it(L_ERROR, "An error occured on sending message to queue, errno: %ld", hr);
         return hr;
     }
-
-    if(dap_sendto(a_es->socket, a_es->port, NULL, 0) == SOCKET_ERROR) {
-        return WSAGetLastError();
-    } else {
-        return 0;
-    }
+    */
+    return dap_sendto(a_es->socket, a_es->port, &a_arg, sizeof(void*)) == SOCKET_ERROR ? WSAGetLastError() : NO_ERROR;
 #elif defined (DAP_EVENTS_CAPS_KQUEUE)
     struct kevent l_event={0};
     dap_events_socket_w_data_t * l_es_w_data = DAP_NEW_Z(dap_events_socket_w_data_t);
@@ -1159,12 +1167,7 @@ int dap_events_socket_event_signal( dap_events_socket_t * a_es, uint64_t a_value
         else
             return 1;
 #elif defined (DAP_OS_WINDOWS)
-    a_es->buf_out[0] = (u_short)a_value;
-    if(dap_sendto(a_es->socket, a_es->port, a_es->buf_out, sizeof(uint64_t)) == SOCKET_ERROR) {
-        return WSAGetLastError();
-    } else {
-        return 0;
-    }
+    return dap_sendto(a_es->socket, a_es->port, NULL, 0) == SOCKET_ERROR ? WSAGetLastError() : NO_ERROR;
 #elif defined (DAP_EVENTS_CAPS_KQUEUE)
     struct kevent l_event={0};
     dap_events_socket_w_data_t * l_es_w_data = DAP_NEW_Z(dap_events_socket_w_data_t);
diff --git a/dap-sdk/io/dap_proc_thread.c b/dap-sdk/io/dap_proc_thread.c
index a5b13b97924ba090748c57feda5f9c1f7243c0c5..49d9243e569995daeb72fe391cd5a4dc054ba84d 100644
--- a/dap-sdk/io/dap_proc_thread.c
+++ b/dap-sdk/io/dap_proc_thread.c
@@ -23,10 +23,10 @@
 #include <errno.h>
 #include <stdatomic.h>
 
+#include "dap_events_socket.h"
 #include "dap_config.h"
 #include "dap_list.h"
 #include "dap_events.h"
-#include "dap_events_socket.h"
 #include "dap_proc_thread.h"
 #include "dap_server.h"
 
diff --git a/dap-sdk/io/dap_timerfd.c b/dap-sdk/io/dap_timerfd.c
index d72233f2a700d3c7eca1d17c6857ffa2543f11cb..97300aca322f28790612cc76d874aa7757365bf4 100644
--- a/dap-sdk/io/dap_timerfd.c
+++ b/dap-sdk/io/dap_timerfd.c
@@ -76,15 +76,6 @@ dap_timerfd_t* dap_timerfd_start(uint64_t a_timeout_ms, dap_timerfd_callback_t a
 }
 
 #ifdef DAP_OS_WINDOWS
-void __stdcall TimerAPCb(void* arg, DWORD low, DWORD high) {  // Timer high value.
-    UNREFERENCED_PARAMETER(low)
-    UNREFERENCED_PARAMETER(high)
-    dap_timerfd_t *l_timerfd = (dap_timerfd_t *)arg;
-    if (dap_sendto(l_timerfd->tfd, l_timerfd->port, NULL, 0) == SOCKET_ERROR) {
-        log_it(L_CRITICAL, "Error occured on writing into socket from APC, errno: %d", WSAGetLastError());
-    }
-}
-
 void __stdcall TimerRoutine(void* arg, BOOLEAN flag) {
     UNREFERENCED_PARAMETER(flag)
     dap_timerfd_t *l_timerfd = (dap_timerfd_t *)arg;
@@ -199,27 +190,26 @@ dap_timerfd_t* dap_timerfd_create(uint64_t a_timeout_ms, dap_timerfd_callback_t
 #elif defined (DAP_OS_WINDOWS)
     l_timerfd->th = NULL;
     SOCKET l_tfd = socket(AF_INET, SOCK_DGRAM, 0);
-    int buffsize = 1024;
 
+    if (l_tfd == INVALID_SOCKET) {
+        log_it(L_ERROR, "Error creating socket for type 'timer': %d", WSAGetLastError());
+        DAP_DELETE(l_timerfd);
+        DAP_DELETE(l_events_socket);
+        return NULL;
+    }
+    int buffsize = 4096;
     setsockopt(l_tfd, SOL_SOCKET, SO_RCVBUF, (char *)&buffsize, sizeof(int));
 
     unsigned long l_mode = 1;
     ioctlsocket(l_tfd, FIONBIO, &l_mode);
 
-    int l_addr_len;
-    struct sockaddr_in l_addr;
-    l_addr.sin_family = AF_INET;
-    IN_ADDR _in_addr = { { .S_addr = htonl(INADDR_LOOPBACK) } };
-    l_addr.sin_addr = _in_addr;
-    l_addr.sin_port = l_tfd + 32768;
-    l_addr_len = sizeof(struct sockaddr_in);
+    struct sockaddr_in l_addr = { .sin_family = AF_INET, .sin_port = l_tfd + 32768, .sin_addr = {{ .S_addr = htonl(INADDR_LOOPBACK) }} };;
     if (bind(l_tfd, (struct sockaddr*)&l_addr, sizeof(l_addr)) < 0) {
         log_it(L_ERROR, "Bind error: %d", WSAGetLastError());
     } else {
         int dummy = 100;
         getsockname(l_tfd, (struct sockaddr*)&l_addr, &dummy);
         l_timerfd->port = l_addr.sin_port;
-        //log_it(L_DEBUG, "Bound to port %d", l_addr.sin_port);
     }
 
     if (!CreateTimerQueueTimer(&l_timerfd->th, hTimerQueue,
diff --git a/dap-sdk/io/dap_worker.c b/dap-sdk/io/dap_worker.c
index f3a116e183570aaba53cd0a355049ff3287e3824..d67711a2c2d86642b275f46d01b8c91250cf3aea 100644
--- a/dap-sdk/io/dap_worker.c
+++ b/dap-sdk/io/dap_worker.c
@@ -24,8 +24,6 @@
 #include <errno.h>
 #include <unistd.h>
 
-#include "dap_common.h"
-#include "dap_config.h"
 #include "dap_context.h"
 #include "dap_math_ops.h"
 #include "dap_worker.h"
@@ -33,6 +31,8 @@
 #include "dap_events.h"
 #include "dap_enc_base64.h"
 #include "dap_proc_queue.h"
+#include "dap_common.h"
+#include "dap_config.h"
 
 #ifndef DAP_NET_CLIENT_NO_SSL
 #include <wolfssl/options.h>
diff --git a/dap-sdk/io/include/dap_context.h b/dap-sdk/io/include/dap_context.h
index 8acb573d20fd39137baf6519c034846e058f0eae..92cadc83f7a380105aaddff72960130b687761e5 100644
--- a/dap-sdk/io/include/dap_context.h
+++ b/dap-sdk/io/include/dap_context.h
@@ -24,9 +24,9 @@
 
 #include <pthread.h>
 #include <uthash.h>
-#include "dap_common.h"
 #include "dap_events_socket.h"
 #include "dap_proc_queue.h"
+#include "dap_common.h"
 
 typedef struct dap_worker dap_worker_t;
 typedef struct dap_proc_thread dap_proc_thread_t;
diff --git a/dap-sdk/io/include/dap_events_socket.h b/dap-sdk/io/include/dap_events_socket.h
index bac00179684371d24d4d4b5599d527085a1e51b0..1d444e7a59123693fd0fb08bbdf3d60c42d00691 100644
--- a/dap-sdk/io/include/dap_events_socket.h
+++ b/dap-sdk/io/include/dap_events_socket.h
@@ -387,33 +387,19 @@ size_t  dap_events_socket_insert_buf_out(dap_events_socket_t * a_es, void *a_dat
 DAP_STATIC_INLINE int dap_recvfrom(SOCKET s, void* buf_in, size_t buf_size) {
     struct sockaddr_in l_dummy;
     socklen_t l_size = sizeof(l_dummy);
-    int ret;
-    if (buf_in) {
-        memset(buf_in, 0, buf_size);
-        ret = recvfrom(s, (char*)buf_in, (long)buf_size, 0, (struct sockaddr *)&l_dummy, &l_size);
-    } else {
-        char l_tempbuf[sizeof(void*)];
-        ret = recvfrom(s, l_tempbuf, sizeof(l_tempbuf), 0, (struct sockaddr *)&l_dummy, &l_size);
-    }
-    return ret;
+    char l_signal;
+    return recvfrom(s, buf_in && buf_size ? (char*)buf_in : &l_signal,
+                    buf_in && buf_size ? buf_size : sizeof(char),
+                    0, (struct sockaddr*)&l_dummy, &l_size);
+
 }
 
 DAP_STATIC_INLINE int dap_sendto(SOCKET s, u_short port, void* buf_out, size_t buf_out_size) {
-    int l_addr_len;
-    struct sockaddr_in l_addr;
-    l_addr.sin_family = AF_INET;
-    IN_ADDR _in_addr = { { .S_addr = htonl(INADDR_LOOPBACK) } };
-    l_addr.sin_addr = _in_addr;
-    l_addr.sin_port = port;
-    l_addr_len = sizeof(struct sockaddr_in);
-    int ret;
-    if (buf_out) {
-        ret = sendto(s, (char*)buf_out, (long)buf_out_size, MSG_DONTWAIT | MSG_NOSIGNAL, (struct sockaddr *)&l_addr, l_addr_len);
-    } else {
-        char l_bytes[sizeof(void*)] = { 0 };
-        ret = sendto(s, l_bytes, sizeof(l_bytes), MSG_DONTWAIT | MSG_NOSIGNAL, (struct sockaddr *)&l_addr, l_addr_len);
-    }
-    return ret;
+    struct sockaddr_in l_addr = { .sin_family = AF_INET, .sin_port = port, .sin_addr = {{ .S_addr = htonl(INADDR_LOOPBACK) }} };
+    return sendto(s, buf_out && buf_out_size ? (char*)buf_out : "\0",
+                  buf_out && buf_out_size ? buf_out_size : sizeof(char),
+                  MSG_DONTWAIT | MSG_NOSIGNAL, (struct sockaddr *)&l_addr, sizeof(struct sockaddr_in));
+
 }
 #endif
 
diff --git a/dap-sdk/net/app-cli/dap_app_cli_net.c b/dap-sdk/net/app-cli/dap_app_cli_net.c
index a1f37d22c4bbc3849b97a9234825688b15dbf659..d1718e18707e1515b61aefa2ad737ddcb50651de 100644
--- a/dap-sdk/net/app-cli/dap_app_cli_net.c
+++ b/dap-sdk/net/app-cli/dap_app_cli_net.c
@@ -157,11 +157,9 @@ dap_app_cli_connect_param_t* dap_app_cli_connect(const char *a_socket_path)
     // connect
     int l_addr_len;
 #ifdef WIN32
-    struct sockaddr_in l_remote_addr;
-    l_remote_addr.sin_family = AF_INET;
-    IN_ADDR _in_addr = { { .S_addr = htonl(INADDR_LOOPBACK) } };
-    l_remote_addr.sin_addr = _in_addr;
-    l_remote_addr.sin_port = l_cli_port;
+    struct sockaddr_in l_remote_addr = {
+        .sin_family = AF_INET, .sin_port = l_cli_port, .sin_addr = {{ .S_addr = htonl(INADDR_LOOPBACK) }}
+    };
     l_addr_len = sizeof(struct sockaddr_in);
 #else
     struct sockaddr_un l_remote_addr;
diff --git a/dap-sdk/net/server/cli_server/dap_cli_server.c b/dap-sdk/net/server/cli_server/dap_cli_server.c
index daa4002500a8f4a6e7fd4c06887b60380e12fbb5..b1f5b3c5f8d50502cbd817be55b5b7ff8929a5d8 100644
--- a/dap-sdk/net/server/cli_server/dap_cli_server.c
+++ b/dap-sdk/net/server/cli_server/dap_cli_server.c
@@ -479,8 +479,7 @@ int dap_cli_server_init(bool a_debug_more,const char * a_socket_path_or_address,
 
         server_addr.sin_family = AF_INET;
 #ifdef _WIN32
-        struct in_addr _in_addr = { { .S_addr = htonl(INADDR_LOOPBACK) } };
-        server_addr.sin_addr = _in_addr;
+        server_addr.sin_addr = (struct in_addr){{ .S_addr = htonl(INADDR_LOOPBACK) }};
         server_addr.sin_port = l_listen_port;
 #else
         inet_pton( AF_INET, l_listen_addr_str, &server_addr.sin_addr );
diff --git a/dap-sdk/net/server/http_server/http_client/dap_http_client.c b/dap-sdk/net/server/http_server/http_client/dap_http_client.c
index 60cc038a3385f6e382b80bbe85b6cd687843ac8b..6fecc7f089bfc2bad9e807eabb33b1dd6bdde2dd 100644
--- a/dap-sdk/net/server/http_server/http_client/dap_http_client.c
+++ b/dap-sdk/net/server/http_server/http_client/dap_http_client.c
@@ -95,6 +95,7 @@ void dap_http_client_new( dap_events_socket_t *a_esocket, void *a_arg )
     l_http_client->http = DAP_HTTP( a_esocket->server );
     l_http_client->state_read = DAP_HTTP_CLIENT_STATE_START;
     l_http_client->state_write = DAP_HTTP_CLIENT_STATE_NONE;
+    l_http_client->socket_num = a_esocket->socket;
 
     return;
 }
@@ -623,7 +624,7 @@ void dap_http_client_out_header_generate(dap_http_client_t *a_http_client)
 
     if ( a_http_client->reply_status_code == 200 ) {
         if (s_debug_http)
-            log_it(L_DEBUG, "Out headers generate for sock %"DAP_FORMAT_SOCKET, a_http_client->esocket->socket);
+            log_it(L_DEBUG, "Out headers generate for sock %"DAP_FORMAT_SOCKET, a_http_client->socket_num);
         if ( a_http_client->out_last_modified ) {
             dap_time_to_str_rfc822( buf, sizeof(buf), a_http_client->out_last_modified );
             dap_http_header_add( &a_http_client->out_headers, "Last-Modified", buf );
@@ -639,7 +640,7 @@ void dap_http_client_out_header_generate(dap_http_client_t *a_http_client)
         }
     }else
         if (s_debug_http)
-            log_it(L_WARNING, "Out headers: nothing generate for sock %"DAP_FORMAT_SOCKET", http code %d", a_http_client->esocket->socket,
+            log_it(L_WARNING, "Out headers: nothing generate for sock %"DAP_FORMAT_SOCKET", http code %d", a_http_client->socket_num,
                    a_http_client->reply_status_code);
 
     if ( a_http_client->out_connection_close || !a_http_client->keep_alive )
diff --git a/dap-sdk/net/server/http_server/http_client/include/dap_http_client.h b/dap-sdk/net/server/http_server/http_client/include/dap_http_client.h
index e948a852b2f09595d439e73ad11313c08f27dac5..5f35aaa688b07ce6d0ac3b8137839b351fe578ce 100644
--- a/dap-sdk/net/server/http_server/http_client/include/dap_http_client.h
+++ b/dap-sdk/net/server/http_server/http_client/include/dap_http_client.h
@@ -69,6 +69,7 @@ typedef struct dap_http_client
     size_t out_cache_position;
 
     dap_events_socket_t *esocket;
+    SOCKET socket_num;
     struct dap_http * http;
 
     uint16_t reply_status_code;
diff --git a/dap-sdk/net/stream/ch/dap_stream_ch.c b/dap-sdk/net/stream/ch/dap_stream_ch.c
index b4f3b4a970889f6465f62370f793ae6d263d61a1..db3ec2d18648910860056c116a6ceab9e7322c69 100644
--- a/dap-sdk/net/stream/ch/dap_stream_ch.c
+++ b/dap-sdk/net/stream/ch/dap_stream_ch.c
@@ -142,51 +142,26 @@ void dap_stream_ch_delete(dap_stream_ch_t *a_ch)
     DAP_DELETE(a_ch);
 }
 
-/**
- * @brief dap_stream_ch_find_by_uuid_unsafe
- * @param a_worker
- * @param a_ch_uuid
- * @return
- */
-dap_stream_ch_t * dap_stream_ch_find_by_uuid_unsafe(dap_stream_worker_t * a_worker, dap_stream_ch_uuid_t a_ch_uuid)
-{
-    dap_stream_ch_t *l_ch = NULL;
-
-    if( a_worker == NULL ){
-        log_it(L_WARNING,"Attempt to search for uuid 0x%016"DAP_UINT64_FORMAT_U" in NULL worker", a_ch_uuid);
-        return NULL;
-    }
-
-
-    pthread_rwlock_rdlock(&a_worker->channels_rwlock);
-    if ( a_worker->channels)
-        HASH_FIND(hh_worker,a_worker->channels ,&a_ch_uuid, sizeof(a_ch_uuid), l_ch );
-    pthread_rwlock_unlock(&a_worker->channels_rwlock);
-    return l_ch;
-
-}
-
 /**
  * @brief Check ch uuid for presense in stream worker
  * @param a_worker
  * @param a_ch_uuid
  * @return
  */
-bool dap_stream_ch_check_uuid(dap_stream_worker_t * a_worker, dap_stream_ch_uuid_t a_ch_uuid)
+dap_stream_ch_t *dap_stream_ch_find_by_uuid_unsafe(dap_stream_worker_t * a_worker, dap_stream_ch_uuid_t a_uuid)
 {
     dap_stream_ch_t *l_ch = NULL;
     if( a_worker == NULL ){
-        log_it(L_WARNING,"Attempt to search for uuid 0x%016"DAP_UINT64_FORMAT_U" in NULL worker", a_ch_uuid);
-        return false;
+        log_it(L_WARNING,"Attempt to search for uuid 0x%016"DAP_UINT64_FORMAT_U" in NULL worker", a_uuid);
+        return NULL;
     }
 
     pthread_rwlock_rdlock(&a_worker->channels_rwlock);
     if ( a_worker->channels)
-        HASH_FIND(hh_worker,a_worker->channels ,&a_ch_uuid, sizeof(a_ch_uuid), l_ch );
+        HASH_FIND(hh_worker,a_worker->channels, &a_uuid, sizeof(a_uuid), l_ch);
     pthread_rwlock_unlock(&a_worker->channels_rwlock);
 
     return l_ch;
-
 }
 
 
diff --git a/dap-sdk/net/stream/ch/include/dap_stream_ch.h b/dap-sdk/net/stream/ch/include/dap_stream_ch.h
index 5ca3630ce7c96046722fbf49144c011293b1f232..837076ab0298378f2bc2c5abde919a83ad0f7800 100644
--- a/dap-sdk/net/stream/ch/include/dap_stream_ch.h
+++ b/dap-sdk/net/stream/ch/include/dap_stream_ch.h
@@ -64,9 +64,12 @@ void dap_stream_ch_set_ready_to_read_unsafe(dap_stream_ch_t * a_ch,bool a_is_rea
 void dap_stream_ch_set_ready_to_write_unsafe(dap_stream_ch_t * a_ch,bool a_is_ready);
 void dap_stream_ch_delete(dap_stream_ch_t *a_ch);
 
-dap_stream_ch_t * dap_stream_ch_find_by_uuid_unsafe(dap_stream_worker_t * a_worker, dap_stream_ch_uuid_t a_uuid);
+dap_stream_ch_t *dap_stream_ch_find_by_uuid_unsafe(dap_stream_worker_t *a_worker, dap_stream_ch_uuid_t a_uuid);
 
 // MT-safe functions
-bool dap_stream_ch_check_uuid(dap_stream_worker_t * a_worker, dap_stream_ch_uuid_t a_ch_uuid);
+DAP_STATIC_INLINE bool dap_stream_ch_check_uuid(dap_stream_worker_t *a_worker, dap_stream_ch_uuid_t a_ch_uuid)
+{
+    return dap_stream_ch_find_by_uuid_unsafe(a_worker, a_ch_uuid);
+}
 
 #endif
diff --git a/modules/chain/CMakeLists.txt b/modules/chain/CMakeLists.txt
index 0ab8bba61d611fd64bef75dd5442d264b77d6408..e3fc6f7f2c7e18c8d543ade7fc944d5f07839067 100644
--- a/modules/chain/CMakeLists.txt
+++ b/modules/chain/CMakeLists.txt
@@ -14,7 +14,7 @@ endif()
 #find_package(PkgConfig REQUIRED)
 #pkg_search_module(GLIB REQUIRED glib-2.0)
 
-target_link_libraries(${PROJECT_NAME} dap_chain_net_srv dap_chain_net_srv_xchange dap_chain_net_srv_stake_pos_delegate dap_chain_net_srv_stake_lock ${GLIB_LDFLAGS})
+target_link_libraries(${PROJECT_NAME} dap_chain_common dap_chain_global_db ${GLIB_LDFLAGS})
 target_include_directories(${PROJECT_NAME} INTERFACE . include/ ${GLIB_INCLUDE_DIRS})
 target_include_directories(${PROJECT_NAME} PUBLIC include)
 target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/uthash/src)
diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c
index 7a15202bdf797092024af67069b0096cb3283bb4..f971680a3c1cc90c8fa290423c185bb3333cd703 100644
--- a/modules/chain/dap_chain.c
+++ b/modules/chain/dap_chain.c
@@ -27,7 +27,6 @@
 #include <stdc-predef.h>
 #endif
 #include <unistd.h>
-#include "dap_chain_net_srv.h"
 #include "dap_chain_common.h"
 #include "dap_chain_datum.h"
 #include "dap_chain_datum_decree.h"
@@ -42,7 +41,6 @@
 #include "dap_chain_ledger.h"
 #include "dap_chain_cs.h"
 #include "dap_cert_file.h"
-#include "dap_chain_vf.h"
 #include <uthash.h>
 #include <pthread.h>
 
@@ -75,7 +73,6 @@ int dap_chain_init(void)
     dap_chain_cell_init();
     dap_chain_ledger_init();
     dap_chain_cs_init();
-    dap_chain_vf_init();
     //dap_chain_show_hash_blocks_file(g_gold_hash_blocks_file);
     //dap_chain_show_hash_blocks_file(g_silver_hash_blocks_file);
     return 0;
diff --git a/modules/chain/dap_chain_cell.c b/modules/chain/dap_chain_cell.c
index 74a65ce7a6e01731ee471a6947135d4d55f2dd90..ff45cc9fb8a67728b5cae4ce22ad9ebf5634e10f 100644
--- a/modules/chain/dap_chain_cell.c
+++ b/modules/chain/dap_chain_cell.c
@@ -30,6 +30,7 @@
 #include "dap_common.h"
 #include "dap_config.h"
 #include "dap_strfuncs.h"
+#include "dap_file_utils.h"
 
 #define LOG_TAG "dap_chain_cell"
 
@@ -188,6 +189,11 @@ int dap_chain_cell_load(dap_chain_t * a_chain, const char * a_cell_file_path)
         fclose(l_f);
         return -3;
     }
+    if (l_hdr.version < DAP_CHAIN_CELL_FILE_VERSION ){
+        log_it(L_ERROR, "Too low chain version, backup files");
+        fclose(l_f);
+        return -3;
+    }
     size_t l_el_size = 0;
     unsigned long q = 0;
     volatile int l_dummy;
diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c
index eb138da2b6feb5c4d1aad8bb7f486084e9ffc8b5..737ce807c5b089a8abbd49faf4bcb7a8262f767e 100644
--- a/modules/chain/dap_chain_ledger.c
+++ b/modules/chain/dap_chain_ledger.c
@@ -63,11 +63,8 @@
 #include "json-c/json.h"
 #include "json-c/json_object.h"
 #include "dap_notify_srv.h"
+#include "dap_chain_net_tx.h"
 #include "dap_chain_net_srv.h"
-#include "dap_chain_net_srv_xchange.h"
-#include "dap_chain_net_srv_stake_lock.h"
-#include "dap_chain_net_srv_stake_pos_delegate.h"
-
 
 #define LOG_TAG "dap_chain_ledger"
 
@@ -83,15 +80,12 @@ static  pthread_rwlock_t s_verificators_rwlock;
 
 #define MAX_OUT_ITEMS   10
 
-typedef struct dap_chain_ledger_token_emission_for_stake_lock_item {
-    dap_chain_hash_fast_t	datum_token_emission_for_stake_lock_hash;
+typedef struct dap_chain_ledger_stake_lock_item {
+    dap_chain_hash_fast_t	tx_for_stake_lock_hash;
     dap_chain_hash_fast_t	tx_used_out;
 //	const char 				datum_token_emission_hash[DAP_CHAIN_HASH_FAST_STR_SIZE];
     UT_hash_handle hh;
-} dap_chain_ledger_token_emission_for_stake_lock_item_t;
-
-static dap_chain_ledger_token_emission_for_stake_lock_item_t	*s_emission_for_stake_lock;
-static  pthread_rwlock_t 										s_emission_for_stake_lock_rwlock;
+} dap_chain_ledger_stake_lock_item_t;
 
 typedef struct dap_chain_ledger_token_emission_item {
     dap_chain_hash_fast_t datum_token_emission_hash;
@@ -101,6 +95,14 @@ typedef struct dap_chain_ledger_token_emission_item {
     UT_hash_handle hh;
 } dap_chain_ledger_token_emission_item_t;
 
+typedef struct dap_chain_ledger_token_update_item {
+    dap_hash_fast_t			update_token_hash;
+    dap_chain_datum_token_t	*datum_token_update;
+    size_t					datum_token_update_size;
+    time_t					updated_time;
+    UT_hash_handle hh;
+} dap_chain_ledger_token_update_item_t;
+
 typedef struct dap_chain_ledger_token_item {
     char ticker[DAP_CHAIN_TICKER_SIZE_MAX];
     uint16_t type;
@@ -113,6 +115,10 @@ typedef struct dap_chain_ledger_token_item {
     pthread_rwlock_t token_emissions_rwlock;
     dap_chain_ledger_token_emission_item_t * token_emissions;
 
+    pthread_rwlock_t token_ts_updated_rwlock;
+    dap_chain_ledger_token_update_item_t * token_ts_updated;
+    time_t last_update_token_time;
+
     // for auth operations
     dap_sign_t ** auth_signs;
     dap_chain_hash_fast_t * auth_signs_pkey_hash;
@@ -136,19 +142,26 @@ typedef struct dap_chain_ledger_tx_item {
     dap_chain_datum_tx_t *tx;
     struct {
         dap_time_t ts_created;
-        int n_outs;
-        int n_outs_used;
+        uint32_t n_outs;
+        uint32_t n_outs_used;
         char token_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
+        char padding[6];
+        byte_t multichannel;
+        char pad[15];
         // TODO dynamically allocates the memory in order not to limit the number of outputs in transaction
         dap_chain_hash_fast_t tx_hash_spent_fast[MAX_OUT_ITEMS]; // spent outs list
-    } cache_data;
+    } DAP_ALIGN_PACKED cache_data;
     UT_hash_handle hh;
 } dap_chain_ledger_tx_item_t;
 
 typedef struct dap_chain_ledger_tx_spent_item {
     dap_chain_hash_fast_t tx_hash_fast;
-    dap_time_t spent_time;
-    char token_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
+    struct {
+        dap_time_t spent_time;
+        char token_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
+        char padding[22];
+        dap_chain_hash_fast_t tx_hash_spent_fast; // spent outs list
+    } DAP_ALIGN_PACKED cache_data;
     UT_hash_handle hh;
 } dap_chain_ledger_tx_spent_item_t;
 
@@ -159,7 +172,7 @@ typedef struct dap_chain_ledger_tokenizer {
 } dap_chain_ledger_tokenizer_t;
 
 typedef struct dap_chain_ledger_tx_bound {
-    dap_chain_hash_fast_t tx_prev_hash_fast;
+    dap_chain_hash_fast_t tx_prev_hash;
     dap_chain_datum_tx_t *tx_prev;
     union {
         dap_chain_tx_in_t *tx_cur_in;
@@ -175,6 +188,7 @@ typedef struct dap_chain_ledger_tx_bound {
     union {
         dap_chain_ledger_tx_item_t *item_out;
         dap_chain_ledger_token_emission_item_t *item_emission;
+        dap_chain_ledger_stake_lock_item_t *stake_lock_item;
     };
 } dap_chain_ledger_tx_bound_t;
 
@@ -205,16 +219,15 @@ typedef struct dap_ledger_private {
 
     dap_chain_ledger_tx_item_t *ledger_items;
     dap_chain_ledger_tx_spent_item_t *spent_items;
-
     dap_chain_ledger_token_item_t *tokens;
-
+    dap_chain_ledger_stake_lock_item_t *emissions_for_stake_lock;
     dap_ledger_wallet_balance_t *balance_accounts;
 
     // for separate access to ledger
     pthread_rwlock_t ledger_rwlock;
     // for separate access to tokens
     pthread_rwlock_t tokens_rwlock;
-
+    pthread_rwlock_t stake_lock_rwlock;
     pthread_rwlock_t threshold_txs_rwlock;
     pthread_rwlock_t threshold_emissions_rwlock;
     pthread_rwlock_t balance_accounts_rwlock;
@@ -230,6 +243,7 @@ typedef struct dap_ledger_private {
     dap_chain_cell_id_t local_cell_id;
 
     bool load_mode;
+    bool cached;
     // TPS section
     dap_timerfd_t *tps_timer;
     struct timespec tps_start_time;
@@ -247,6 +261,7 @@ static void s_threshold_txs_proc( dap_ledger_t * a_ledger);
 static int 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 int s_ledger_permissions_check(dap_chain_ledger_token_item_t *  a_token_item, uint16_t a_permission_id, const void * a_data,size_t a_data_size );
 static bool s_ledger_tps_callback(void *a_arg);
+static int s_sort_ledger_tx_item(dap_chain_ledger_tx_item_t* a, dap_chain_ledger_tx_item_t* b);
 
 static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash, bool a_from_threshold, bool a_safe_call);
 static int s_tx_add_unsafe(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash, bool a_from_threshold);
@@ -256,14 +271,11 @@ static int s_token_emission_add_unsafe(dap_ledger_t *a_ledger, byte_t *a_token_e
 static inline int s_token_emission_add(dap_ledger_t *a_ledger, byte_t *a_token_emission, size_t a_token_emission_size,
                                         dap_hash_fast_t *a_emission_hash, bool a_from_threshold, bool a_safe_call);
 
-
-
 static size_t s_threshold_emissions_max = 1000;
 static size_t s_threshold_txs_max = 10000;
 static bool s_debug_more = false;
 
 struct json_object *wallet_info_json_collect(dap_ledger_t *a_ledger, dap_ledger_wallet_balance_t* a_bal);
-static void wallet_info_notify();
 
 /**
  * @brief dap_chain_ledger_init
@@ -273,20 +285,8 @@ static void wallet_info_notify();
 int dap_chain_ledger_init()
 {
     s_debug_more = dap_config_get_item_bool_default(g_config,"ledger","debug_more",false);
-    return 0;
-}
-
-bool dap_chain_global_rwlocks_and_verificators_init(void)
-{
     pthread_rwlock_init(&s_verificators_rwlock, NULL);
-    pthread_rwlock_init(&s_emission_for_stake_lock_rwlock, NULL);
-    dap_chain_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY, dap_chain_net_srv_pay_verificator, NULL);
-    dap_chain_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE, dap_chain_ledger_fee_verificator, NULL);
-    dap_chain_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, dap_chain_net_srv_xchange_verificator, NULL);
-    dap_chain_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, dap_chain_net_srv_stake_pos_delegate_verificator, NULL);
-    dap_chain_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE_UPDATE, dap_chain_net_srv_stake_updater, NULL);
-    dap_chain_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK, s_callback_verificator, s_callback_verificator_added);
-    return true;
+    return 0;
 }
 
 /**
@@ -301,6 +301,7 @@ void dap_chain_ledger_deinit()
         dap_chain_ledger_purge(l_net_list[i]->pub.ledger, true);
     }
     DAP_DELETE(l_net_list);
+    pthread_rwlock_destroy(&s_verificators_rwlock);
 }
 
 /**
@@ -320,6 +321,7 @@ static dap_ledger_t * dap_chain_ledger_handle_new(void)
     pthread_rwlock_init(&l_ledger_pvt->threshold_txs_rwlock , NULL);
     pthread_rwlock_init(&l_ledger_pvt->threshold_emissions_rwlock , NULL);
     pthread_rwlock_init(&l_ledger_pvt->balance_accounts_rwlock , NULL);
+    pthread_rwlock_init(&l_ledger_pvt->stake_lock_rwlock, NULL);
     return l_ledger;
 }
 
@@ -336,9 +338,10 @@ void dap_chain_ledger_handle_free(dap_ledger_t *a_ledger)
     // Destroy Read/Write Lock
     pthread_rwlock_destroy(&PVT(a_ledger)->ledger_rwlock);
     pthread_rwlock_destroy(&PVT(a_ledger)->tokens_rwlock);
-    pthread_rwlock_destroy(&PVT(a_ledger)->threshold_txs_rwlock );
-    pthread_rwlock_destroy(&PVT(a_ledger)->threshold_emissions_rwlock );
-    pthread_rwlock_destroy(&PVT(a_ledger)->balance_accounts_rwlock );
+    pthread_rwlock_destroy(&PVT(a_ledger)->threshold_txs_rwlock);
+    pthread_rwlock_destroy(&PVT(a_ledger)->threshold_emissions_rwlock);
+    pthread_rwlock_destroy(&PVT(a_ledger)->balance_accounts_rwlock);
+    pthread_rwlock_destroy(&PVT(a_ledger)->stake_lock_rwlock);
     DAP_DELETE(PVT(a_ledger));
     DAP_DELETE(a_ledger);
 
@@ -377,6 +380,81 @@ struct json_object *wallet_info_json_collect(dap_ledger_t *a_ledger, dap_ledger_
     return l_json;
 }
 
+/**
+ * @brief s_chain_ledger_token_update_check
+ * @param a_cur_token_item
+ * @param a_token_update
+ * @param a_token_update_size
+ * @return true or false
+ */
+static bool s_ledger_token_update_check(dap_chain_ledger_token_item_t *a_cur_token_item, dap_chain_datum_token_t *a_token_update, size_t a_token_update_size)
+{
+    dap_sign_t								**l_signs_upd_token;
+    size_t									auth_signs_total = 0;
+    size_t									auth_signs_valid = 0;
+    dap_chain_ledger_token_update_item_t	*l_token_update_item;
+    dap_hash_fast_t							l_hash_token_update;
+
+    dap_hash_fast(a_token_update, a_token_update_size, &l_hash_token_update);
+    pthread_rwlock_rdlock(&a_cur_token_item->token_ts_updated_rwlock);
+    HASH_FIND(hh, a_cur_token_item->token_ts_updated, &l_hash_token_update, sizeof(dap_hash_fast_t),
+              l_token_update_item);
+    pthread_rwlock_unlock(&a_cur_token_item->token_ts_updated_rwlock);
+    if (l_token_update_item
+    &&	a_cur_token_item->last_update_token_time == l_token_update_item->updated_time) {
+        if (s_debug_more)
+            log_it(L_WARNING,"This upadate already applied for token with ticker '%s' ", a_token_update->ticker);
+        return false;
+    }
+
+    /*if (a_cur_token_item->auth_signs_total != a_token_update->signs_total
+    ||	a_cur_token_item->auth_signs_valid != a_token_update->signs_valid) {
+        if(s_debug_more)
+            log_it(L_WARNING,"Can't update token with ticker '%s' because: "
+                             "l_token_item auth signs total/valid == %lu/%lu | "
+                             "token_update auth signs total/valid == %hu/%hu",
+                   a_token_update->ticker,
+                   a_cur_token_item->auth_signs_total, a_cur_token_item->auth_signs_valid,
+                   a_token_update->signs_total, a_token_update->signs_valid);
+        return false;
+    }*/
+
+    l_signs_upd_token = dap_chain_datum_token_signs_parse(a_token_update, a_token_update_size,
+                                                          &auth_signs_total, &auth_signs_valid);
+    if (a_cur_token_item->auth_signs_total != auth_signs_total
+    ||	a_cur_token_item->auth_signs_valid != auth_signs_valid) {
+        DAP_DEL_Z(l_signs_upd_token);
+        if(s_debug_more)
+            log_it(L_WARNING,"Can't update token with ticker '%s' because: "
+                             "l_token_item auth signs total/valid == %lu/%lu | "
+                             "token_update auth signs total/valid == %lu/%lu",
+                   a_token_update->ticker,
+                   a_cur_token_item->auth_signs_total, a_cur_token_item->auth_signs_valid,
+                   auth_signs_total, auth_signs_valid);
+        return false;
+    }
+    if(auth_signs_total) {
+        for(uint16_t i = 0; i < auth_signs_total; i++){
+            if (!dap_sign_match_pkey_signs(a_cur_token_item->auth_signs[i], l_signs_upd_token[i])) {
+                DAP_DEL_Z(l_signs_upd_token);
+                if(s_debug_more)
+                    log_it(L_WARNING, "Can't update token with ticker '%s' because: Signs not compare", a_token_update->ticker);
+                return false;
+            }
+        }
+    }
+    DAP_DEL_Z(l_signs_upd_token);
+    if (!IS_ZERO_256(a_token_update->total_supply)){
+        if (compare256(a_token_update->total_supply, a_cur_token_item->total_supply) < 0) {//compare old 'total_supply' to updated
+            if(s_debug_more)
+                log_it(L_WARNING, "Can't update token with ticker '%s' because: the new 'total_supply' cannot be smaller than the old one", a_token_update->ticker);
+            return false;
+        }
+    }
+    return true;
+}
+
+
 /**
  * @brief dap_chain_ledger_token_check
  * @param a_ledger
@@ -392,36 +470,51 @@ int dap_chain_ledger_token_decl_add_check(dap_ledger_t *a_ledger, dap_chain_datu
         return  -1;
     }
 
+    bool update_token = false;
     dap_chain_ledger_token_item_t *l_token_item;
     pthread_rwlock_rdlock(&PVT(a_ledger)->tokens_rwlock);
     HASH_FIND_STR(PVT(a_ledger)->tokens, a_token->ticker, l_token_item);
     pthread_rwlock_unlock(&PVT(a_ledger)->tokens_rwlock);
-    if ( l_token_item != NULL ){
-        log_it(L_WARNING,"Duplicate token declaration for ticker '%s' ", a_token->ticker);
-        return -3;
+    if (a_token->type == DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE
+    ||	a_token->type == DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_UPDATE)
+        update_token = true;
+
+    if	(l_token_item != NULL) {
+        if (update_token == false) {
+            log_it(L_WARNING,"Duplicate token declaration for ticker '%s' ", a_token->ticker);
+            return -3;
+        } else if (s_ledger_token_update_check(l_token_item, a_token, a_token_size) == false) {
+            return -2;
+        }
+    }
+    else if	(l_token_item == NULL && update_token == true) {
+        log_it(L_WARNING,"Can't update token that doesn't exist for ticker '%s' ", a_token->ticker);
+        return -6;
     }
     // Check signs
-//    dap_chain_datum_token_signs_parse(a_token, a_token_size, )
     size_t l_signs_unique = 0;
     size_t l_size_tsd_section = 0;
     switch (a_token->type) {
         case DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL:
-        case DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL:
             l_size_tsd_section = a_token->header_native_decl.tsd_total_size;
             break;
+        case DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL:
+            l_size_tsd_section = a_token->header_private_decl.tsd_total_size;
+            break;
+        case DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_UPDATE:
+            l_size_tsd_section = a_token->header_native_update.tsd_total_size;
+            break;
+        case DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE:
+            l_size_tsd_section = a_token->header_private_update.tsd_total_size;
+            break;
     }
     size_t l_signs_size = a_token_size - sizeof(dap_chain_datum_token_t) - l_size_tsd_section;
     dap_sign_t **l_signs = dap_sign_get_unique_signs(a_token->data_n_tsd + l_size_tsd_section, l_signs_size, &l_signs_unique);
     if (l_signs_unique == a_token->signs_total){
         size_t l_signs_approve = 0;
-        for (size_t i=0; i < l_signs_unique; i++){
-            dap_sign_t *l_sign = l_signs[i];
-            if (dap_sign_verify_size(l_sign, l_signs_size)) {
-                if (dap_sign_verify(l_sign, a_token, sizeof(dap_chain_datum_token_t) - sizeof(uint16_t)) == 1) {
-                    l_signs_approve++;
-                }
-            }
-        }
+        for (size_t i=0; i < l_signs_unique; i++)
+            if (!dap_sign_verify_all(l_signs[i], l_signs_size, a_token, sizeof(dap_chain_datum_token_t) - sizeof(uint16_t)))
+                l_signs_approve++;
         if (l_signs_approve == a_token->signs_total){
             return 0;
         } else {
@@ -464,7 +557,7 @@ dap_chain_datum_token_t *dap_chain_ledger_token_ticker_check(dap_ledger_t * a_le
  * @param a_ledger ledger object
  * @param l_token_item token item object
  */
-void s_update_token_cache(dap_ledger_t *a_ledger, dap_chain_ledger_token_item_t *l_token_item)
+void s_ledger_token_cache_update(dap_ledger_t *a_ledger, dap_chain_ledger_token_item_t *l_token_item)
 {
     char *l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_TOKENS_STR);
     size_t l_cache_size = l_token_item->datum_token_size + sizeof(uint256_t);
@@ -479,6 +572,63 @@ void s_update_token_cache(dap_ledger_t *a_ledger, dap_chain_ledger_token_item_t
     DAP_DELETE(l_gdb_group);
 }
 
+/**
+ * @brief s_ledger_update_token_add_in_hash_table
+ * @param a_cur_token_item
+ * @param a_token_update
+ * @param a_token_update_size
+ * @return true or false
+ */
+static bool s_ledger_update_token_add_in_hash_table(dap_chain_ledger_token_item_t *a_cur_token_item, dap_chain_datum_token_t *a_token_update, size_t a_token_update_size)
+{
+    dap_chain_ledger_token_update_item_t	*l_token_update_item;
+    dap_hash_fast_t							l_hash_token_update;
+    bool									new_item = false;
+
+    dap_hash_fast(a_token_update, a_token_update_size, &l_hash_token_update);
+    pthread_rwlock_rdlock(&a_cur_token_item->token_ts_updated_rwlock);
+    HASH_FIND(hh, a_cur_token_item->token_ts_updated, &l_hash_token_update, sizeof(dap_hash_fast_t),
+              l_token_update_item);
+    pthread_rwlock_unlock(&a_cur_token_item->token_ts_updated_rwlock);
+    if (l_token_update_item
+    &&	a_cur_token_item->last_update_token_time == l_token_update_item->updated_time) {
+        if (s_debug_more)
+            log_it(L_WARNING, "Error: item 'dap_chain_ledger_token_update_item_t' already exist in hash-table");
+        return false;
+    } else if (!l_token_update_item){
+        new_item = true;
+        l_token_update_item = DAP_NEW(dap_chain_ledger_token_update_item_t);
+        if (!l_token_update_item) {
+            if (s_debug_more)
+                log_it(L_ERROR, "Error: memory allocation when try adding item 'dap_chain_ledger_token_update_item_t' to hash-table");
+            return false;
+        }
+        *l_token_update_item = (dap_chain_ledger_token_update_item_t) {
+                .update_token_hash			= l_hash_token_update,
+                .datum_token_update			= a_token_update,
+                .datum_token_update_size	= a_token_update_size
+        };
+    }
+
+    l_token_update_item->updated_time		= dap_time_now();
+
+    if (new_item) {
+        pthread_rwlock_wrlock(&a_cur_token_item->token_ts_updated_rwlock);
+        HASH_ADD(hh, a_cur_token_item->token_ts_updated, update_token_hash, sizeof(dap_chain_hash_fast_t), l_token_update_item);
+        pthread_rwlock_unlock(&a_cur_token_item->token_ts_updated_rwlock);
+    }
+
+    if (!l_token_update_item) {
+        if (s_debug_more)
+            log_it(L_ERROR, "Error: adding to hash-table. Be careful, there may be leaks");
+        return false;
+    }
+
+    a_cur_token_item->last_update_token_time = l_token_update_item->updated_time;
+
+    return true;
+}
+
 /**
  * @brief dap_chain_ledger_token_add
  * @param a_token
@@ -487,51 +637,81 @@ void s_update_token_cache(dap_ledger_t *a_ledger, dap_chain_ledger_token_item_t
  */
 int dap_chain_ledger_token_add(dap_ledger_t *a_ledger, dap_chain_datum_token_t *a_token, size_t a_token_size)
 {
-    if ( !a_ledger){
-        if(s_debug_more)
-            log_it(L_ERROR, "NULL ledger, can't add datum with token declaration!");
+    if (!a_ledger) {
+        debug_if(s_debug_more, L_ERROR, "NULL ledger, can't add datum with token declaration!");
         return  -1;
     }
+
+    bool update_token = false;
+    if (a_token->type == DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE
+    ||	a_token->type == DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_UPDATE)
+        update_token = true;
+
+
     dap_chain_ledger_token_item_t * l_token_item;
     pthread_rwlock_rdlock(&PVT(a_ledger)->tokens_rwlock);
     HASH_FIND_STR(PVT(a_ledger)->tokens, a_token->ticker,l_token_item);
     pthread_rwlock_unlock(&PVT(a_ledger)->tokens_rwlock);
 
-    if (l_token_item) {
-        if(s_debug_more)
+    if	(l_token_item != NULL) {
+        if (update_token == false) {
             log_it(L_WARNING,"Duplicate token declaration for ticker '%s' ", a_token->ticker);
-        return -3;
+            return -3;
+        } else if (s_ledger_token_update_check(l_token_item, a_token, a_token_size) == true) {
+            if (s_ledger_update_token_add_in_hash_table(l_token_item, a_token, a_token_size) == false) {
+                if (s_debug_more)
+                    log_it(L_ERROR, "Failed to add ticker '%s' to hash-table", a_token->ticker);
+                return -5;
+            }
+            if (!IS_ZERO_256(a_token->total_supply)){
+                SUBTRACT_256_256(l_token_item->total_supply, l_token_item->current_supply, &l_token_item->current_supply);
+                SUBTRACT_256_256(a_token->total_supply, l_token_item->current_supply, &l_token_item->current_supply);
+            } else {
+                l_token_item->current_supply = a_token->total_supply;
+            }
+            l_token_item->total_supply = a_token->total_supply;
+            DAP_DEL_Z(l_token_item->datum_token);
+        } else {
+            return -2;
+        }
+    }
+    else if	(l_token_item == NULL && update_token == true) {
+        log_it(L_WARNING,"Can't update token that doesn't exist for ticker '%s' ", a_token->ticker);
+        return -6;
     }
-
-    l_token_item = DAP_NEW_Z(dap_chain_ledger_token_item_t);
-    dap_snprintf(l_token_item->ticker,sizeof (l_token_item->ticker), "%s", a_token->ticker);
-    pthread_rwlock_init(&l_token_item->token_emissions_rwlock,NULL);
 
     dap_chain_datum_token_t *l_token = a_token->type == DAP_CHAIN_DATUM_TOKEN_TYPE_OLD_SIMPLE ?
-                dap_chain_datum_token_read((byte_t *)a_token, &a_token_size) : a_token;
-
-    l_token_item->datum_token_size  = a_token_size;
-    l_token_item->type              = a_token->type;
-    l_token_item->datum_token       = DAP_DUP_SIZE(a_token, a_token_size);
-    l_token_item->total_supply      = l_token->total_supply;
-    l_token_item->auth_signs_total  = l_token->signs_total;
-    l_token_item->auth_signs_valid  = l_token->signs_valid;
-
-    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);
-    if(l_token_item->auth_signs_total) {
-        l_token_item->auth_signs_pkey_hash = DAP_NEW_Z_SIZE(dap_chain_hash_fast_t, sizeof(dap_chain_hash_fast_t) * l_token_item->auth_signs_total);
-        for(uint16_t k=0; k<l_token_item->auth_signs_total;k++){
-            dap_sign_get_pkey_hash(l_token_item->auth_signs[k], &l_token_item->auth_signs_pkey_hash[k]);
+                                       dap_chain_datum_token_read((byte_t *)a_token, &a_token_size) : a_token;
+
+    if (update_token == false) {//create new token
+        l_token_item = DAP_NEW_Z(dap_chain_ledger_token_item_t);
+        dap_snprintf(l_token_item->ticker,sizeof (l_token_item->ticker), "%s", l_token->ticker);
+        pthread_rwlock_init(&l_token_item->token_emissions_rwlock,NULL);
+        pthread_rwlock_init(&l_token_item->token_ts_updated_rwlock,NULL);
+        l_token_item->type = l_token->type;
+        l_token_item->total_supply      = l_token->total_supply;
+        l_token_item->current_supply	= l_token_item->total_supply;
+        l_token_item->auth_signs_total  = l_token->signs_total;
+        l_token_item->auth_signs_valid  = l_token->signs_valid;
+        l_token_item->auth_signs		= dap_chain_datum_token_signs_parse(l_token, a_token_size,
+                                                                     &l_token_item->auth_signs_total,&l_token_item->auth_signs_valid);
+        if (l_token_item->auth_signs_total) {
+            l_token_item->auth_signs_pkey_hash = DAP_NEW_Z_SIZE(dap_chain_hash_fast_t, sizeof(dap_chain_hash_fast_t) * l_token_item->auth_signs_total);
+            for(uint16_t k=0; k<l_token_item->auth_signs_total;k++){
+                dap_sign_get_pkey_hash(l_token_item->auth_signs[k], &l_token_item->auth_signs_pkey_hash[k]);
+            }
         }
     }
 
-    l_token_item->current_supply = l_token_item->total_supply;
+    l_token_item->datum_token_size  = a_token_size;
+    l_token_item->datum_token       = DAP_DUP_SIZE(l_token, a_token_size);
+    l_token_item->datum_token->type = l_token_item->type;
 
-    pthread_rwlock_wrlock(&PVT(a_ledger)->tokens_rwlock);
-    HASH_ADD_STR(PVT(a_ledger)->tokens, ticker, l_token_item);
-    pthread_rwlock_unlock(&PVT(a_ledger)->tokens_rwlock);
+    if (update_token == false) {
+        pthread_rwlock_wrlock(&PVT(a_ledger)->tokens_rwlock);
+        HASH_ADD_STR(PVT(a_ledger)->tokens, ticker, l_token_item);
+        pthread_rwlock_unlock(&PVT(a_ledger)->tokens_rwlock);
+    }
     int l_res_token_tsd_parse = 0;
 
     switch(a_token->type) {
@@ -539,19 +719,19 @@ int dap_chain_ledger_token_add(dap_ledger_t *a_ledger, dap_chain_datum_token_t *
     case DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE:
         if(s_debug_more) {
             char *l_balance = dap_chain_balance_to_coins(l_token->total_supply);
-            log_it(L_NOTICE, "Simple token %s added (total_supply = %s total_signs_valid=%hu signs_total=%hu type=DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE )",
+            log_it(L_NOTICE, "Simple token %s added (total_supply = %s total_signs_valid=%hu signs_total=%hu)",
                     l_token->ticker, l_balance,
                     l_token->signs_valid, l_token->signs_total);
-            DAP_DELETE(l_balance);
+            DAP_DEL_Z(l_balance);
         }
         break;
     case DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL:
         if(s_debug_more) {
             char *l_balance = dap_chain_balance_to_coins(a_token->total_supply);
-            log_it(L_NOTICE, "Private token %s added (total_supply = %s total_signs_valid=%hu signs_total=%hu type=DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL)",
+            log_it(L_NOTICE, "Private token %s added (total_supply = %s total_signs_valid=%hu signs_total=%hu)",
                     a_token->ticker, l_balance,
                     a_token->signs_valid, a_token->signs_total);
-            DAP_DELETE(l_balance);
+            DAP_DEL_Z(l_balance);
         }
         l_res_token_tsd_parse = s_token_tsd_parse(a_ledger,l_token_item, a_token, a_token_size);
         break;
@@ -566,11 +746,26 @@ int dap_chain_ledger_token_add(dap_ledger_t *a_ledger, dap_chain_datum_token_t *
         l_res_token_tsd_parse = s_token_tsd_parse(a_ledger,l_token_item, a_token, a_token_size);
         break;
     case DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE:
-        if(s_debug_more)
-            log_it( L_WARNING, "Private token %s type=DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE. Not processed, wait for software update", a_token->ticker);
-            // TODO: Check authorithy
-            //l_res_token_tsd_parse = s_token_tsd_parse(a_ledger,l_token_item, a_token, a_token_size);
+        if(s_debug_more) {
+            char *l_balance = dap_chain_balance_to_coins(a_token->total_supply);
+            log_it(L_NOTICE, "Private token %s updated (total_supply = %s total_signs_valid=%hu signs_total=%hu)",
+                   a_token->ticker, l_balance,
+                   a_token->signs_valid, a_token->signs_total);
+            DAP_DEL_Z(l_balance);
+        }
+        l_res_token_tsd_parse = s_token_tsd_parse(a_ledger,l_token_item, a_token, a_token_size);
         break;
+    case DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_UPDATE:
+        if(s_debug_more) {
+            char *l_balance = dap_chain_balance_to_coins(a_token->total_supply);
+            log_it(L_NOTICE, "CF20 token %s updated (total_supply = %s total_signs_valid=%hu signs_total=%hu)",
+                   a_token->ticker, l_balance,
+                   a_token->signs_valid, a_token->signs_total);
+            DAP_DEL_Z(l_balance);
+        }
+        l_res_token_tsd_parse = s_token_tsd_parse(a_ledger,l_token_item, a_token, a_token_size);
+        break;
+
     default:
         if(s_debug_more)
             log_it(L_WARNING,"Unknown token declaration type 0x%04X", a_token->type );
@@ -582,7 +777,8 @@ int dap_chain_ledger_token_add(dap_ledger_t *a_ledger, dap_chain_datum_token_t *
         return -1;
     }
     s_threshold_emissions_proc(a_ledger); //TODO process thresholds only for no-consensus chains
-    s_update_token_cache(a_ledger, l_token_item);
+    if (PVT(a_ledger)->cached)
+        s_ledger_token_cache_update(a_ledger, l_token_item);
     if (a_token->type == DAP_CHAIN_DATUM_TOKEN_TYPE_OLD_SIMPLE)
         DAP_DELETE(l_token);
     return 0;
@@ -606,7 +802,7 @@ static int s_token_tsd_parse(dap_ledger_t * a_ledger, dap_chain_ledger_token_ite
     a_token_item->flags = a_token->header_native_decl.flags;
 
     for( size_t l_offset=0; l_offset < l_tsd_total_size;  l_offset += l_tsd_size ){
-        l_tsd = (dap_tsd_t *)(((byte_t*)l_tsd ) + l_tsd_size);
+        l_tsd = (dap_tsd_t *)(((byte_t *)l_tsd ) + l_tsd_size);
         l_tsd_size =  l_tsd? dap_tsd_size(l_tsd): 0;
         if( l_tsd_size==0 ){
             if(s_debug_more)
@@ -1059,11 +1255,13 @@ dap_chain_net_t* dap_chain_ledger_get_net(dap_ledger_t* a_ledger)
 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)->load_mode) {
+        bool l_update_token = (a_token->type != DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE &&
+                               a_token->type != DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_UPDATE) ? false : true;
         dap_chain_ledger_token_item_t *l_token_item;
         pthread_rwlock_rdlock(&PVT(a_ledger)->tokens_rwlock);
         HASH_FIND_STR(PVT(a_ledger)->tokens, a_token->ticker, l_token_item);
         pthread_rwlock_unlock(&PVT(a_ledger)->tokens_rwlock);
-        if (l_token_item)
+        if (l_token_item && l_update_token == false)
             return 0;
     }
     return dap_chain_ledger_token_add(a_ledger, a_token, a_token_size);
@@ -1159,13 +1357,11 @@ dap_string_t *dap_chain_ledger_threshold_hash_info(dap_ledger_t *a_ledger, dap_c
 dap_string_t *dap_chain_ledger_balance_info(dap_ledger_t *a_ledger)
 {
     dap_ledger_private_t *l_ledger_pvt = PVT(a_ledger);
-    dap_chain_ledger_tx_item_t *l_tx_item, *l_tx_tmp;
     dap_string_t *l_str_ret = dap_string_new("");
     pthread_rwlock_rdlock(&l_ledger_pvt->balance_accounts_rwlock);
     uint32_t l_counter = 0;
     dap_ledger_wallet_balance_t *l_balance_item, *l_balance_tmp;
-    HASH_ITER(hh, l_ledger_pvt->balance_accounts, l_balance_item, l_balance_tmp){
-        char l_time[1024] = {0};
+    HASH_ITER(hh, l_ledger_pvt->balance_accounts, l_balance_item, l_balance_tmp) {
         //log_it(L_DEBUG,"Ledger balance key %s, token_ticker: %s, balance: %s", l_balance_key, l_balance_item->token_ticker,
         //                        dap_chain_balance_print(l_balance_item->balance));
         dap_string_append(l_str_ret, "Ledger balance key: ");
@@ -1193,11 +1389,12 @@ dap_string_t *dap_chain_ledger_balance_info(dap_ledger_t *a_ledger)
 dap_list_t *dap_chain_ledger_token_info(dap_ledger_t *a_ledger)
 {
     dap_list_t *l_ret_list = NULL;
+    dap_string_t *l_str_tmp = dap_string_new("");
     dap_chain_ledger_token_item_t *l_token_item, *l_tmp_item;
     pthread_rwlock_rdlock(&PVT(a_ledger)->tokens_rwlock);
     HASH_ITER(hh, PVT(a_ledger)->tokens, l_token_item, l_tmp_item) {
         const char *l_type_str;
-        const char *l_flags_str = s_flag_str_from_code(l_token_item->datum_token->header_private_decl.flags);;
+        //const char *l_flags_str = s_flag_str_from_code(l_token_item->datum_token->header_private_decl.flags);;
         switch (l_token_item->type) {
             case DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE: // 256
             case DAP_CHAIN_DATUM_TOKEN_TYPE_OLD_SIMPLE:
@@ -1219,36 +1416,51 @@ dap_list_t *dap_chain_ledger_token_info(dap_ledger_t *a_ledger)
        char *l_item_str = NULL;
 
         if ((l_token_item->type == DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL)
-                || (l_token_item->type == DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_UPDATE)){
+                ||	(l_token_item->type == DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_UPDATE)
+                ||	(l_token_item->type == DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL)
+                ||	(l_token_item->type == DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE)) {
             char *l_balance_cur = dap_chain_balance_print(l_token_item->current_supply);
             char *l_balance_total = dap_chain_balance_print(l_token_item->total_supply);
-            l_item_str = dap_strdup_printf("Token name '%s', type %s, flags: %s\n"
+            s_datum_token_dump_tsd(l_str_tmp, l_token_item->datum_token, l_token_item->datum_token_size, "hex");
+            size_t l_certs_field_size = l_token_item->datum_token_size - sizeof(*l_token_item->datum_token) - l_token_item->datum_token->header_native_decl.tsd_total_size;
+            dap_chain_datum_token_certs_dump(l_str_tmp, l_token_item->datum_token->data_n_tsd + l_token_item->datum_token->header_native_decl.tsd_total_size,
+                                         l_certs_field_size, "hex");
+            l_item_str = dap_strdup_printf("-->Token name '%s', type %s, flags: %s\n"
                                             "\tSupply (current/total) %s/%s\n"
                                             "\tDecimals: 18\n"
                                             "\tAuth signs (valid/total) %zu/%zu\n"
-                                            "\tTotal emissions %u\n",
-                                            &l_token_item->ticker, l_type_str, s_flag_str_from_code(l_token_item->datum_token->header_private_decl.flags),
-                                            l_balance_cur, l_balance_total, l_token_item->auth_signs_valid, l_token_item->auth_signs_total,
+                                            "TSD and Signs:\n"
+                                            "%s"
+                                            "\tTotal emissions %u\n___\n",
+                                            &l_token_item->ticker, l_type_str, s_flag_str_from_code(l_token_item->datum_token->header_native_decl.flags),
+                                            l_balance_cur, l_balance_total,
+                                            l_token_item->auth_signs_valid, l_token_item->auth_signs_total,
+                                            l_str_tmp->str,
                                             HASH_COUNT(l_token_item->token_emissions));
             DAP_DEL_Z(l_balance_cur);
             DAP_DEL_Z(l_balance_total);
         } else {
                 char *l_balance_cur = dap_chain_balance_print(l_token_item->current_supply);
                 char *l_balance_total = dap_chain_balance_print(l_token_item->total_supply);
-                l_item_str = dap_strdup_printf("Token name '%s', type %s, flags: %s\n"
+                size_t l_certs_field_size = l_token_item->datum_token_size - sizeof(*l_token_item->datum_token);
+                dap_chain_datum_token_certs_dump(l_str_tmp, l_token_item->datum_token->data_n_tsd,
+                                                 l_certs_field_size, "hex");
+                l_item_str = dap_strdup_printf("-->Token name '%s', type %s, flags: %s\n"
                                                 "\tSupply (current/total) %s/%s\n"
                                                 "\tDecimals: 18\n"
                                                 "\tAuth signs (valid/total) %zu/%zu\n"
-                                                "\tTotal emissions %u\n",
-                                                &l_token_item->ticker, l_type_str, s_flag_str_from_code(l_token_item->datum_token->header_private_decl.flags),
+                                                "%s"
+                                                "\tTotal emissions %u\n___\n",
+                                                &l_token_item->ticker, l_type_str, "SIMPLE token has no flags",
                                                 l_balance_cur, l_balance_total,
                                                 l_token_item->auth_signs_valid, l_token_item->auth_signs_total,
+                                                l_str_tmp->str,
                                                 HASH_COUNT(l_token_item->token_emissions));
                 DAP_DEL_Z(l_balance_cur);
                 DAP_DEL_Z(l_balance_total);
         }
-
         l_ret_list = dap_list_append(l_ret_list, l_item_str);
+        dap_string_free(l_str_tmp, true);
     }
     pthread_rwlock_unlock(&PVT(a_ledger)->tokens_rwlock);
     return l_ret_list;
@@ -1375,14 +1587,7 @@ static bool s_load_cache_gdb_loaded_spent_txs_callback(dap_global_db_context_t *
     for (size_t i = 0; i < a_values_count; i++) {
         dap_chain_ledger_tx_spent_item_t *l_tx_spent_item = DAP_NEW_Z(dap_chain_ledger_tx_spent_item_t);
         dap_chain_hash_fast_from_str(a_values[i].key, &l_tx_spent_item->tx_hash_fast);
-        strncpy(l_tx_spent_item->token_ticker, (char *)a_values[i].value,
-                min(a_values[i].value_len, DAP_CHAIN_TICKER_SIZE_MAX - 1));
-        size_t l_spent_time_len = 0;
-        byte_t* l_spent_time_data = dap_global_db_get_sync(DAP_CHAIN_LEDGER_SPENT_TXS_TIME_STR, a_values[i].key, &l_spent_time_len, NULL, NULL);
-        if (l_spent_time_data && l_spent_time_len == sizeof(dap_time_t)) {
-            l_tx_spent_item->spent_time = *(dap_time_t*)l_spent_time_data;
-            DAP_DELETE(l_spent_time_data);
-        }
+        l_tx_spent_item->cache_data = *(typeof(((dap_chain_ledger_tx_spent_item_t*)0)->cache_data)*)a_values[i].value;
         HASH_ADD(hh, l_ledger_pvt->spent_items, tx_hash_fast, sizeof(dap_chain_hash_fast_t), l_tx_spent_item);
     }
 
@@ -1418,7 +1623,7 @@ static bool s_load_cache_gdb_loaded_txs_callback(dap_global_db_context_t * a_glo
         l_tx_item->tx = DAP_NEW_Z_SIZE(dap_chain_datum_tx_t, a_values[i].value_len - sizeof(l_tx_item->cache_data));
         memcpy(&l_tx_item->cache_data, a_values[i].value, sizeof(l_tx_item->cache_data));
         memcpy(l_tx_item->tx, a_values[i].value + sizeof(l_tx_item->cache_data), a_values[i].value_len - sizeof(l_tx_item->cache_data));
-        HASH_ADD(hh, l_ledger_pvt->ledger_items, tx_hash_fast, sizeof(dap_chain_hash_fast_t), l_tx_item);
+        HASH_ADD_INORDER(hh, l_ledger_pvt->ledger_items, tx_hash_fast, sizeof(dap_chain_hash_fast_t), l_tx_item, s_sort_ledger_tx_item);
     }
 
     char *l_gdb_group = dap_chain_ledger_get_gdb_group(l_ledger, DAP_CHAIN_LEDGER_SPENT_TXS_STR);
@@ -1427,6 +1632,34 @@ static bool s_load_cache_gdb_loaded_txs_callback(dap_global_db_context_t * a_glo
     return true;
 }
 
+static bool s_load_cache_gdb_loaded_stake_lock_callback(dap_global_db_context_t * a_global_db_context,int a_rc,
+                                             const char * a_group, const char * a_key,
+                                             const size_t a_values_total,  const size_t a_values_shift,
+                                             const size_t a_values_count, dap_global_db_obj_t * a_values,
+                                             void * a_arg)
+{
+    dap_ledger_t *l_ledger = (dap_ledger_t *) a_arg;
+    dap_ledger_private_t *l_ledger_pvt = PVT(l_ledger);
+
+    for (size_t i = 0; i < a_values_count; i++) {
+        if (a_values[i].value_len != sizeof(dap_hash_fast_t))
+            continue;
+        dap_chain_ledger_stake_lock_item_t *l_new_stake_lock_emission = DAP_NEW(dap_chain_ledger_stake_lock_item_t);
+        if (!l_new_stake_lock_emission) {
+            debug_if(s_debug_more, L_ERROR, "Error: memory allocation when try adding item 'dap_chain_ledger_stake_lock_item_t' to hash-table");
+            continue;
+        }
+        dap_chain_hash_fast_from_str(a_values[i].key, &l_new_stake_lock_emission->tx_for_stake_lock_hash);
+        l_new_stake_lock_emission->tx_used_out = *(dap_hash_fast_t *)(a_values[i].value);
+        HASH_ADD(hh, l_ledger_pvt->emissions_for_stake_lock, tx_for_stake_lock_hash, sizeof(dap_chain_hash_fast_t), l_new_stake_lock_emission);
+    }
+
+    char* l_gdb_group = dap_chain_ledger_get_gdb_group(l_ledger, DAP_CHAIN_LEDGER_TXS_STR);
+    dap_global_db_get_all(l_gdb_group,0, s_load_cache_gdb_loaded_txs_callback, l_ledger);
+    DAP_DELETE(l_gdb_group);
+    return true;
+}
+
 
 /**
  * @brief GDB callback for loaded emissions from cache
@@ -1471,10 +1704,11 @@ static bool s_load_cache_gdb_loaded_emissions_callback(dap_global_db_context_t *
                  sizeof(dap_chain_hash_fast_t), l_emission_item);
     }
 
-    char* l_gdb_group = dap_chain_ledger_get_gdb_group(l_ledger, DAP_CHAIN_LEDGER_TXS_STR);
+    char* l_gdb_group = dap_chain_ledger_get_gdb_group(l_ledger, DAP_CHAIN_LEDGER_STAKE_LOCK_STR);
     dap_global_db_get_all(l_gdb_group,0, s_load_cache_gdb_loaded_txs_callback, l_ledger);
     DAP_DELETE(l_gdb_group);
     return true;
+
 }
 
 
@@ -1579,13 +1813,17 @@ dap_ledger_t* dap_chain_ledger_create(uint16_t a_check_flags, char *a_net_name)
     l_ledger_priv->load_mode = true;
     l_ledger_priv->tps_timer = NULL;
     l_ledger_priv->tps_count = 0;
-#ifdef DAP_CHAIN_LEDGER_TEST
-    if (dap_config_get_item_bool_default(g_config, "ledger", "cache_enabled", false)) {
-#else
+
     if (dap_config_get_item_bool_default(g_config, "ledger", "cache_enabled", true)) {
+        dap_chain_node_role_t l_role = dap_chain_net_get_role(l_ledger_priv->net);
+        if (l_role.enums != NODE_ROLE_MASTER && l_role.enums != NODE_ROLE_ROOT) {
+#ifndef DAP_CHAIN_LEDGER_TEST
+            l_ledger_priv->cached = true;
+            // load ledger cache from GDB
+            dap_chain_ledger_load_cache(l_ledger);
 #endif
-        // load ledger cache from GDB
-        dap_chain_ledger_load_cache(l_ledger);
+        }
+
     }
 
     return l_ledger;
@@ -1661,9 +1899,9 @@ int dap_chain_ledger_token_emission_add_check(dap_ledger_t *a_ledger, byte_t *a_
     }
 
     //additional check for private tokens
-    if ((l_token_item->type == DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL) 
-        ||  (l_token_item->type == DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE) 
-        ||  (l_token_item->type == DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL) 
+    if ((l_token_item->type == DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL)
+        ||  (l_token_item->type == DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE)
+        ||  (l_token_item->type == DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL)
         ||  (l_token_item->type == DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_UPDATE)) {
         //s_ledger_permissions_check(l_token_item)
         //    return -5;
@@ -1766,6 +2004,19 @@ bool s_chain_ledger_token_tsd_check(dap_chain_ledger_token_item_t * a_token_item
     return true;
 }
 
+static void s_ledger_emission_cache_update(dap_ledger_t *a_ledger, dap_chain_ledger_token_emission_item_t *a_emission_item)
+{
+    char *l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_EMISSIONS_STR);
+    size_t l_cache_size = a_emission_item->datum_token_emission_size + sizeof(dap_hash_fast_t);
+    uint8_t *l_cache = DAP_NEW_STACK_SIZE(uint8_t, l_cache_size);
+    memcpy(l_cache, &a_emission_item->tx_used_out, sizeof(dap_hash_fast_t));
+    memcpy(l_cache + sizeof(dap_hash_fast_t), a_emission_item->datum_token_emission, a_emission_item->datum_token_emission_size);
+    char *l_hash_str = dap_hash_fast_to_str_new(&a_emission_item->datum_token_emission_hash);
+    if (!dap_global_db_set(l_gdb_group, l_hash_str, l_cache, l_cache_size, false, NULL, NULL)) {
+        log_it(L_WARNING, "Ledger cache mismatch");
+    }
+    DAP_DELETE(l_gdb_group);
+}
 
 /**
  * @brief dap_chain_ledger_token_emission_add
@@ -1862,24 +2113,17 @@ static inline int s_token_emission_add(dap_ledger_t *a_ledger, byte_t *a_token_e
                     DAP_DELETE(l_value);
                     return -4;
                 }
-                //update current_supply in ledger cache and ledger memory object
-                s_update_token_cache(a_ledger, l_token_item);
+                if (PVT(a_ledger)->cached)
+                    s_ledger_token_cache_update(a_ledger, l_token_item);
             }
 
             pthread_rwlock_wrlock(&l_token_item->token_emissions_rwlock);
             HASH_ADD(hh, l_token_item->token_emissions, datum_token_emission_hash,
                      sizeof(*a_emission_hash), l_token_emission_item);
             pthread_rwlock_unlock(&l_token_item->token_emissions_rwlock);
-            // Add it to cache
-            char *l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_EMISSIONS_STR);
-            size_t l_cache_size = a_token_emission_size + sizeof(dap_hash_fast_t);
-            uint8_t *l_cache = DAP_NEW_Z_SIZE(uint8_t, l_cache_size);
-            memcpy(l_cache + sizeof(dap_hash_fast_t), a_token_emission, a_token_emission_size);
-            if ( dap_global_db_set(l_gdb_group, l_hash_str, l_cache, l_cache_size, false, NULL, NULL ) ) {
-                log_it(L_WARNING, "Ledger cache mismatch");
-            }
-            DAP_DELETE(l_cache);
-            DAP_DELETE(l_gdb_group);
+            if (PVT(a_ledger)->cached)
+                // Add it to cache
+                s_ledger_emission_cache_update(a_ledger, l_token_emission_item);
             if(s_debug_more) {
                 char * l_token_emission_address_str = dap_chain_addr_to_str(&(l_token_emission_item->datum_token_emission->hdr.address));
                 char *l_balance = dap_chain_balance_to_coins(l_token_emission_item->datum_token_emission->hdr.value_256);
@@ -1931,42 +2175,60 @@ static inline int s_token_emission_add(dap_ledger_t *a_ledger, byte_t *a_token_e
     return l_ret;
 }
 
-dap_chain_ledger_token_emission_for_stake_lock_item_t *s_emission_for_stake_lock_item_add(dap_ledger_t *a_ledger, const dap_chain_hash_fast_t *a_token_emission_hash)
+void s_ledger_stake_lock_cache_update(dap_ledger_t *a_ledger, dap_chain_ledger_stake_lock_item_t *a_stake_lock_item)
+{
+    char *l_hash_str = dap_chain_hash_fast_to_str_new(&a_stake_lock_item->tx_for_stake_lock_hash);
+    char *l_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_STAKE_LOCK_STR);
+    if (!dap_global_db_set(l_group, l_hash_str, &a_stake_lock_item->tx_used_out, sizeof(dap_hash_fast_t), false, NULL, NULL))
+        log_it(L_WARNING, "Ledger cache mismatch");
+    DAP_DEL_Z(l_hash_str);
+    DAP_DEL_Z(l_group);
+}
+
+int dap_chain_ledger_emission_for_stake_lock_item_add(dap_ledger_t *a_ledger, const dap_chain_hash_fast_t *a_tx_hash)
 {
     dap_ledger_private_t *l_ledger_priv = PVT(a_ledger);
-    dap_chain_ledger_token_emission_for_stake_lock_item_t *l_new_stake_lock_emission;
-    pthread_rwlock_rdlock(&s_emission_for_stake_lock_rwlock);
-    HASH_FIND(hh, s_emission_for_stake_lock, a_token_emission_hash, sizeof(dap_hash_fast_t),
+    dap_chain_ledger_stake_lock_item_t *l_new_stake_lock_emission;
+    pthread_rwlock_rdlock(&l_ledger_priv->stake_lock_rwlock);
+    HASH_FIND(hh, l_ledger_priv->emissions_for_stake_lock, a_tx_hash, sizeof(dap_hash_fast_t),
               l_new_stake_lock_emission);
-    pthread_rwlock_unlock(&s_emission_for_stake_lock_rwlock);
+    pthread_rwlock_unlock(&l_ledger_priv->stake_lock_rwlock);
     if (l_new_stake_lock_emission) {
-        return l_new_stake_lock_emission;
+        return -1;
     }
-    l_new_stake_lock_emission = DAP_NEW(dap_chain_ledger_token_emission_for_stake_lock_item_t);
-    l_new_stake_lock_emission->datum_token_emission_for_stake_lock_hash = *a_token_emission_hash;
-    l_new_stake_lock_emission->tx_used_out = (dap_chain_hash_fast_t){ 0 };
-    pthread_rwlock_wrlock(&s_emission_for_stake_lock_rwlock);
-    HASH_ADD(hh, s_emission_for_stake_lock, datum_token_emission_for_stake_lock_hash, sizeof(dap_chain_hash_fast_t), l_new_stake_lock_emission);
-    pthread_rwlock_unlock(&s_emission_for_stake_lock_rwlock);
-
-    if (!l_new_stake_lock_emission
-    &&	s_debug_more) {
-        log_it(L_ERROR, "Error: memory allocation when adding item 'dap_chain_ledger_token_emission_for_stake_lock_item_t' to hash-table");
+    l_new_stake_lock_emission = DAP_NEW_Z(dap_chain_ledger_stake_lock_item_t);
+    if (!l_new_stake_lock_emission) {
+        if (s_debug_more) {
+            log_it(L_ERROR, "Error: memory allocation when try adding item 'dap_chain_ledger_stake_lock_item_t' to hash-table");
+        }
+        return -13;
     }
-    return l_new_stake_lock_emission;
+    l_new_stake_lock_emission->tx_for_stake_lock_hash = *a_tx_hash;
+    pthread_rwlock_wrlock(&l_ledger_priv->stake_lock_rwlock);
+    HASH_ADD(hh, l_ledger_priv->emissions_for_stake_lock, tx_for_stake_lock_hash, sizeof(dap_chain_hash_fast_t), l_new_stake_lock_emission);
+    pthread_rwlock_unlock(&l_ledger_priv->stake_lock_rwlock);
+
+    if (!l_new_stake_lock_emission)
+        debug_if(s_debug_more, L_ERROR, "Error: adding to hash-table. Be careful, there may be leaks");
+    else if (PVT(a_ledger)->cached)
+        s_ledger_stake_lock_cache_update(a_ledger, l_new_stake_lock_emission);
+
+    return 0;
+
 }
 
-dap_chain_ledger_token_emission_for_stake_lock_item_t *s_emission_for_stake_lock_item_find(dap_ledger_t *a_ledger, const dap_chain_hash_fast_t *a_token_emission_hash)
+dap_chain_ledger_stake_lock_item_t *s_emissions_for_stake_lock_item_find(dap_ledger_t *a_ledger, const dap_chain_hash_fast_t *a_token_emission_hash)
 {
     dap_ledger_private_t *l_ledger_priv = PVT(a_ledger);
-    dap_chain_ledger_token_emission_for_stake_lock_item_t *l_new_stake_lock_emission;
-    pthread_rwlock_rdlock(&s_emission_for_stake_lock_rwlock);
-    HASH_FIND(hh, s_emission_for_stake_lock, a_token_emission_hash, sizeof(dap_chain_hash_fast_t),
+    dap_chain_ledger_stake_lock_item_t *l_new_stake_lock_emission;
+    pthread_rwlock_rdlock(&l_ledger_priv->stake_lock_rwlock);
+    HASH_FIND(hh, l_ledger_priv->emissions_for_stake_lock, a_token_emission_hash, sizeof(dap_chain_hash_fast_t),
               l_new_stake_lock_emission);
-    pthread_rwlock_unlock(&s_emission_for_stake_lock_rwlock);
+    pthread_rwlock_unlock(&l_ledger_priv->stake_lock_rwlock);
     return l_new_stake_lock_emission;
 }
 
+
 int dap_chain_ledger_token_emission_load(dap_ledger_t *a_ledger, byte_t *a_token_emission, size_t a_token_emission_size)
 {
     dap_chain_hash_fast_t l_token_emission_hash = {};
@@ -2065,7 +2327,7 @@ const char* dap_chain_ledger_tx_get_token_ticker_by_hash(dap_ledger_t *a_ledger,
     dap_chain_ledger_tx_spent_item_t *l_spent_item;
     HASH_FIND_BYHASHVALUE(hh, l_ledger_priv->spent_items, a_tx_hash, sizeof(*a_tx_hash), l_hash_value, l_spent_item);
     pthread_rwlock_unlock(&l_ledger_priv->ledger_rwlock);
-    return l_spent_item ? l_spent_item->token_ticker : NULL;
+    return l_spent_item ? l_spent_item->cache_data.token_ticker : NULL;
 
 }
 
@@ -2216,6 +2478,50 @@ bool dap_chain_ledger_tx_spent_find_by_hash(dap_ledger_t *a_ledger, dap_chain_ha
     return l_tx_item;
 }
 
+dap_hash_fast_t *dap_chain_ledger_get_final_chain_tx_hash(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a_cond_type, dap_chain_hash_fast_t *a_tx_hash)
+{
+    if(!a_ledger || !a_tx_hash || dap_hash_fast_is_blank(a_tx_hash))
+        return NULL;
+    dap_ledger_private_t *l_ledger_priv = PVT(a_ledger);
+    dap_chain_ledger_tx_item_t *l_item;
+    unsigned l_hash_value;
+    dap_chain_hash_fast_t *l_tx_hash = a_tx_hash;
+    pthread_rwlock_rdlock(&l_ledger_priv->ledger_rwlock);
+    while (l_tx_hash) {
+        HASH_VALUE(l_tx_hash, sizeof(*l_tx_hash), l_hash_value);
+        HASH_FIND_BYHASHVALUE(hh, l_ledger_priv->ledger_items, l_tx_hash, sizeof(*l_tx_hash), l_hash_value, l_item);
+        if (l_item) {
+            int l_out_num = -1;
+            dap_chain_datum_tx_out_cond_get(l_item->tx, a_cond_type, &l_out_num);
+            if (l_out_num != -1 && l_out_num < MAX_OUT_ITEMS) {
+                if (dap_hash_fast_is_blank(&l_item->cache_data.tx_hash_spent_fast[l_out_num]))
+                    break;      // We have unused conditional output
+                else {
+                    l_tx_hash = &l_item->cache_data.tx_hash_spent_fast[l_out_num];
+                    continue;   // Conditional output is used out
+                }
+            } else {            // No conditional output found
+                l_tx_hash = NULL;
+                break;
+            }
+        }
+        dap_chain_ledger_tx_spent_item_t *l_spent_item;
+        HASH_FIND_BYHASHVALUE(hh, l_ledger_priv->spent_items, l_tx_hash, sizeof(*l_tx_hash), l_hash_value, l_spent_item);
+        if (l_spent_item) {
+            l_tx_hash = &l_spent_item->cache_data.tx_hash_spent_fast;
+            if (dap_hash_fast_is_blank(l_tx_hash))
+                break;          // We have no condional outpul with spent item
+        } else {
+            l_tx_hash = NULL;   // We can't find pointed hash in the ledger
+            break;
+        }
+    }
+    pthread_rwlock_unlock(&l_ledger_priv->ledger_rwlock);
+    if (l_tx_hash && !dap_hash_fast_is_blank(l_tx_hash))
+        return l_tx_hash;
+    return NULL;
+}
+
 /**
  * Check whether used 'out' items (local function)
  */
@@ -2228,7 +2534,7 @@ static bool dap_chain_ledger_item_is_used_out(dap_chain_ledger_tx_item_t *a_item
     }
     if(a_idx_out >= MAX_OUT_ITEMS) {
         if(s_debug_more)
-            log_it(L_ERROR, "Too big index(%d) of 'out'items (max=%d)", a_idx_out, MAX_OUT_ITEMS);
+            log_it(L_ERROR, "Too big index(%d) of 'out' items (max=%d)", a_idx_out, MAX_OUT_ITEMS);
     }
     assert(a_idx_out < MAX_OUT_ITEMS);
     // if there are used 'out' items
@@ -2290,7 +2596,6 @@ static int s_ledger_permissions_check(dap_chain_ledger_token_item_t *  a_token_i
  */
 bool s_tx_match_sign(dap_chain_datum_token_emission_t *a_datum_emission, dap_chain_datum_tx_t *a_tx)
 {
-    bool l_ret_value = false;
     if(!a_datum_emission || !a_tx) {
         return false;
     }
@@ -2342,77 +2647,45 @@ bool s_tx_match_sign(dap_chain_datum_token_emission_t *a_datum_emission, dap_cha
     return false;
 }
 
-static int s_check_out_cond_verificator_added(dap_ledger_t* a_ledger, dap_chain_datum_tx_t* a_tx, dap_list_t* a_list_tx_out_cond)
-{
-    for (dap_list_t* list_tmp = a_list_tx_out_cond; list_tmp; list_tmp = dap_list_next(list_tmp)) {
-
-        dap_chain_tx_out_cond_t* l_tx_out = (dap_chain_tx_out_cond_t*)a_list_tx_out_cond->data;
-
-        // Check for add out callback
-        dap_chain_ledger_verificator_t* l_verificator;
-        int l_tmp = l_tx_out->header.subtype;
-
-        pthread_rwlock_rdlock(&s_verificators_rwlock);
-        HASH_FIND_INT(s_verificators, &l_tmp, l_verificator);
-        pthread_rwlock_unlock(&s_verificators_rwlock);
-
-        if (!l_verificator) {
-            if (s_debug_more)
-                log_it(L_ERROR, "No verificator set for conditional output subtype %d", l_tmp);
-            return -13;
-        }
-        else if (l_verificator->callback_added && l_verificator->callback_added(a_ledger, a_tx, l_tx_out) == false)
-            return -14;
-
-        /*
-        TODO: use this code when issuing for special emission-transactions is approved. needed for smart contracts in the future
-
-                    dap_ledger_private_t *l_ledger_priv = PVT(a_ledger);
-                    dap_chain_ledger_token_item_t * l_token_item = NULL;
-                    pthread_rwlock_rdlock(&l_ledger_priv->tokens_rwlock);
-                    HASH_FIND_STR(l_ledger_priv->tokens, a_token_ticker, l_token_item);
-                    pthread_rwlock_unlock(&l_ledger_priv->tokens_rwlock);
-
-                    if (!l_token_item)
-                        return NULL;
-                    dap_chain_ledger_token_emission_item_t * l_token_emission_item = NULL;
-                    pthread_rwlock_rdlock(&l_token_item->token_emissions_rwlock);
-                    HASH_FIND(hh, l_token_item->token_emissions, a_token_emission_hash, sizeof(*a_token_emission_hash),
-                              l_token_emission_item);
-                    pthread_rwlock_unlock(&l_token_item->token_emissions_rwlock);
-                    return l_token_emission_item;
-        */
-
-    }
-    return 0;
-}
-
 /**
  * Checking a new transaction before adding to the cache
  *
  * return 1 OK, -1 error
  */
 // Checking a new transaction before adding to the cache
-int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx,
-        bool a_from_threshold, dap_list_t **a_list_bound_items, dap_list_t **a_list_tx_out)
+int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash,
+                                    bool a_from_threshold, dap_list_t **a_list_bound_items, dap_list_t **a_list_tx_out)
 {
-    /*
-     Steps of checking for current transaction tx2 and every previous transaction tx1:
-     1. !is_used_out(tx1.dap_chain_datum_tx_out)
-     &&
-     2. valid(tx2.dap_chain_datum_tx_sig.pkey)
-     &&
-     3. hash(tx1) == tx2.dap_chain_datump_tx_in.tx_prev_hash
-     &&
-     4. tx1.dap_chain_datum_tx_out.addr.data.key == tx2.dap_chain_datum_tx_sig.pkey for unconditional output
-     \\
-     5a. tx1.dap_chain_datum_tx_sig.pkey == tx2.dap_chain_datum_tx_sig.pkey for conditional owner
-     \\
-     5b. tx1.dap_chain_datum_tx_out.condition == verify_svc_type(tx2) for conditional output
-     &&
-     6. sum(  find (tx2.input.tx_prev_hash).output[tx2.input_tx_prev_idx].value )  ==  sum (tx2.outputs.value) per token
-     */
-
+    if (!PVT(a_ledger)->load_mode && !a_from_threshold) {
+        dap_chain_ledger_tx_item_t *l_ledger_item;
+        pthread_rwlock_rdlock(&PVT(a_ledger)->ledger_rwlock);
+        HASH_FIND(hh, PVT(a_ledger)->ledger_items, a_tx_hash, sizeof(dap_chain_hash_fast_t), l_ledger_item);
+        pthread_rwlock_unlock(&PVT(a_ledger)->ledger_rwlock);
+        if (l_ledger_item) {     // transaction already present in the cache list
+            if (s_debug_more) {
+                char l_tx_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
+                dap_chain_hash_fast_to_str(a_tx_hash, l_tx_hash_str, sizeof(l_tx_hash_str));
+                log_it(L_WARNING, "Transaction %s already present in the cache", l_tx_hash_str);
+            }
+            return -1;
+        }
+    }
+/*
+ * Steps of checking for current transaction tx2 and every previous transaction tx1:
+ * 1. valid(tx2.dap_chain_datum_tx_sig.pkey)
+ * &&
+ * 2. !is_used_out(tx1.dap_chain_datum_tx_out)
+ * &&
+ * 3. tx1.output != tx2.bound_items.outputs.used
+ * &&
+ * 4. tx1.dap_chain_datum_tx_out.addr.data.key == tx2.dap_chain_datum_tx_sig.pkey for unconditional output
+ * \\
+ * 5. tx1.dap_chain_datum_tx_out.condition == verify_svc_type(tx2) for conditional output
+ * &&
+ * 6. sum(  find (tx2.input.tx_prev_hash).output[tx2.input_tx_prev_idx].value )  ==  sum (tx2.outputs.value) per token
+ * &&
+ * 7. valid(fee)
+*/
     dap_ledger_private_t *l_ledger_priv = PVT(a_ledger);
     if(!a_tx){
         log_it(L_DEBUG, "NULL transaction, check broken");
@@ -2430,7 +2703,7 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
     // sum of values in 'out' items from the previous transactions
     dap_chain_ledger_tokenizer_t *l_values_from_prev_tx = NULL, *l_values_from_cur_tx = NULL,
                                  *l_value_cur = NULL, *l_tmp = NULL, *l_res = NULL;
-    char *l_token = NULL;
+    char *l_token = NULL, *l_main_ticker = NULL;
     dap_chain_ledger_token_item_t * l_token_item = NULL;
     dap_chain_hash_fast_t *l_emission_hash = NULL;
 
@@ -2438,24 +2711,22 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
     int l_err_num = 0;
     int l_prev_tx_count = 0;
 
+    // 1. Verify signature in current transaction
+    if (!a_from_threshold && dap_chain_datum_tx_verify_sign(a_tx) != 1)
+        return -2;
+
     // ----------------------------------------------------------------
-    // find all 'in' items in current transaction
-    dap_list_t *l_list_in = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_IN,
-                                                          &l_prev_tx_count);
-    // find all conditional 'in' items in current transaction
-    dap_list_t *l_list_tmp = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_IN_COND,
+    // find all 'in' & conditional 'in' items in current transaction
+    dap_list_t *l_list_in = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_IN_ALL,
                                                           &l_prev_tx_count);
-    if (l_list_tmp) {
-        // add conditional input to common list
-        l_list_in = dap_list_concat(l_list_in, l_list_tmp);
-    }
-    l_list_tmp = l_list_in;
     if (!l_list_in) {
         log_it(L_WARNING, "Tx check: no valid inputs found");
         return -22;
     }
     dap_chain_ledger_tx_bound_t *bound_item;
+    dap_chain_hash_fast_t l_hash_pkey = {};
      // find all previous transactions
+    dap_list_t *l_list_tmp = l_list_in;
     for (int l_list_tmp_num = 0; l_list_tmp; l_list_tmp = dap_list_next(l_list_tmp), l_list_tmp_num++) {
         bound_item = DAP_NEW_Z(dap_chain_ledger_tx_bound_t);
         dap_chain_tx_in_t *l_tx_in = NULL;
@@ -2473,13 +2744,12 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
             l_tx_prev_hash = l_tx_in_cond->header.tx_prev_hash;
             bound_item->in.tx_cur_in_cond = l_tx_in_cond;
         }
-        bound_item->tx_prev_hash_fast = l_tx_prev_hash;
+        bound_item->tx_prev_hash = l_tx_prev_hash;
 
         bool l_is_blank = dap_hash_fast_is_blank(&l_tx_prev_hash);
         char l_tx_prev_hash_str[70]={[0]='\0'};
         if (l_is_blank){
-            if(s_debug_more)
-                log_it(L_DEBUG, "Tx check: blank prev hash ");
+            debug_if(s_debug_more && !a_from_threshold, L_DEBUG, "Tx check: blank prev hash");
             dap_snprintf(l_tx_prev_hash_str,sizeof( l_tx_prev_hash_str),"BLANK");
         }else{
             dap_chain_hash_fast_to_str(&l_tx_prev_hash,l_tx_prev_hash_str,sizeof(l_tx_prev_hash_str));
@@ -2501,20 +2771,22 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
             l_token = l_tx_token->header.ticker;
             l_emission_hash = &l_tx_token->header.token_emission_hash;
             dap_chain_ledger_token_emission_item_t *l_emission_item = s_emission_item_find(a_ledger, l_token, l_emission_hash);
-            dap_chain_ledger_token_emission_for_stake_lock_item_t *stake_lock_emission = s_emission_for_stake_lock_item_find(a_ledger, l_emission_hash);
+            dap_chain_ledger_stake_lock_item_t *stake_lock_emission = s_emissions_for_stake_lock_item_find(a_ledger, l_emission_hash);
             if (!l_emission_item && stake_lock_emission) {//check emission for STAKE_LOCK
                 dap_hash_fast_t cur_tx_hash;
                 dap_hash_fast(a_tx, dap_chain_datum_tx_get_size(a_tx), &cur_tx_hash);
-                if (!dap_hash_fast_is_blank(&stake_lock_emission->tx_used_out)
-                && 	!dap_hash_fast_compare(&cur_tx_hash, &stake_lock_emission->tx_used_out)) {
-                    debug_if(s_debug_more, L_WARNING, "stake_lock_emission is used out for tx_token [%s]", l_token);
+                if (!dap_hash_fast_is_blank(&stake_lock_emission->tx_used_out)) {
+                    if (!dap_hash_fast_compare(&cur_tx_hash, &stake_lock_emission->tx_used_out))
+                        debug_if(s_debug_more, L_WARNING, "stake_lock_emission already present in cache for tx_token [%s]", l_token);
+                    else
+                        debug_if(s_debug_more, L_WARNING, "stake_lock_emission is used out for tx_token [%s]", l_token);
                     l_err_num = -22;
                     break;
                 }
                 dap_tsd_t *l_tsd;
                 dap_chain_datum_token_t *l_datum_token = dap_chain_ledger_token_ticker_check(a_ledger, l_token);
                 if (l_datum_token
-                &&	l_datum_token->type == DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL
+                &&	(l_datum_token->type == DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL || l_datum_token->type == DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_UPDATE)
                 &&	l_datum_token->header_native_decl.tsd_total_size
                 &&	NULL != (l_tsd = dap_tsd_find(l_datum_token->data_n_tsd, l_datum_token->header_native_decl.tsd_total_size, DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DELEGATE_EMISSION_FROM_STAKE_LOCK))) {
                     dap_chain_datum_token_tsd_delegate_from_stake_lock_t l_tsd_section = dap_tsd_get_scalar(l_tsd, dap_chain_datum_token_tsd_delegate_from_stake_lock_t);
@@ -2531,10 +2803,15 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
                         break;
                     }
                     dap_chain_datum_tx_t *l_tx_stake_lock = dap_chain_ledger_tx_find_by_hash(a_ledger, l_emission_hash);
+                    if (!l_tx_stake_lock) {
+                        debug_if(s_debug_more, L_WARNING, "Not found stake_lock transaction");
+                        l_err_num = DAP_CHAIN_CS_VERIFY_CODE_TX_NO_EMISSION;
+                        break;
+                    }
                     dap_chain_tx_out_cond_t *l_tx_stake_lock_out_cond = (dap_chain_tx_out_cond_t*)dap_chain_datum_tx_item_get(l_tx_stake_lock, 0, TX_ITEM_TYPE_OUT_COND, 0);//TODO: ADD CHECK COUNT TX
                     if (!l_tx_stake_lock_out_cond) {
                         debug_if(s_debug_more, L_WARNING, "No OUT_COND to for tx_token [%s]", l_tx_token->header.ticker);
-                        l_err_num = -30;
+                        l_err_num = -32;
                         break;
                     }
                     if (l_tx_stake_lock_out_cond->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK) {
@@ -2555,7 +2832,27 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
                         l_err_num = -26;
                         break;
                     }
-
+                    l_token_item = NULL;
+                    pthread_rwlock_rdlock(&l_ledger_priv->tokens_rwlock);
+                    HASH_FIND_STR(l_ledger_priv->tokens, l_token, l_token_item);
+                    pthread_rwlock_unlock(&l_ledger_priv->tokens_rwlock);
+                    if (!l_token_item){
+                        if(s_debug_more)
+                            log_it(L_WARNING, "No token item found for token %s", l_token);
+                        l_err_num = -15;
+                        break;
+                    }
+                    if (!IS_ZERO_256(l_token_item->total_supply) &&
+                            compare256(l_token_item->current_supply, l_tx_out->header.value) < 0) {
+                        char *l_balance = dap_chain_balance_print(l_token_item->current_supply);
+                        char *l_value = dap_chain_balance_print(l_tx_out->header.value);
+                        log_it(L_WARNING, "Token current supply %s lower, than emission value = %s",
+                               l_balance, l_value);
+                        DAP_DEL_Z(l_balance);
+                        DAP_DEL_Z(l_value);
+                        l_err_num = -30;
+                        break;
+                    }
                     if (!EQUAL_256(l_value_expected, l_tx_out->header.value)) {
                         char * l_value_expected_str = dap_chain_balance_print(l_value_expected);
                         char * l_locked_value_str = dap_chain_balance_print(l_tx_out->header.value);
@@ -2571,54 +2868,19 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
                     // check tiker
                     const char *tx_tiker = dap_chain_ledger_tx_get_token_ticker_by_hash(a_ledger, l_emission_hash);
                     if (!tx_tiker) {
-                        debug_if(s_debug_more, L_WARNING, "No tiker stake_lock to for tx_token [%s]", l_tx_token->header.ticker);
+                        debug_if(s_debug_more, L_WARNING, "No ticker stake_lock to for tx_token [%s]", l_tx_token->header.ticker);
                         l_err_num = -33;
                         break;
                     }
                     if (strcmp(tx_tiker, l_tsd_section.ticker_token_from)) {
-                        debug_if(s_debug_more, L_WARNING, "Tikers not equal for [%s]", l_tx_token->header.ticker);
+                        debug_if(s_debug_more, L_WARNING, "Tickers not equal for [%s]", l_tx_token->header.ticker);
                         l_err_num = -35;
                         break;
                     }
-
-                    //Update value in ledger memory object
-                    if (dap_hash_fast_is_blank(&stake_lock_emission->tx_used_out)) {
-                        l_token_item = NULL;
-                        pthread_rwlock_rdlock(&l_ledger_priv->tokens_rwlock);
-                        HASH_FIND_STR(l_ledger_priv->tokens, l_token, l_token_item);
-                        pthread_rwlock_unlock(&l_ledger_priv->tokens_rwlock);
-                        if (!l_token_item){
-                            if(s_debug_more)
-                                log_it(L_WARNING, "No token item found for token %s", l_token);
-                            l_err_num = -15;
-                            break;
-                        }
-                        if (!IS_ZERO_256(l_token_item->total_supply)) {
-                            if (compare256(l_token_item->current_supply, l_tx_out->header.value) >= 0){
-                                SUBTRACT_256_256(l_token_item->current_supply, l_tx_out->header.value, &l_token_item->current_supply);
-                                char *l_balance = dap_chain_balance_print(l_token_item->current_supply);
-                                log_it(L_DEBUG, "New current supply %s for token %s", l_balance, l_token_item->ticker);
-                                DAP_DEL_Z(l_balance);
-                            } else {
-                                char *l_balance = dap_chain_balance_print(l_token_item->current_supply);
-                                char *l_value = dap_chain_balance_print(l_tx_out->header.value);
-                                log_it(L_WARNING, "Token current supply %s lower, than emission value = %s",
-                                       l_balance, l_value);
-                                DAP_DEL_Z(l_balance);
-                                DAP_DEL_Z(l_value);
-                                l_err_num = -30;
-                                break;
-                            }
-                            stake_lock_emission->tx_used_out = cur_tx_hash;
-                            //update current_supply in ledger cache and ledger memory object
-                            s_update_token_cache(a_ledger, l_token_item);
-                        } else {
-                            log_it(L_DEBUG, "Total supply for token %s not found", l_token_item->ticker);
-                            l_err_num = -32;
-                            break;
-                        }
-                    }
                     debug_if(s_debug_more, L_NOTICE, "Check emission passed for tx_token [%s]", l_tx_token->header.ticker);
+                    bound_item->tx_prev = l_tx_stake_lock;
+                    bound_item->stake_lock_item = stake_lock_emission;
+                    l_list_bound_items = dap_list_append(l_list_bound_items, bound_item);
                     break;
                 } else {
                     debug_if(s_debug_more, L_WARNING, "tx_token [%s] not valid for stake_lock transaction", l_token);
@@ -2627,7 +2889,7 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
                 }
             }
             if (!l_emission_item) {
-                debug_if(s_debug_more, L_WARNING, "Emission for tx_token [%s] wasn't found", l_tx_token->header.ticker);
+                debug_if(s_debug_more && !a_from_threshold, L_WARNING, "Emission for tx_token [%s] wasn't found", l_tx_token->header.ticker);
                 l_err_num = DAP_CHAIN_CS_VERIFY_CODE_TX_NO_EMISSION;
                 break;
             }
@@ -2668,12 +2930,9 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
         }
         // Get previous transaction in the cache by hash
         dap_chain_ledger_tx_item_t *l_item_out = NULL;
-        dap_chain_datum_tx_t *l_tx_prev =
-                s_find_datum_tx_by_hash(a_ledger, &l_tx_prev_hash, &l_item_out); // dap_chain_datum_tx_t *l_tx_prev = (dap_chain_datum_tx_t*) dap_chain_node_datum_tx_cache_find(&tx_prev_hash);
-        bound_item->item_out = l_item_out;
-        if(!l_tx_prev) { // Unchained transaction
-            if (s_debug_more && !a_from_threshold)
-                log_it(L_DEBUG, "No previous transaction was found for hash %s", l_tx_prev_hash_str);
+        dap_chain_datum_tx_t *l_tx_prev = s_find_datum_tx_by_hash(a_ledger, &l_tx_prev_hash, &l_item_out);
+        if (!l_tx_prev) { // Unchained transaction
+            debug_if(s_debug_more && !a_from_threshold, L_DEBUG, "No previous transaction was found for hash %s", l_tx_prev_hash_str);
             l_err_num = DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS;
             break;
         }
@@ -2681,54 +2940,54 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
             log_it(L_INFO,"Previous transaction was found for hash %s",l_tx_prev_hash_str);
         bound_item->tx_prev = l_tx_prev;
 
-        // 1. Check if out in previous transaction has spent
+        // 2. Check if out in previous transaction has spent
         int l_idx = (l_cond_type == TX_ITEM_TYPE_IN) ? l_tx_in->header.tx_out_prev_idx : l_tx_in_cond->header.tx_out_prev_idx;
         if (dap_chain_ledger_item_is_used_out(l_item_out, l_idx)) {
             l_err_num = -6;
             break;
         }
 
-        // 2. Verify signature in current transaction
-        if(dap_chain_datum_tx_verify_sign(a_tx) != 1) {
-            l_err_num = -2;
-            break;
-        }
-
-        // 3. Compare hash in previous transaction with hash inside 'in' item
-        // calculate hash of previous transaction anew
-        dap_chain_hash_fast_t *l_hash_prev = dap_chain_node_datum_tx_calc_hash(l_tx_prev);
-        int l_res_hash = dap_hash_fast_compare(l_hash_prev, &l_tx_prev_hash);
-
-        DAP_DELETE(l_hash_prev);
-        if (l_res_hash != 1) {
-            l_err_num = -7;
-            break;
-        }
-
         uint256_t l_value;
-        // Get list of all 'out' items from previous transaction
-        dap_list_t *l_list_prev_out = dap_chain_datum_tx_items_get(l_tx_prev, TX_ITEM_TYPE_OUT_ALL, NULL);
         // Get one 'out' item in previous transaction bound with current 'in' item
-        void *l_tx_prev_out = dap_list_nth_data(l_list_prev_out, l_idx);
-        dap_list_free(l_list_prev_out);
+        void *l_tx_prev_out = dap_chain_datum_tx_item_get_nth(l_tx_prev, TX_ITEM_TYPE_OUT_ALL, l_idx);
         if(!l_tx_prev_out) {
             l_err_num = -8;
             break;
         }
+        // 3. Compare out in previous transaction with currently used out
+        for (dap_list_t *it = l_list_bound_items; it; it = it->next) {
+            dap_chain_ledger_tx_bound_t *l_bound_tmp = it->data;
+            if (l_tx_prev_out == l_bound_tmp->out.tx_prev_out) {
+                debug_if(s_debug_more, L_ERROR, "Previous transaction output already used in current tx");
+                l_err_num = -7;
+                break;
+            }
+        }
+        if (l_err_num)
+            break;
+
         if (l_cond_type == TX_ITEM_TYPE_IN) {
             dap_chain_tx_item_type_t l_type = *(uint8_t *)l_tx_prev_out;
+            dap_hash_fast_t *l_prev_out_addr_key = NULL;
             switch (l_type) {
             case TX_ITEM_TYPE_OUT_OLD:
                 bound_item->out.tx_prev_out = l_tx_prev_out;
                 l_tx_in_from = bound_item->out.tx_prev_out->addr;
+                l_prev_out_addr_key = &bound_item->out.tx_prev_out->addr.data.hash_fast;
+                l_value = dap_chain_uint256_from(bound_item->out.tx_prev_out->header.value);
                 break;
             case TX_ITEM_TYPE_OUT: // 256
                 bound_item->out.tx_prev_out_256 = l_tx_prev_out;
                 l_tx_in_from = bound_item->out.tx_prev_out_256->addr;
+                l_prev_out_addr_key = &bound_item->out.tx_prev_out_256->addr.data.hash_fast;
+                l_value = bound_item->out.tx_prev_out_256->header.value;
                 break;
             case TX_ITEM_TYPE_OUT_EXT: // 256
                 bound_item->out.tx_prev_out_ext_256 = l_tx_prev_out;
                 l_tx_in_from = bound_item->out.tx_prev_out_ext_256->addr;
+                l_prev_out_addr_key = &bound_item->out.tx_prev_out_ext_256->addr.data.hash_fast;
+                l_value = bound_item->out.tx_prev_out_ext_256->header.value;
+                l_token = bound_item->out.tx_prev_out_ext_256->token;
                 break;
             default:
                 l_err_num = -8;
@@ -2737,48 +2996,20 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
             if (l_err_num)
                 break;
 
-            // calculate hash of public key in current transaction
-            dap_chain_hash_fast_t l_hash_pkey;
-            // Get sign item
-            dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t*) dap_chain_datum_tx_item_get(a_tx, NULL,
-                    TX_ITEM_TYPE_SIG, NULL);
-            // Get sign from sign item
-            dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t*) l_tx_sig);
-            // Get public key from sign
-            size_t l_pkey_ser_size = 0;
-            const uint8_t *l_pkey_ser = dap_sign_get_pkey(l_sign, &l_pkey_ser_size);
-            // calculate hash from public key
-            dap_hash_fast(l_pkey_ser, l_pkey_ser_size, &l_hash_pkey);
-            // hash of public key in 'out' item of previous transaction
-
-            uint8_t *l_prev_out_addr_key = NULL;
-            switch (l_type) {
-                case TX_ITEM_TYPE_OUT:
-                    l_prev_out_addr_key = bound_item->out.tx_prev_out_256->addr.data.key; break;
-                case TX_ITEM_TYPE_OUT_OLD:
-                    l_prev_out_addr_key = bound_item->out.tx_prev_out->addr.data.key; break;
-                case TX_ITEM_TYPE_OUT_EXT:
-                    l_prev_out_addr_key = bound_item->out.tx_prev_out_ext_256->addr.data.key; break;
-                default: break;
-            }
-
             // 4. compare public key hashes in the signature of the current transaction and in the 'out' item of the previous transaction
-            if(memcmp(&l_hash_pkey, l_prev_out_addr_key, sizeof(dap_chain_hash_fast_t))) {
+            if (dap_hash_fast_is_blank(&l_hash_pkey)) {
+                // Get sign item
+                dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t*) dap_chain_datum_tx_item_get(a_tx, NULL,
+                        TX_ITEM_TYPE_SIG, NULL);
+                // Get sign from sign item
+                dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig(l_tx_sig);
+                // calculate hash from sign public key
+                dap_sign_get_pkey_hash(l_sign, &l_hash_pkey);
+            }
+            if (!dap_hash_fast_compare(&l_hash_pkey, l_prev_out_addr_key)) {
                 l_err_num = -9;
                 break;
             }
-
-            switch (l_type) {
-                case TX_ITEM_TYPE_OUT: // 256
-                    l_value = bound_item->out.tx_prev_out_256->header.value; break;
-                case TX_ITEM_TYPE_OUT_OLD:
-                    l_value = dap_chain_uint256_from(bound_item->out.tx_prev_out->header.value); break;
-                case TX_ITEM_TYPE_OUT_EXT: // 256
-                    l_value = bound_item->out.tx_prev_out_ext_256->header.value;
-                    l_token = bound_item->out.tx_prev_out_ext_256->token;
-                    break;
-                default: break;
-            }
         } else { // TX_ITEM_TYPE_IN_COND
             if(*(uint8_t *)l_tx_prev_out != TX_ITEM_TYPE_OUT_COND) {
                 l_err_num = -8;
@@ -2796,6 +3027,8 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
 
             dap_chain_tx_out_cond_t *l_tx_prev_out_cond = NULL;
             l_tx_prev_out_cond = (dap_chain_tx_out_cond_t *)l_tx_prev_out;
+            if (l_tx_prev_out_cond->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE)
+                l_main_ticker = l_token;
 
             bool l_owner = false;
             if (l_pkey_ser_size == l_prev_pkey_ser_size &&
@@ -2815,17 +3048,17 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
                 l_err_num = -13;
                 break;
             }
-            if (l_verificator->callback(a_ledger, l_tx_prev_out_cond, a_tx, l_owner) == false) {
-                l_err_num = -14;
+            if (l_verificator->callback(a_ledger, &l_tx_prev_hash, l_tx_prev_out_cond, a_tx, l_owner) == false) {
+                if (l_sub_tmp == DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK) {
+                    l_err_num = DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS;
+                } else {
+                    l_err_num = -14;
+                }
                 break;
             }
             // calculate sum of values from previous transactions
             bound_item->out.tx_prev_out_cond_256 = l_tx_prev_out_cond;
             l_value = l_tx_prev_out_cond->header.value;
-            l_token = NULL;
-        }
-        if (!l_token || !*l_token) {
-            l_token = l_item_out->cache_data.token_ticker;
         }
         if (! l_token || !*l_token ) {
             log_it(L_WARNING, "No token ticker found in previous transaction");
@@ -2901,6 +3134,13 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
     bool l_multichannel = false;
     if (HASH_COUNT(l_values_from_prev_tx) > 1) {
         l_multichannel = true;
+        if (HASH_COUNT(l_values_from_prev_tx) == 2 && !l_main_ticker) {
+            HASH_FIND_STR(l_values_from_cur_tx, PVT(a_ledger)->net->pub.native_ticker, l_value_cur);
+            if (l_value_cur) {
+                l_value_cur = l_value_cur->hh.next ? l_value_cur->hh.next : l_value_cur->hh.prev;
+                l_main_ticker = l_value_cur->token_ticker;
+            }
+        }
     } else {
         l_value_cur = DAP_NEW_Z(dap_chain_ledger_tokenizer_t);
         if(l_token)
@@ -2910,7 +3150,9 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
 
     // find 'out' items
     dap_list_t *l_list_out = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_OUT_ALL, NULL);
-    uint256_t l_value = {};
+    uint256_t l_value = {}, l_fee_value = {}, l_fee_sum = {};
+    dap_chain_addr_t l_fee_addr = {};
+    bool l_fee_check = dap_chain_net_tx_get_fee(PVT(a_ledger)->net->pub.id, &l_fee_value, &l_fee_addr);
     int l_item_idx = 0;
     for (l_list_tmp = l_list_out; l_list_tmp; l_list_tmp = dap_list_next(l_list_tmp), l_item_idx++) {
         dap_chain_tx_item_type_t l_type = *(uint8_t *)l_list_tmp->data;
@@ -2929,8 +3171,12 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
         case TX_ITEM_TYPE_OUT: { // 256
             dap_chain_tx_out_t *l_tx_out = (dap_chain_tx_out_t *)l_list_tmp->data;
             if (l_multichannel) { // token ticker is mandatory for multichannel transactions
-                l_err_num = -16;
-                break;
+                if (l_main_ticker)
+                    l_token = l_main_ticker;
+                else {
+                    l_err_num = -16;
+                    break;
+                }
             }
             l_value = l_tx_out->header.value;
             l_tx_out_to = l_tx_out->addr;
@@ -2949,14 +3195,19 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
         } break;
         case TX_ITEM_TYPE_OUT_COND: {
             dap_chain_tx_out_cond_t *l_tx_out = (dap_chain_tx_out_cond_t *)l_list_tmp->data;
-            if (l_multichannel) { // out_cond have no field .token
-                log_it(L_WARNING, "No conditional output support for multichannel transaction");
-                l_err_num = -18;
-                break;
+            if (l_multichannel) {
+                if (l_main_ticker)
+                    l_token = l_main_ticker;
+                else if (l_tx_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE)
+                    l_token = (char *)PVT(a_ledger)->net->pub.native_ticker;
+                else {
+                    log_it(L_WARNING, "No conditional output support for multichannel transaction");
+                    l_err_num = -18;
+                    break;
+                }
             }
             l_value = l_tx_out->header.value;
             l_list_tx_out = dap_list_append(l_list_tx_out, l_tx_out);
-            l_list_tx_out_cond = dap_list_append(l_list_tx_out_cond, l_tx_out);
         } break;
         default: {}
         }
@@ -2968,7 +3219,12 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
                 HASH_ADD_STR(l_values_from_cur_tx, token_ticker, l_value_cur);
             }
         }
-        SUM_256_256(l_value_cur->sum, l_value, &l_value_cur->sum);
+        if (SUM_256_256(l_value_cur->sum, l_value, &l_value_cur->sum)) {
+            debug_if(s_debug_more, L_WARNING, "Sum result overflow for tx_add_check with ticker %s",
+                                    l_value_cur->token_ticker);
+            l_err_num = -77;
+            break;
+        }
 
         // Get permissions for token
         l_token_item = NULL;
@@ -3009,8 +3265,12 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
                 break;
             }
         }
-    }
 
+        if (l_fee_check && !memcmp(&l_tx_out_to, &l_fee_addr, sizeof(dap_chain_addr_t)) &&
+                !dap_strcmp(l_value_cur->token_ticker, PVT(a_ledger)->net->pub.native_ticker)) {
+            SUM_256_256(l_fee_sum, l_value, &l_fee_sum);
+        }
+    }
 
     if ( l_list_out )
         dap_list_free(l_list_out);
@@ -3020,10 +3280,10 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
         HASH_ITER(hh, l_values_from_prev_tx, l_value_cur, l_tmp) {
             HASH_FIND_STR(l_values_from_cur_tx, l_value_cur->token_ticker, l_res);
             if (!l_res || !EQUAL_256(l_res->sum, l_value_cur->sum) ) {
-                if(s_debug_more) {
-                    char *l_balance = dap_chain_balance_print(l_res ? l_res->sum : uint256_0);
-                    char *l_balance_cur = dap_chain_balance_print(l_value_cur->sum);
-                    log_it(L_ERROR, "Sum of values of out items from current tx 256 (%s) is not equal outs from previous tx (%s) for token %s",
+                if (s_debug_more) {
+                    char *l_balance = dap_chain_balance_to_coins(l_res ? l_res->sum : uint256_0);
+                    char *l_balance_cur = dap_chain_balance_to_coins(l_value_cur->sum);
+                    log_it(L_ERROR, "Sum of values of out items from current tx (%s) is not equal outs from previous tx (%s) for token %s",
                             l_balance, l_balance_cur, l_value_cur->token_ticker);
                     DAP_DELETE(l_balance);
                     DAP_DELETE(l_balance_cur);
@@ -3034,6 +3294,16 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
         }
     }
 
+    // 7. Check the network fee
+    if (l_fee_check && compare256(l_fee_sum, l_fee_value) == -1) {
+        char *l_current_fee = dap_chain_balance_to_coins(l_fee_sum);
+        char *l_expected_fee = dap_chain_balance_to_coins(l_fee_value);
+        log_it(L_ERROR, "Fee value is invalid, expected %s pointed %s", l_expected_fee, l_current_fee);
+        l_err_num = -55;
+        DAP_DEL_Z(l_current_fee);
+        DAP_DEL_Z(l_expected_fee);
+    }
+
     HASH_ITER(hh, l_values_from_prev_tx, l_value_cur, l_tmp) {
         HASH_DEL(l_values_from_prev_tx, l_value_cur);
         DAP_DELETE(l_value_cur);
@@ -3047,10 +3317,7 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
     } else {
         *a_list_bound_items = l_list_bound_items;
     }
-    if (l_list_tx_out_cond && !l_err_num) {
-        l_err_num = s_check_out_cond_verificator_added(a_ledger, a_tx, l_list_tx_out_cond);
-        dap_list_free(l_list_tx_out_cond);
-    }
+
     if (!a_list_tx_out || l_err_num) {
         dap_list_free(l_list_tx_out);
     } else {
@@ -3072,19 +3339,20 @@ int dap_chain_ledger_tx_add_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *
         return -2;
     dap_list_t *l_list_bound_items = NULL;
     dap_list_t *l_list_tx_out = NULL;
+    dap_hash_fast_t l_tx_hash;
+    dap_hash_fast(a_tx, dap_chain_datum_tx_get_size(a_tx), &l_tx_hash);
 
     int l_ret_check;
-    if( (l_ret_check = dap_chain_ledger_tx_cache_check(
-             a_ledger, a_tx, false, &l_list_bound_items, &l_list_tx_out)) < 0){
-        if(s_debug_more)
-            log_it (L_DEBUG, "dap_chain_ledger_tx_add_check() tx not passed the check: code %d ",l_ret_check);
+    if( (l_ret_check = dap_chain_ledger_tx_cache_check(a_ledger, a_tx, &l_tx_hash, false,
+                                                       &l_list_bound_items, &l_list_tx_out)) < 0) {
+        debug_if(s_debug_more, L_DEBUG, "dap_chain_ledger_tx_add_check() tx not passed the check: code %d ", l_ret_check);
         return l_ret_check;
     }
-    dap_chain_hash_fast_t *l_tx_hash = dap_chain_node_datum_tx_calc_hash(a_tx);
-    char l_tx_hash_str[70];
-    dap_chain_hash_fast_to_str(l_tx_hash,l_tx_hash_str,sizeof(l_tx_hash_str));
-    if(s_debug_more)
-        log_it ( L_INFO, "dap_chain_ledger_tx_add_check() check passed for tx %s",l_tx_hash_str);
+    if(s_debug_more) {
+        char l_tx_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
+        dap_chain_hash_fast_to_str(&l_tx_hash, l_tx_hash_str, sizeof(l_tx_hash_str));
+        log_it ( L_INFO, "dap_chain_ledger_tx_add_check() check passed for tx %s", l_tx_hash_str);
+    }
     return 0;
 }
 
@@ -3096,15 +3364,14 @@ int dap_chain_ledger_tx_add_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *
  */
 static int s_balance_cache_update(dap_ledger_t *a_ledger, dap_ledger_wallet_balance_t *a_balance)
 {
-    char *l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_BALANCES_STR);
-
-    if ( dap_global_db_set(l_gdb_group, a_balance->key, &a_balance->balance, sizeof(uint256_t), false, NULL, NULL) ) {
-        if(s_debug_more)
-            log_it(L_WARNING, "Ledger cache mismatch");
-        return -1;
+    if (PVT(a_ledger)->cached) {
+        char *l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_BALANCES_STR);
+        if (!dap_global_db_set(l_gdb_group, a_balance->key, &a_balance->balance, sizeof(uint256_t), false, NULL, NULL)) {
+            debug_if(s_debug_more, L_WARNING, "Ledger cache mismatch");
+            return -1;
+        }
+        DAP_DELETE(l_gdb_group);
     }
-
-    DAP_DELETE(l_gdb_group);
     /* Notify the world*/
     struct json_object *l_json = wallet_info_json_collect(a_ledger, a_balance);
     dap_notify_server_send_mt(json_object_get_string(l_json));
@@ -3112,7 +3379,7 @@ static int s_balance_cache_update(dap_ledger_t *a_ledger, dap_ledger_wallet_bala
     return 0;
 }
 
-int sort_ledger_tx_item(dap_chain_ledger_tx_item_t* a, dap_chain_ledger_tx_item_t* b)
+static int s_sort_ledger_tx_item(dap_chain_ledger_tx_item_t* a, dap_chain_ledger_tx_item_t* b)
 {
     return a->tx->header.ts_created == b->tx->header.ts_created ? 0 :
                 a->tx->header.ts_created < b->tx->header.ts_created ? -1 : 1;
@@ -3179,29 +3446,18 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d
             l_ledger_priv->tps_timer = NULL;
     }
     bool l_from_threshold = a_from_threshold;
-    if (!l_ledger_priv->load_mode && !a_from_threshold) {
-        HASH_VALUE(a_tx_hash, sizeof(*a_tx_hash), l_hash_value);
-        if(a_safe_call) pthread_rwlock_rdlock(&l_ledger_priv->ledger_rwlock);
-        HASH_FIND_BYHASHVALUE(hh, l_ledger_priv->ledger_items, a_tx_hash, sizeof(dap_chain_hash_fast_t), l_hash_value, l_item_tmp);
-        if(a_safe_call) pthread_rwlock_unlock(&l_ledger_priv->ledger_rwlock);
-    }
-    char l_tx_hash_str[70];
+    char l_tx_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
     dap_chain_hash_fast_to_str(a_tx_hash, l_tx_hash_str, sizeof(l_tx_hash_str));
-    if (l_item_tmp) {     // transaction already present in the cache list
-        if(s_debug_more)
-            log_it(L_WARNING, "Transaction %s already present in the cache", l_tx_hash_str);
-        return -1;
-    }
 
     int l_ret_check;
     l_item_tmp = NULL;
-    if( (l_ret_check = dap_chain_ledger_tx_cache_check(
-             a_ledger, a_tx, a_from_threshold, &l_list_bound_items, &l_list_tx_out)) < 0) {
+    if( (l_ret_check = dap_chain_ledger_tx_cache_check(a_ledger, a_tx, a_tx_hash, a_from_threshold,
+                                                       &l_list_bound_items, &l_list_tx_out)) < 0) {
         if (l_ret_check == DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS ||
                 l_ret_check == DAP_CHAIN_CS_VERIFY_CODE_TX_NO_EMISSION) {
             if (!l_from_threshold) {
-                if (!l_hash_value)
-                    HASH_VALUE(a_tx_hash, sizeof(*a_tx_hash), l_hash_value);
+                unsigned l_hash_value = 0;
+                HASH_VALUE(a_tx_hash, sizeof(*a_tx_hash), l_hash_value);
                 pthread_rwlock_rdlock(&l_ledger_priv->threshold_txs_rwlock);
                 HASH_FIND_BYHASHVALUE(hh, l_ledger_priv->threshold_txs, a_tx_hash, sizeof(*a_tx_hash), l_hash_value, l_item_tmp);
                 unsigned long long l_threshold_txs_count = HASH_COUNT(l_ledger_priv->threshold_txs);
@@ -3230,11 +3486,6 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d
     if(s_debug_more)
         log_it ( L_DEBUG, "dap_chain_ledger_tx_add() check passed for tx %s",l_tx_hash_str);
 
-    char l_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX]      = { '\0'},
-         l_token_ticker_old[DAP_CHAIN_TICKER_SIZE_MAX]  = { '\0'};
-
-    //char *l_token_ticker = NULL, *l_token_ticker_old = NULL;
-    bool l_multichannel = false;
     // Mark 'out' items in cache if they were used & delete previous transactions from cache if it need
     // find all bound pairs 'in' and 'out'
     dap_list_t *l_list_tmp = l_list_bound_items;
@@ -3242,10 +3493,10 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d
     size_t l_cache_size = sizeof(dap_store_obj_t) * (l_outs_used + 1);
     dap_store_obj_t *l_cache_used_outs = DAP_NEW_Z_SIZE(dap_store_obj_t, l_cache_size);
     char *l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_TXS_STR);
-    char *l_ticker_trl = NULL, *l_ticker_old_trl = NULL;
-    bool l_stake_updated = false;
-    // Update balance: deducts
+    char *l_main_token_ticker = NULL, *l_cur_token_ticker = NULL;
+    bool l_ticker_in_heap = false;
 
+    // Update balance: deducts
     for (int i = 1; l_list_tmp; i++) {
         dap_chain_ledger_tx_bound_t *bound_item = l_list_tmp->data;
         void *l_item_in = *(void **)&bound_item->in;
@@ -3253,22 +3504,43 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d
         if (l_type == TX_ITEM_TYPE_IN) {
             dap_chain_tx_in_t *l_tx_in = bound_item->in.tx_cur_in;
             if (dap_hash_fast_is_blank(&l_tx_in->header.tx_prev_hash)) { // It's the emission behind
-                // Mark it as used with base tx hash
-                bound_item->item_emission->tx_used_out = *a_tx_hash;
-                // Mirror it in cache
-                char *l_hash_str = dap_chain_hash_fast_to_str_new(&bound_item->item_emission->datum_token_emission_hash);
-                size_t l_emission_size = bound_item->item_emission->datum_token_emission_size;
-                char *l_ems_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_EMISSIONS_STR);
-                size_t l_cache_size = l_emission_size + sizeof(dap_hash_fast_t);
-                uint8_t *l_cache = DAP_NEW_Z_SIZE(uint8_t, l_cache_size);
-                memcpy(l_cache, a_tx_hash, sizeof(dap_hash_fast_t));
-                memcpy(l_cache + sizeof(dap_hash_fast_t), bound_item->item_emission->datum_token_emission, l_emission_size);
-                if ( dap_global_db_set(l_ems_group, l_hash_str, l_cache, l_cache_size, false, NULL, NULL) ) {
-                    log_it(L_WARNING, "Ledger cache mismatch");
+                // Find token ticker for emission
+                dap_chain_tx_token_t * l_tx_token = (dap_chain_tx_token_t *) dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_TOKEN, NULL);
+                if (l_tx_token)
+                     l_main_token_ticker = l_tx_token->header.ticker;
+                else {
+                    log_it(L_ERROR, "No token item with blank prev tx hash");
+                    break;
+                }
+                if (bound_item->tx_prev) { // It's the stake lock emission
+                    dap_chain_ledger_token_item_t *l_token_item = NULL;
+                    pthread_rwlock_rdlock(&l_ledger_priv->tokens_rwlock);
+                    HASH_FIND_STR(l_ledger_priv->tokens, l_main_token_ticker, l_token_item);
+                    pthread_rwlock_unlock(&l_ledger_priv->tokens_rwlock);
+                    if (!l_token_item){
+                        log_it(L_ERROR, "No token item found for token %s", l_main_token_ticker);
+                        break;
+                    }
+                    if (!IS_ZERO_256(l_token_item->total_supply)) {
+                        dap_chain_tx_out_t *l_tx_out = (dap_chain_tx_out_t*)dap_chain_datum_tx_item_get(a_tx, 0, TX_ITEM_TYPE_OUT, 0);
+                        SUBTRACT_256_256(l_token_item->current_supply, l_tx_out->header.value, &l_token_item->current_supply);
+                        char *l_balance = dap_chain_balance_print(l_token_item->current_supply);
+                        log_it(L_DEBUG, "New current supply %s for token %s", l_balance, l_token_item->ticker);
+                        DAP_DEL_Z(l_balance);
+                        if (PVT(a_ledger)->cached)
+                            s_ledger_token_cache_update(a_ledger, l_token_item);
+                    }
+                    bound_item->stake_lock_item->tx_used_out = *a_tx_hash;
+                    if (PVT(a_ledger)->cached)
+                        // Mirror it in cache
+                        s_ledger_stake_lock_cache_update(a_ledger, bound_item->stake_lock_item);
+                } else {    // It's the general emission
+                    // Mark it as used with base tx hash
+                    bound_item->item_emission->tx_used_out = *a_tx_hash;
+                    if (PVT(a_ledger)->cached)
+                        // Mirror it in cache
+                        s_ledger_emission_cache_update(a_ledger, bound_item->item_emission);
                 }
-                DAP_DELETE(l_hash_str);
-                DAP_DELETE(l_cache);
-                DAP_DELETE(l_ems_group);
                 l_list_tmp = dap_list_next(l_list_tmp);
                 i--;    // Do not calc this output with tx used items
                 l_outs_used--;
@@ -3276,16 +3548,9 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d
             }
         }
         dap_chain_ledger_tx_item_t *l_prev_item_out = bound_item->item_out;
-
-        if ( *l_prev_item_out->cache_data.token_ticker )
-            l_ticker_trl = dap_stpcpy(l_token_ticker, l_prev_item_out->cache_data.token_ticker);
-        else
-            l_ticker_trl = dap_stpcpy(l_token_ticker, bound_item->out.tx_prev_out_ext_256->token);
-
-        if (!l_multichannel && l_ticker_old_trl && strcmp(l_token_ticker, l_token_ticker_old)) {
-            l_multichannel = true;
-        }
-        l_ticker_old_trl = dap_stpcpy(l_token_ticker_old, l_token_ticker);
+        l_cur_token_ticker = l_prev_item_out->cache_data.token_ticker;
+        if (!l_main_token_ticker)
+            l_main_token_ticker = l_cur_token_ticker;
         int l_tx_prev_out_used_idx;
         if (l_type == TX_ITEM_TYPE_IN) {
             dap_chain_tx_in_t *l_tx_in = bound_item->in.tx_cur_in;
@@ -3295,41 +3560,40 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d
             void *l_item_out = *(void **)&bound_item->out;
             dap_chain_tx_item_type_t l_out_type = *(uint8_t *)l_item_out;
             switch (l_out_type) {
-                case TX_ITEM_TYPE_OUT: l_addr = &bound_item->out.tx_prev_out_256->addr; break;
-                case TX_ITEM_TYPE_OUT_OLD: l_addr = &bound_item->out.tx_prev_out->addr; break;
-                case TX_ITEM_TYPE_OUT_EXT: l_addr = &bound_item->out.tx_prev_out_ext_256->addr; break;
-                default:
-                    log_it(L_DEBUG, "Unknown item type %d", l_out_type);
-                    break;
+            case TX_ITEM_TYPE_OUT:
+                l_addr = &bound_item->out.tx_prev_out_256->addr;
+                l_value = bound_item->out.tx_prev_out_256->header.value;
+                break;
+            case TX_ITEM_TYPE_OUT_OLD:
+                l_addr = &bound_item->out.tx_prev_out->addr;
+                l_value = GET_256_FROM_64(bound_item->out.tx_prev_out->header.value);
+                break;
+            case TX_ITEM_TYPE_OUT_EXT:
+                l_addr = &bound_item->out.tx_prev_out_ext_256->addr;
+                l_value = bound_item->out.tx_prev_out_ext_256->header.value;
+                l_cur_token_ticker = bound_item->out.tx_prev_out_ext_256->token;
+                break;
+            default:
+                log_it(L_DEBUG, "Unknown item type %d", l_out_type);
+                break;
             }
             char *l_addr_str = dap_chain_addr_to_str(l_addr);
-            char *l_wallet_balance_key = dap_strjoin(" ", l_addr_str, l_token_ticker, (char*)NULL);
+            char *l_wallet_balance_key = dap_strjoin(" ", l_addr_str, l_cur_token_ticker, (char*)NULL);
             pthread_rwlock_rdlock(&PVT(a_ledger)->balance_accounts_rwlock);
             HASH_FIND_STR(PVT(a_ledger)->balance_accounts, l_wallet_balance_key, wallet_balance);
             pthread_rwlock_unlock(&PVT(a_ledger)->balance_accounts_rwlock);
             if (wallet_balance) {
-                switch (l_out_type) {
-                    case TX_ITEM_TYPE_OUT: l_value = bound_item->out.tx_prev_out_256->header.value; break;
-                    case TX_ITEM_TYPE_OUT_OLD: l_value = GET_256_FROM_64(bound_item->out.tx_prev_out->header.value); break;
-                    case TX_ITEM_TYPE_OUT_EXT: l_value = bound_item->out.tx_prev_out_ext_256->header.value; break;
-                    default:
-                        log_it(L_DEBUG, "Unknown item type %d", l_out_type);
-                    break;
-                }
-
                 if(s_debug_more) {
                     char *l_balance = dap_chain_balance_print(l_value);
                     log_it(L_DEBUG,"SPEND %s from addr: %s", l_balance, l_wallet_balance_key);
                     DAP_DELETE(l_balance);
                 }
-
                 SUBTRACT_256_256(wallet_balance->balance, l_value, &wallet_balance->balance);
-
                 // Update the cache
                 s_balance_cache_update(a_ledger, wallet_balance);
             } else {
                 if(s_debug_more)
-                    log_it(L_ERROR,"!!! Attempt to SPEND from some non-existent balance !!!: %s %s", l_addr_str, l_token_ticker);
+                    log_it(L_ERROR,"!!! Attempt to SPEND from some non-existent balance !!!: %s %s", l_addr_str, l_cur_token_ticker);
             }
             DAP_DELETE(l_addr_str);
             DAP_DELETE(l_wallet_balance_key);
@@ -3340,19 +3604,19 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d
             dap_chain_tx_in_cond_t *l_tx_in_cond = bound_item->in.tx_cur_in_cond;
             /// Mark 'out' item in cache because it used
             l_tx_prev_out_used_idx = l_tx_in_cond->header.tx_out_prev_idx;
-            // Update stakes if any
             dap_chain_tx_out_cond_t *l_cond = bound_item->out.tx_prev_out_cond_256;
-            if (l_cond->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE) {
-                dap_chain_ledger_verificator_t *l_verificator;
-                int l_tmp = (int)DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE_UPDATE;
-                pthread_rwlock_rdlock(&s_verificators_rwlock);
-                HASH_FIND_INT(s_verificators, &l_tmp, l_verificator);
-                pthread_rwlock_unlock(&s_verificators_rwlock);
-                if (l_verificator && l_verificator->callback) {
-                    l_verificator->callback(a_ledger, l_cond, a_tx, true);
-                }
-                l_stake_updated = true;
-            }
+            if (l_cond->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE)
+                l_main_token_ticker = l_prev_item_out->cache_data.token_ticker;
+            if (l_cond->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE)
+                l_cur_token_ticker = (char *)PVT(a_ledger)->net->pub.native_ticker;
+            // Update service items if any
+            dap_chain_ledger_verificator_t *l_verificator;
+            int l_tmp = l_cond->header.subtype;
+            pthread_rwlock_rdlock(&s_verificators_rwlock);
+            HASH_FIND_INT(s_verificators, &l_tmp, l_verificator);
+            pthread_rwlock_unlock(&s_verificators_rwlock);
+            if (l_verificator && l_verificator->callback_added)
+                l_verificator->callback_added(a_ledger, a_tx, l_cond);
         }
         // add a used output
         l_prev_item_out->cache_data.tx_hash_spent_fast[l_tx_prev_out_used_idx] = *a_tx_hash;
@@ -3363,8 +3627,9 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d
         uint8_t *l_tx_cache = DAP_NEW_Z_SIZE(uint8_t, l_tx_cache_sz);
         memcpy(l_tx_cache, &l_prev_item_out->cache_data, sizeof(l_prev_item_out->cache_data));
         memcpy(l_tx_cache + sizeof(l_prev_item_out->cache_data), l_prev_item_out->tx, l_tx_size);
+        char *l_tx_i_hash = dap_chain_hash_fast_to_str_new(&l_prev_item_out->tx_hash_fast);
         l_cache_used_outs[i] = (dap_store_obj_t) {
-                .key        = dap_chain_hash_fast_to_str_new(&l_prev_item_out->tx_hash_fast),
+                .key        = l_tx_i_hash,
                 .value      = l_tx_cache,
                 .value_len  = l_tx_cache_sz,
                 .group      = l_gdb_group
@@ -3372,9 +3637,13 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d
 
         // delete previous transactions from cache because all out is used
         if(l_prev_item_out->cache_data.n_outs_used == l_prev_item_out->cache_data.n_outs) {
-            dap_chain_hash_fast_t l_tx_prev_hash_to_del = bound_item->tx_prev_hash_fast;
+            if (l_main_token_ticker == l_prev_item_out->cache_data.token_ticker) {
+                l_main_token_ticker = dap_strdup(l_prev_item_out->cache_data.token_ticker);
+                l_ticker_in_heap = true;
+            }
+            dap_chain_hash_fast_t l_tx_prev_hash_to_del = bound_item->tx_prev_hash;
             // remove from memory ledger
-            int res = dap_chain_ledger_tx_remove(a_ledger, &l_tx_prev_hash_to_del);
+            int res = dap_chain_ledger_tx_remove(a_ledger, &l_tx_prev_hash_to_del, a_tx->header.ts_created);
             if(res == -2) {
                 if(s_debug_more) {
                     char * l_tx_prev_hash_str = dap_chain_hash_fast_to_str_new(&l_tx_prev_hash_to_del);
@@ -3400,108 +3669,86 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d
         l_list_tmp = dap_list_next(l_list_tmp);
     }
 
-    // Try to find token ticker if wasn't
-    if (!l_ticker_trl){
-        //int l_base_tx_count = 0;
-        //dap_list_t *l_base_tx_list = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_TOKEN, &l_base_tx_count );
-        //if (l_base_tx_count >=1  && l_base_tx_list){
-        dap_chain_tx_token_t * l_tx_token = (dap_chain_tx_token_t *) dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_TOKEN, NULL);
-        if (l_tx_token)
-            l_ticker_trl = dap_stpcpy(l_token_ticker, l_tx_token->header.ticker);
-        //}
-    }
-
     //Update balance : raise
+    bool l_multichannel = false;
     for (dap_list_t *l_tx_out = l_list_tx_out; l_tx_out; l_tx_out = dap_list_next(l_tx_out)) {
+        if (!l_tx_out->data) {
+            debug_if(s_debug_more, L_WARNING, "Can't detect tx ticker or matching output, can't append balances cache");
+            continue;
+        }
         dap_chain_tx_item_type_t l_type = *(uint8_t *)l_tx_out->data;
         if (l_type == TX_ITEM_TYPE_OUT_COND) {
-            // Update stakes if any
+            // Update service items if any
             dap_chain_tx_out_cond_t *l_cond = (dap_chain_tx_out_cond_t *)l_tx_out->data;
-            if (l_cond->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE && !l_stake_updated) {
-                dap_chain_ledger_verificator_t *l_verificator;
-                int l_tmp = (int)DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE_UPDATE;
-                pthread_rwlock_rdlock(&s_verificators_rwlock);
-                HASH_FIND_INT(s_verificators, &l_tmp, l_verificator);
-                pthread_rwlock_unlock(&s_verificators_rwlock);
-                if (l_verificator && l_verificator->callback) {
-                    l_verificator->callback(a_ledger, NULL, a_tx, true);
-                }
-            }
+            dap_chain_ledger_verificator_t *l_verificator;
+            int l_tmp = l_cond->header.subtype;
+            pthread_rwlock_rdlock(&s_verificators_rwlock);
+            HASH_FIND_INT(s_verificators, &l_tmp, l_verificator);
+            pthread_rwlock_unlock(&s_verificators_rwlock);
+            if (l_verificator && l_verificator->callback_added)
+                l_verificator->callback_added(a_ledger, a_tx, NULL);
             continue;   // balance raise will be with next conditional transaction
         }
-        dap_chain_tx_out_old_t *l_out_item = NULL;
-        dap_chain_tx_out_t *l_out_item_256 = NULL;
-        dap_chain_tx_out_ext_t *l_out_item_ext_256 = NULL;
 
+        dap_chain_addr_t *l_addr;
+        uint256_t l_value = {};
         switch (l_type) {
-            case TX_ITEM_TYPE_OUT: l_out_item_256 = (dap_chain_tx_out_t *)l_tx_out->data; break;
-            case TX_ITEM_TYPE_OUT_OLD: l_out_item = (dap_chain_tx_out_old_t *)l_tx_out->data; break;
-            case TX_ITEM_TYPE_OUT_EXT: l_out_item_ext_256 = (dap_chain_tx_out_ext_t *)l_tx_out->data; break;
-            default:
-                log_it(L_DEBUG, "Unknown item type %d", l_type);
-                break;
+        case TX_ITEM_TYPE_OUT: {
+            dap_chain_tx_out_t *l_out_item_256 = (dap_chain_tx_out_t *)l_tx_out->data;
+            l_addr = &l_out_item_256->addr;
+            l_value = l_out_item_256->header.value;
+            l_cur_token_ticker = l_main_token_ticker;
+        } break;
+        case TX_ITEM_TYPE_OUT_OLD: {
+            dap_chain_tx_out_old_t *l_out_item = (dap_chain_tx_out_old_t *)l_tx_out->data;
+            l_addr = &l_out_item->addr;
+            l_value = GET_256_FROM_64(l_out_item->header.value);
+            l_cur_token_ticker = l_main_token_ticker;
+        } break;
+        case TX_ITEM_TYPE_OUT_EXT: {
+            dap_chain_tx_out_ext_t *l_out_item_ext_256 = (dap_chain_tx_out_ext_t *)l_tx_out->data;
+            l_addr = &l_out_item_ext_256->addr;
+            l_value = l_out_item_ext_256->header.value;
+            l_cur_token_ticker = l_out_item_ext_256->token;
+            l_multichannel = true;
+        } break;
+        default:
+            log_it(L_DEBUG, "Unknown item type %d", l_type);
+            break;
         }
-
-        if ((l_out_item||l_out_item_256||l_out_item_ext_256) && l_ticker_trl) {
-            dap_chain_addr_t *l_addr;
-            switch (l_type) {
-                case TX_ITEM_TYPE_OUT: l_addr = &l_out_item_256->addr; break;
-                case TX_ITEM_TYPE_OUT_OLD: l_addr = &l_out_item->addr; break;
-                case TX_ITEM_TYPE_OUT_EXT: l_addr = &l_out_item_ext_256->addr; break;
-                default:
-                    log_it(L_DEBUG, "Unknown item type %d", l_type);
-                    break;
-            }
-            char *l_addr_str = dap_chain_addr_to_str(l_addr);
-            dap_ledger_wallet_balance_t *wallet_balance = NULL;
-            if (l_multichannel) {
-                l_ticker_trl = dap_stpcpy(l_token_ticker, l_out_item_ext_256->token);
-            }
-            char *l_wallet_balance_key = dap_strjoin(" ", l_addr_str, l_token_ticker, (char*)NULL);
-            uint256_t l_value_256 = {};
-            switch (l_type) {
-                case TX_ITEM_TYPE_OUT: l_value_256 = l_out_item_256->header.value; break; // _256
-                case TX_ITEM_TYPE_OUT_OLD: l_value_256 = GET_256_FROM_64(l_out_item->header.value); break;
-                case TX_ITEM_TYPE_OUT_EXT: l_value_256 = l_out_item_ext_256->header.value; break; // _256
-                default:
-                    log_it(L_DEBUG, "Unknown item type %d", l_type);
-                    break;
-            }
-
-            if(s_debug_more) {
-                char *l_balance = dap_chain_balance_print(l_value_256);
-                log_it(L_DEBUG, "GOT %s to addr: %s", l_balance, l_wallet_balance_key);
-                DAP_DELETE(l_balance);
-            }
-            pthread_rwlock_rdlock(&l_ledger_priv->balance_accounts_rwlock);
-            HASH_FIND_STR(PVT(a_ledger)->balance_accounts, l_wallet_balance_key, wallet_balance);
-            pthread_rwlock_unlock(&l_ledger_priv->balance_accounts_rwlock);
-            if (wallet_balance) {
-                //if(s_debug_more)
-                //    log_it(L_DEBUG, "Balance item is present in cache");
-                SUM_256_256(wallet_balance->balance, l_value_256, &wallet_balance->balance);
-                DAP_DELETE (l_wallet_balance_key);
-                // Update the cache
-                s_balance_cache_update(a_ledger, wallet_balance);
-            } else {
-                wallet_balance = DAP_NEW_Z(dap_ledger_wallet_balance_t);
-                wallet_balance->key = l_wallet_balance_key;
-                strcpy(wallet_balance->token_ticker, l_token_ticker);
-                SUM_256_256(wallet_balance->balance, l_value_256, &wallet_balance->balance);
-                if(s_debug_more)
-                    log_it(L_DEBUG, "Create new balance item: %s %s", l_addr_str, l_token_ticker);
-                pthread_rwlock_wrlock(&l_ledger_priv->balance_accounts_rwlock);
-                HASH_ADD_KEYPTR(hh, PVT(a_ledger)->balance_accounts, wallet_balance->key,
-                                strlen(l_wallet_balance_key), wallet_balance);
-                pthread_rwlock_unlock(&l_ledger_priv->balance_accounts_rwlock);
-                // Add it to cache
-                s_balance_cache_update(a_ledger, wallet_balance);
-            }
-            DAP_DELETE (l_addr_str);
+        char *l_addr_str = dap_chain_addr_to_str(l_addr);
+        dap_ledger_wallet_balance_t *wallet_balance = NULL;
+        char *l_wallet_balance_key = dap_strjoin(" ", l_addr_str, l_cur_token_ticker, (char*)NULL);
+        if(s_debug_more) {
+            char *l_balance = dap_chain_balance_print(l_value);
+            log_it(L_DEBUG, "GOT %s to addr: %s", l_balance, l_wallet_balance_key);
+            DAP_DELETE(l_balance);
+        }
+        pthread_rwlock_rdlock(&l_ledger_priv->balance_accounts_rwlock);
+        HASH_FIND_STR(PVT(a_ledger)->balance_accounts, l_wallet_balance_key, wallet_balance);
+        pthread_rwlock_unlock(&l_ledger_priv->balance_accounts_rwlock);
+        if (wallet_balance) {
+            //if(s_debug_more)
+            //    log_it(L_DEBUG, "Balance item is present in cache");
+            SUM_256_256(wallet_balance->balance, l_value, &wallet_balance->balance);
+            DAP_DELETE (l_wallet_balance_key);
+            // Update the cache
+            s_balance_cache_update(a_ledger, wallet_balance);
         } else {
+            wallet_balance = DAP_NEW_Z(dap_ledger_wallet_balance_t);
+            wallet_balance->key = l_wallet_balance_key;
+            strcpy(wallet_balance->token_ticker, l_cur_token_ticker);
+            SUM_256_256(wallet_balance->balance, l_value, &wallet_balance->balance);
             if(s_debug_more)
-                log_it(L_WARNING, "Can't detect tx ticker or matching output, can't append balances cache");
+                log_it(L_DEBUG, "Create new balance item: %s %s", l_addr_str, l_cur_token_ticker);
+            pthread_rwlock_wrlock(&l_ledger_priv->balance_accounts_rwlock);
+            HASH_ADD_KEYPTR(hh, PVT(a_ledger)->balance_accounts, wallet_balance->key,
+                            strlen(l_wallet_balance_key), wallet_balance);
+            pthread_rwlock_unlock(&l_ledger_priv->balance_accounts_rwlock);
+            // Add it to cache
+            s_balance_cache_update(a_ledger, wallet_balance);
         }
+        DAP_DELETE (l_addr_str);
     }
 
     // add transaction to the cache list
@@ -3510,57 +3757,43 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d
     size_t l_tx_size = dap_chain_datum_tx_get_size(a_tx);
     l_tx_item->tx = DAP_DUP_SIZE(a_tx, l_tx_size);
     l_tx_item->cache_data.ts_created = dap_time_now(); // Time of transasction added to ledger
-    dap_list_t *l_tist_tmp = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_OUT_ALL, &l_tx_item->cache_data.n_outs);
-    // If debug mode dump the UTXO
-    if (dap_log_level_get() == L_DEBUG && s_debug_more) {
-        dap_list_t *it = l_tist_tmp;
-        for (int i = 0; i < l_tx_item->cache_data.n_outs; i++) {
-            dap_chain_tx_out_old_t *l_tx_out = it->data;
-            if (l_tx_out->header.type != TX_ITEM_TYPE_OUT_OLD)
-                continue;
-            char * l_tx_out_addr_str = dap_chain_addr_to_str( &l_tx_out->addr );
-            log_it(L_DEBUG, "Added tx out to %s", l_tx_out_addr_str);
-            DAP_DELETE (l_tx_out_addr_str);
-            it = it->next;
-        }
-    }
+    int l_outs_count = 0;
+    dap_list_t *l_tist_tmp = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_OUT_ALL, &l_outs_count);
+    l_tx_item->cache_data.n_outs = l_outs_count;
+    // TODO: dump the UTXO in debug mode if need
+
     if(l_tist_tmp)
         dap_list_free(l_tist_tmp);
-    if (!l_ticker_trl) { //No token ticker in previous txs
-        if(s_debug_more)
-            log_it(L_DEBUG, "No token ticker in previous txs");
-        dap_chain_tx_token_t *l_token = (dap_chain_tx_token_t *)dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_TOKEN, NULL);
-        l_ticker_trl = l_token
-                ? dap_stpcpy(l_token_ticker, l_token->header.ticker)
-                : NULL;
-        }
-    if (l_ticker_trl && !l_multichannel)
-        dap_stpcpy(l_tx_item->cache_data.token_ticker, l_token_ticker);
-
-    if (!l_hash_value)
-        HASH_VALUE(a_tx_hash, sizeof(*a_tx_hash), l_hash_value);
+    if (l_main_token_ticker) {
+        dap_stpcpy(l_tx_item->cache_data.token_ticker, l_main_token_ticker);
+        if (l_ticker_in_heap)
+            DAP_DELETE(l_main_token_ticker);
+    }
+    else
+        debug_if(s_debug_more, L_ERROR, "No token ticker in previous txs");
+    l_tx_item->cache_data.multichannel = l_multichannel;
     if(a_safe_call) pthread_rwlock_wrlock(&l_ledger_priv->ledger_rwlock);
-    HASH_ADD_BYHASHVALUE_INORDER(hh, l_ledger_priv->ledger_items, tx_hash_fast, sizeof(dap_chain_hash_fast_t),
-                                 l_hash_value, l_tx_item, sort_ledger_tx_item); // tx_hash_fast: name of key field
+    HASH_ADD_INORDER(hh, l_ledger_priv->ledger_items, tx_hash_fast, sizeof(dap_chain_hash_fast_t),
+                         l_tx_item, s_sort_ledger_tx_item); // tx_hash_fast: name of key field
     if(a_safe_call) pthread_rwlock_unlock(&l_ledger_priv->ledger_rwlock);
     // Count TPS
     clock_gettime(CLOCK_REALTIME, &l_ledger_priv->tps_end_time);
     l_ledger_priv->tps_count++;
-    // Add it to cache
-    size_t l_tx_cache_sz = l_tx_size + sizeof(l_tx_item->cache_data);
-    uint8_t *l_tx_cache = DAP_NEW_STACK_SIZE(uint8_t, l_tx_cache_sz);
-    memcpy(l_tx_cache, &l_tx_item->cache_data, sizeof(l_tx_item->cache_data));
-    memcpy(l_tx_cache + sizeof(l_tx_item->cache_data), a_tx, l_tx_size);
-    l_cache_used_outs[0] = (dap_store_obj_t) {
-            .key        = l_tx_hash_str,
-            .value      = l_tx_cache,
-            .value_len  = l_tx_cache_sz,
-            .group      = l_gdb_group
-    };
-    // Apply it with single DB transaction
-    if ( dap_global_db_set_raw(l_cache_used_outs, l_outs_used + 1,NULL,NULL) != 0) {
-        if(s_debug_more)
-            log_it(L_WARNING, "Ledger cache mismatch");
+    if (PVT(a_ledger)->cached) {
+        // Add it to cache
+        size_t l_tx_cache_sz = l_tx_size + sizeof(l_tx_item->cache_data);
+        uint8_t *l_tx_cache = DAP_NEW_STACK_SIZE(uint8_t, l_tx_cache_sz);
+        memcpy(l_tx_cache, &l_tx_item->cache_data, sizeof(l_tx_item->cache_data));
+        memcpy(l_tx_cache + sizeof(l_tx_item->cache_data), a_tx, l_tx_size);
+        l_cache_used_outs[0] = (dap_store_obj_t) {
+                .key        = l_tx_hash_str,
+                .value      = l_tx_cache,
+                .value_len  = l_tx_cache_sz,
+                .group      = l_gdb_group
+        };
+        // Apply it with single DB transaction
+        if (dap_global_db_set_raw(l_cache_used_outs, l_outs_used + 1, NULL, NULL))
+            debug_if(s_debug_more, L_WARNING, "Ledger cache mismatch");
     }
     if (!a_from_threshold)
         s_threshold_txs_proc(a_ledger);
@@ -3627,7 +3860,7 @@ int dap_chain_ledger_tx_load(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx,
  *
  * return 1 OK, -1 error, -2 tx_hash not found
  */
-int dap_chain_ledger_tx_remove(dap_ledger_t *a_ledger, dap_chain_hash_fast_t *a_tx_hash)
+int dap_chain_ledger_tx_remove(dap_ledger_t *a_ledger, dap_chain_hash_fast_t *a_tx_hash, dap_time_t a_spent_time)
 {
     if(!a_tx_hash)
         return -1;
@@ -3640,12 +3873,14 @@ int dap_chain_ledger_tx_remove(dap_ledger_t *a_ledger, dap_chain_hash_fast_t *a_
     HASH_FIND_BYHASHVALUE(hh, l_ledger_priv->ledger_items, a_tx_hash, sizeof(dap_chain_hash_fast_t), l_hash_value, l_item_tmp);
     if(l_item_tmp != NULL) {
         HASH_DEL(l_ledger_priv->ledger_items, l_item_tmp);
-        // Remove it from cache
-        char *l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_TXS_STR);
-        char *l_tx_hash_str = dap_chain_hash_fast_to_str_new(a_tx_hash);
-        dap_global_db_del(l_gdb_group, l_tx_hash_str, NULL, NULL);
-        DAP_DELETE(l_tx_hash_str);
-        DAP_DELETE(l_gdb_group);
+        if (PVT(a_ledger)->cached) {
+            // Remove it from cache
+            char *l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_TXS_STR);
+            char *l_tx_hash_str = dap_chain_hash_fast_to_str_new(a_tx_hash);
+            dap_global_db_del(l_gdb_group, l_tx_hash_str, NULL, NULL);
+            DAP_DELETE(l_tx_hash_str);
+            DAP_DELETE(l_gdb_group);
+        }
         l_ret = 1;
         dap_chain_ledger_tx_spent_item_t *l_item_used;
         HASH_FIND_BYHASHVALUE(hh, l_ledger_priv->spent_items, a_tx_hash, sizeof(dap_chain_hash_fast_t), l_hash_value, l_item_used);
@@ -3653,19 +3888,22 @@ int dap_chain_ledger_tx_remove(dap_ledger_t *a_ledger, dap_chain_hash_fast_t *a_
             l_item_used = DAP_NEW_Z(dap_chain_ledger_tx_spent_item_t);
             l_item_used->tx_hash_fast = *a_tx_hash;
             int l_len = strnlen(l_item_tmp->cache_data.token_ticker, DAP_CHAIN_TICKER_SIZE_MAX);
-            strncpy(l_item_used->token_ticker, l_item_tmp->cache_data.token_ticker, l_len);
+            l_item_used->cache_data.spent_time = a_spent_time;
+            strncpy(l_item_used->cache_data.token_ticker, l_item_tmp->cache_data.token_ticker, DAP_CHAIN_TICKER_SIZE_MAX);
+            int l_out_num = -1;
+            dap_chain_datum_tx_out_cond_get(l_item_tmp->tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL, &l_out_num);
+            if (l_out_num != -1 && l_out_num < MAX_OUT_ITEMS)
+                l_item_used->cache_data.tx_hash_spent_fast = l_item_tmp->cache_data.tx_hash_spent_fast[l_out_num];
             HASH_ADD_BYHASHVALUE(hh, l_ledger_priv->spent_items, tx_hash_fast, sizeof(dap_chain_hash_fast_t), l_hash_value, l_item_used);
-
-            // Add it to cache
-            l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_SPENT_TXS_STR);
-            char *l_tx_hash_str = dap_hash_fast_to_str_new(a_tx_hash);
-            if ( dap_global_db_set(l_gdb_group, l_tx_hash_str, l_item_used->token_ticker, l_len, false, NULL, NULL)) {
-                if(s_debug_more)
-                    log_it(L_WARNING, "Ledger cache mismatch");
-            }
-
-            DAP_DELETE(l_tx_hash_str);
-            DAP_DELETE(l_gdb_group);
+           if (PVT(a_ledger)->cached) {
+                // Add it to cache
+                char *l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_SPENT_TXS_STR);
+                char *l_tx_hash_str = dap_hash_fast_to_str_new(a_tx_hash);
+                if (dap_global_db_set(l_gdb_group, l_tx_hash_str, &l_item_used->cache_data, sizeof(l_item_used->cache_data), false, NULL, NULL))
+                    debug_if(s_debug_more, L_WARNING, "Ledger cache mismatch");
+                DAP_DELETE(l_tx_hash_str);
+                DAP_DELETE(l_gdb_group);
+           }
         }
         // delete tx & its item
         DAP_DELETE(l_item_tmp->tx);
@@ -3689,6 +3927,7 @@ void dap_chain_ledger_purge(dap_ledger_t *a_ledger, bool a_preserve_db)
     pthread_rwlock_wrlock(&l_ledger_priv->threshold_emissions_rwlock);
     pthread_rwlock_wrlock(&l_ledger_priv->threshold_txs_rwlock);
     pthread_rwlock_wrlock(&l_ledger_priv->balance_accounts_rwlock);
+    pthread_rwlock_wrlock(&l_ledger_priv->stake_lock_rwlock);
 
     /* Delete regular transactions */
     dap_chain_ledger_tx_item_t *l_item_current, *l_item_tmp;
@@ -3760,6 +3999,18 @@ void dap_chain_ledger_purge(dap_ledger_t *a_ledger, bool a_preserve_db)
         DAP_DELETE(l_gdb_group);
     }
 
+    /* Delete stake-lock items */
+    dap_chain_ledger_stake_lock_item_t *l_stake_item_current, *l_stake_item_tmp;
+    HASH_ITER(hh, l_ledger_priv->emissions_for_stake_lock, l_stake_item_current, l_stake_item_tmp) {
+        HASH_DEL(l_ledger_priv->emissions_for_stake_lock, l_stake_item_current);
+        DAP_DELETE(l_stake_item_current);
+    }
+    if (!a_preserve_db) {
+        l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_STAKE_LOCK_STR);
+        dap_global_db_del(l_gdb_group, NULL, NULL, NULL);
+        DAP_DELETE(l_gdb_group);
+    }
+
     /* Delete threshold emissions */
     HASH_ITER(hh, l_ledger_priv->threshold_emissions, l_emission_current, l_emission_tmp) {
         HASH_DEL(l_ledger_priv->threshold_emissions, l_emission_current);
@@ -3785,6 +4036,7 @@ void dap_chain_ledger_purge(dap_ledger_t *a_ledger, bool a_preserve_db)
     pthread_rwlock_unlock(&l_ledger_priv->threshold_emissions_rwlock);
     pthread_rwlock_unlock(&l_ledger_priv->threshold_txs_rwlock);
     pthread_rwlock_unlock(&l_ledger_priv->balance_accounts_rwlock);
+    pthread_rwlock_unlock(&l_ledger_priv->stake_lock_rwlock);
 }
 
 /**
@@ -4010,7 +4262,8 @@ static dap_chain_ledger_tx_item_t* tx_item_find_by_addr(dap_ledger_t *a_ledger,
     {
         // If a_token is setup we check if its not our token - miss it
         if (a_token && *l_iter_current->cache_data.token_ticker &&
-                dap_strcmp(l_iter_current->cache_data.token_ticker, a_token))
+                dap_strcmp(l_iter_current->cache_data.token_ticker, a_token) &&
+                !l_iter_current->cache_data.multichannel)
             continue;
         // Now work with it
         dap_chain_datum_tx_t *l_tx = l_iter_current->tx;
@@ -4148,14 +4401,13 @@ dap_list_t* dap_chain_ledger_tx_cache_find_out_cond_all(dap_ledger_t *a_ledger,d
     dap_chain_ledger_tx_item_t *l_iter_current = NULL, *l_item_tmp = NULL;
     HASH_ITER(hh, l_ledger_priv->ledger_items, l_iter_current, l_item_tmp) {
         dap_chain_datum_tx_t *l_tx = l_iter_current->tx;
-        dap_chain_hash_fast_t *l_tx_hash = &l_iter_current->tx_hash_fast;
-        int l_tx_out_cond_idx = 0;
-        dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_tx, &l_tx_out_cond_idx);
-        if(l_tx_out_cond){ // Is present cond out
-            if(l_tx_out_cond->header.srv_uid.uint64 == a_srv_uid.uint64 ) // is srv uid is same as we're searching for?
+        dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT_COND, NULL);
+        for (dap_list_t *it = l_list_out_items; it; it = it->next) {
+            // Is present cond out
+            dap_chain_tx_out_cond_t *l_tx_out_cond = it->data;
+            if (l_tx_out_cond->header.srv_uid.uint64 == a_srv_uid.uint64) // is srv uid is same as we're searching for?
                 l_ret = dap_list_append(l_ret,l_tx);
         }
-
     }
     return l_ret;
 }
@@ -4166,7 +4418,7 @@ dap_list_t* dap_chain_ledger_tx_cache_find_out_cond_all(dap_ledger_t *a_ledger,d
  *
  * a_addr[in] wallet address, whose owner can use the service
  */
-dap_chain_datum_tx_t* dap_chain_ledger_tx_cache_find_out_cond(dap_ledger_t *a_ledger,
+dap_chain_datum_tx_t* dap_chain_ledger_tx_cache_find_out_cond(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_subtype_t a_cond_type,
         dap_chain_hash_fast_t *a_tx_first_hash, dap_chain_tx_out_cond_t **a_out_cond, int *a_out_cond_idx, char *a_token_ticker)
 {
     if (!a_tx_first_hash)
@@ -4189,7 +4441,7 @@ dap_chain_datum_tx_t* dap_chain_ledger_tx_cache_find_out_cond(dap_ledger_t *a_le
             continue;
         }
         // Get out_cond item from transaction
-        l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_tx_tmp, &l_tx_out_cond_idx);
+        l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_tx_tmp, a_cond_type, &l_tx_out_cond_idx);
 
         if(l_tx_out_cond) {
             l_cur_tx = l_tx_tmp;
@@ -4220,8 +4472,9 @@ dap_chain_datum_tx_t* dap_chain_ledger_tx_cache_find_out_cond(dap_ledger_t *a_le
  * a_public_key[in] public key that signed the transaction
  * a_public_key_size[in] public key size
  */
-uint256_t dap_chain_ledger_tx_cache_get_out_cond_value(dap_ledger_t *a_ledger, dap_chain_addr_t *a_addr,
-        dap_chain_tx_out_cond_t **tx_out_cond)
+uint256_t dap_chain_ledger_tx_cache_get_out_cond_value(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_subtype_t a_cond_type,
+                                                       dap_chain_addr_t *a_addr, dap_chain_tx_out_cond_t **tx_out_cond)
+
 {
     uint256_t l_ret_value = {};
 
@@ -4232,14 +4485,11 @@ uint256_t dap_chain_ledger_tx_cache_get_out_cond_value(dap_ledger_t *a_ledger, d
     dap_chain_tx_out_cond_t *l_tx_out_cond;
     // Find all transactions
     do {
-
-        l_tx_tmp = dap_chain_ledger_tx_cache_find_out_cond(a_ledger, &l_tx_first_hash, &l_tx_out_cond, NULL, NULL);
-
+        l_tx_tmp = dap_chain_ledger_tx_cache_find_out_cond(a_ledger, a_cond_type, &l_tx_first_hash, &l_tx_out_cond, NULL, NULL);
         // Get out_cond item from transaction
         if(l_tx_tmp) {
             UNUSED(a_addr);
             // TODO check relations a_addr with cond_data and public key
-
             if(l_tx_out_cond) {
                 l_ret_value = l_tx_out_cond->header.value;
                 if(tx_out_cond)
@@ -4358,7 +4608,8 @@ int dap_chain_ledger_verificator_add(dap_chain_tx_out_cond_subtype_t a_subtype,
     return 0;
 }
 
-dap_list_t * dap_chain_ledger_get_txs(dap_ledger_t *a_ledger, size_t a_count, size_t a_page){
+dap_list_t * dap_chain_ledger_get_txs(dap_ledger_t *a_ledger, size_t a_count, size_t a_page, bool a_reverse)
+{
     dap_ledger_private_t *l_ledger_priv = PVT(a_ledger);
     size_t l_offset = a_count * (a_page - 1);
     size_t l_count = HASH_COUNT(l_ledger_priv->ledger_items);
@@ -4373,18 +4624,30 @@ dap_list_t * dap_chain_ledger_get_txs(dap_ledger_t *a_ledger, size_t a_count, si
     if (!l_ledger_priv->ledger_items) {
         return NULL;
     }
-    dap_chain_ledger_tx_item_t *l_ptr = l_ledger_priv->ledger_items->hh.tbl->tail->prev;
-    if (!l_ptr)
-        l_ptr = l_ledger_priv->ledger_items;
-    else
-        l_ptr = l_ptr->hh.next;
-    for (dap_chain_ledger_tx_item_t *ptr = l_ptr; ptr != NULL && l_counter < l_end; ptr = ptr->hh.prev){
-        if (l_counter >= l_offset){
-            dap_chain_datum_tx_t *l_tx = ptr->tx;
-            l_list = dap_list_append(l_list, l_tx);
+    if (a_reverse) {
+        dap_chain_ledger_tx_item_t *l_ptr = l_ledger_priv->ledger_items->hh.tbl->tail->prev;
+        if (!l_ptr)
+            l_ptr = l_ledger_priv->ledger_items;
+        else
+            l_ptr = l_ptr->hh.next;
+        for (dap_chain_ledger_tx_item_t *ptr = l_ptr; ptr != NULL && l_counter < l_end; ptr = ptr->hh.prev) {
+            if (l_counter >= l_offset) {
+                dap_chain_datum_tx_t *l_tx = ptr->tx;
+                l_list = dap_list_append(l_list, l_tx);
+            }
+            l_counter++;
+        }
+    } else {
+        dap_chain_ledger_tx_item_t *l_ptr = l_ledger_priv->ledger_items;
+        for (dap_chain_ledger_tx_item_t *ptr = l_ptr; ptr != NULL && l_counter < l_end; ptr = ptr->hh.next) {
+            if (l_counter >= l_offset) {
+                dap_chain_datum_tx_t *l_tx = ptr->tx;
+                l_list = dap_list_append(l_list, l_tx);
+            }
+            l_counter++;
         }
-        l_counter++;
     }
+
     return l_list;
 }
 
@@ -4456,8 +4719,3 @@ dap_list_t *dap_chain_ledger_get_list_tx_cond_outs_with_val(dap_ledger_t *a_ledg
     }
     return l_list_used_out;
 }
-
-bool dap_chain_ledger_fee_verificator(dap_ledger_t* a_ledger, dap_chain_tx_out_cond_t* a_cond, dap_chain_datum_tx_t* a_tx, bool a_owner)
-{
-    return false;
-}
diff --git a/modules/chain/dap_chain_pvt.c b/modules/chain/dap_chain_pvt.c
index 33f233562ae7ce9bfef0557b0cc30ed9bcce6040..8481a4be4ff56762082c69e42a6f728aa3a58ca6 100644
--- a/modules/chain/dap_chain_pvt.c
+++ b/modules/chain/dap_chain_pvt.c
@@ -41,7 +41,3 @@ void dap_chain_add_mempool_notify_callback(dap_chain_t *a_chain, dap_global_db_o
     l_notifier->cb_arg = a_cb_arg;
     DAP_CHAIN_PVT(a_chain)->mempool_notifires = dap_list_append(DAP_CHAIN_PVT(a_chain)->mempool_notifires, l_notifier);
 }
-
-
-
-
diff --git a/modules/chain/dap_chain_tx.c b/modules/chain/dap_chain_tx.c
new file mode 100644
index 0000000000000000000000000000000000000000..b5d3441d6d24add54e3c744f70ec604c3f0ae851
--- /dev/null
+++ b/modules/chain/dap_chain_tx.c
@@ -0,0 +1,90 @@
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * Cellframe Network https://cellframe.net
+ * Copyright  (c) 2022
+ * All rights reserved.
+
+ This file is part of DAP (Deus Applications Prototypes) the open source project
+
+    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    DAP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "dap_chain_tx.h"
+#include "dap_chain_datum_tx.h"
+#include "dap_chain_ledger.h"
+#include "dap_common.h"
+#include "uthash.h"
+#define LOG_TAG "dap_chain_tx"
+
+/**
+ * @brief Wrap without deep copy the datum tx into the deserialed tx
+ * @param a_tx_packed
+ * @return
+ */
+dap_chain_tx_t * dap_chain_tx_wrap_packed(dap_chain_datum_tx_t * a_tx_packed)
+{
+    dap_chain_tx_t * l_tx = DAP_NEW_Z(dap_chain_tx_t);
+    dap_hash_fast(a_tx_packed, dap_chain_datum_tx_get_size(a_tx_packed), &l_tx->hash);
+    l_tx->datum_tx = a_tx_packed;
+    return l_tx;
+}
+
+/**
+ * @brief Delete TX. IMPORTANT, doesn't delete wrapped packed tx if it has its store type
+ * @param a_tx
+ */
+void dap_chain_tx_delete(dap_chain_tx_t * a_tx)
+{
+    if(a_tx->prev)
+        DAP_DELETE(a_tx->prev);
+    if( a_tx->prev_hash )
+        DAP_DELETE(a_tx->prev_hash);
+
+    DAP_DELETE(a_tx);
+}
+
+/**
+ * @brief dap_chain_tx_dup
+ * @param a_tx
+ * @return
+ */
+dap_chain_tx_t* dap_chain_tx_dup(dap_chain_tx_t * a_tx)
+{
+    dap_chain_tx_t * l_ret = DAP_DUP(a_tx);
+    if(a_tx->prev)
+        l_ret->prev = DAP_DUP_SIZE(a_tx->prev, sizeof(*a_tx->prev)* a_tx->prev_count );
+    if(a_tx->prev_hash)
+        l_ret->prev_hash = DAP_DUP_SIZE(a_tx->prev_hash,sizeof(*a_tx->prev_hash)* a_tx->prev_count );
+    return l_ret;
+}
+
+/**
+ * @brief Add TX in hash table and updated prev/next links
+ * @param a_tx_hh
+ * @param a_tx
+ */
+void dap_chain_tx_hh_add (dap_chain_tx_t * a_tx_hh, dap_chain_tx_t * a_tx)
+{
+    HASH_ADD(hh,a_tx_hh,hash, sizeof(a_tx->hash),a_tx);
+}
+
+void dap_chain_tx_hh_free (dap_chain_tx_t * a_tx_hh)
+{
+    dap_chain_tx_t * l_tx = NULL, *l_tmp = NULL;
+    HASH_ITER(hh, a_tx_hh, l_tx, l_tmp){
+        HASH_DELETE(hh, a_tx_hh, l_tx);
+        dap_chain_tx_delete(l_tx);
+    }
+}
diff --git a/modules/chain/dap_chain_vf.c b/modules/chain/dap_chain_vf.c
deleted file mode 100644
index d6797bea0775e50c21584eb53e66e6e6c62a54d8..0000000000000000000000000000000000000000
--- a/modules/chain/dap_chain_vf.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Authors:
- * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * CellFrame       https://cellframe.net
- * Sources         https://gitlab.demlabs.net/cellframe
- * Copyright  (c) 2017-2019
- * All rights reserved.
-
- This file is part of CellFrame SDK
-
-    CellFrame SDK is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    CellFrame SDK is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "dap_chain_vf.h"
-
-#define LOG_TAG "dap_chain_vf"
-
-/**
- * @brief
- * empty function
- * return 0
- * @return
- */
-int dap_chain_vf_init()
-{
-    return 0;
-}
-
-/**
- * @brief
- * empty function
- */
-void dap_chain_vf_deinit()
-{
-
-}
-
-/**
- * @brief 
- * empty function
- * return 0
- * @param a_vf_id
- * @param a_callback
- * @return
- */
-int dap_chain_vf_add(dap_chain_vf_id_t a_vf_id, dap_chain_vf_callback_t a_callback)
-{
-    return 0;
-}
-
-/**
- * @brief dap_chain_vf_check
- * empty function
- * return true
- * @param a_vf_id
- * @param a_ledger
- * @param a_receipt
- * @param a_arg
- * @param a_arg_size
- * @param a_param_value
- * @param a_param_value_size
- * @return
- */
-bool dap_chain_vf_check(dap_chain_vf_id_t a_vf_id,  dap_ledger_t * a_ledger, dap_chain_datum_tx_receipt_t * a_receipt,
-                        void *a_arg , size_t a_arg_size, const char * a_param_value, const char * a_param_value_size )
-{
-    return true;
-}
diff --git a/modules/chain/include/dap_chain.h b/modules/chain/include/dap_chain.h
index 9b508ea967aa15045aba56c9ad7894d77e9fa4fe..537062aae2216d2e14816b82373c53d76a7099a1 100644
--- a/modules/chain/include/dap_chain.h
+++ b/modules/chain/include/dap_chain.h
@@ -83,13 +83,11 @@ typedef dap_chain_atom_ptr_t (*dap_chain_callback_atom_iter_find_by_hash_t)(dap_
 typedef dap_chain_datum_tx_t* (*dap_chain_callback_tx_find_by_hash_t)(dap_chain_t * ,dap_chain_hash_fast_t *);
 
 typedef dap_chain_atom_ptr_t * (*dap_chain_callback_atom_iter_get_atoms_t)(dap_chain_atom_iter_t * ,size_t* ,size_t**);
+typedef size_t (*dap_chain_callback_add_datums_t)(dap_chain_t * , dap_chain_datum_t **, size_t );
 
 typedef dap_chain_atom_ptr_t (*dap_chain_callback_atom_iter_get_next_t)(dap_chain_atom_iter_t *  ,size_t*);
 typedef void (*dap_chain_callback_atom_iter_delete_t)(dap_chain_atom_iter_t *  );
 
-typedef size_t (*dap_chain_callback_add_datums_t)(dap_chain_t * , dap_chain_datum_t **, size_t );
-typedef size_t (*dap_chain_callback_add_datums_with_group_t)(dap_chain_t * , dap_chain_datum_t **, size_t, const char *);
-
 typedef void (*dap_chain_callback_notify_t)(void * a_arg, dap_chain_t *a_chain, dap_chain_cell_id_t a_id, void* a_atom, size_t a_atom_size); //change in chain happened
 
 typedef size_t(*dap_chain_callback_get_count)(dap_chain_t *a_chain);
@@ -111,7 +109,7 @@ typedef struct dap_chain {
 
     dap_chain_id_t id;
     dap_chain_net_id_t net_id;
-	uint16_t load_priority;
+    uint16_t load_priority;
     char * name;
     char * net_name;
     dap_ledger_t * ledger; // If present - pointer to associated ledger
@@ -122,12 +120,12 @@ typedef struct dap_chain {
 
     uint16_t datum_types_count;
     dap_chain_type_t *datum_types;
-	uint16_t default_datum_types_count;
-	dap_chain_type_t *default_datum_types;
+    uint16_t default_datum_types_count;
+    dap_chain_type_t *default_datum_types;
     uint16_t autoproc_datum_types_count;
     uint16_t *autoproc_datum_types;
 
-	uint256_t minimum_commission;
+    uint256_t minimum_commission;
 
     // To hold it in double-linked lists
     struct dap_chain * next;
@@ -146,8 +144,6 @@ typedef struct dap_chain {
     dap_chain_callback_atom_verify_t callback_atom_verify;
 
     dap_chain_callback_add_datums_t callback_add_datums;
-    dap_chain_callback_add_datums_with_group_t callback_add_datums_with_group;
-
     dap_chain_callback_atom_get_hdr_size_t callback_atom_get_hdr_static_size; // Get atom header's size
 
     dap_chain_callback_atom_iter_create_t callback_atom_iter_create;
diff --git a/modules/chain/include/dap_chain_cell.h b/modules/chain/include/dap_chain_cell.h
index 2c5f9246e746be0de3c0f5a1d83eae1d4f1a3267..8ca6a758cbf198c7b5cb1f060090c1dcf868270f 100644
--- a/modules/chain/include/dap_chain_cell.h
+++ b/modules/chain/include/dap_chain_cell.h
@@ -24,6 +24,7 @@
 #pragma once
 #include <stdint.h>
 #include <stdio.h>
+#include <pthread.h>
 #include "uthash.h"
 #include "dap_chain_common.h"
 
diff --git a/modules/chain/include/dap_chain_ledger.h b/modules/chain/include/dap_chain_ledger.h
index a77164a96de9ca51c6f50b2e861dc0f88250adde..d53d5452898a902a1e42ce9a6802cf103258ccff 100644
--- a/modules/chain/include/dap_chain_ledger.h
+++ b/modules/chain/include/dap_chain_ledger.h
@@ -26,9 +26,8 @@
 #pragma once
 #include <stdint.h>
 #include <stdbool.h>
-
-//#include "dap_enc_key.h"
 #include "dap_common.h"
+#include "dap_hash.h"
 #include "dap_list.h"
 #include "dap_math_ops.h"
 #include "dap_chain_common.h"
@@ -42,7 +41,8 @@ typedef struct dap_ledger {
     void *_internal;
 } dap_ledger_t;
 
-typedef bool (*dap_chain_ledger_verificator_callback_t)(dap_ledger_t* a_ledger, dap_chain_tx_out_cond_t* a_cond, dap_chain_datum_tx_t* a_tx, bool a_owner);
+typedef bool (* dap_chain_ledger_verificator_callback_t)(dap_ledger_t * a_ledger, dap_hash_fast_t *a_tx_out_hash,  dap_chain_tx_out_cond_t *a_tx_out_cond,
+                                                         dap_chain_datum_tx_t *a_tx_in, bool a_owner);
 typedef bool (*dap_chain_ledger_verificator_callback_out_t)(dap_ledger_t* a_ledger, dap_chain_datum_tx_t* a_tx, dap_chain_tx_out_cond_t* a_cond);
 
 typedef struct dap_chain_net dap_chain_net_t;
@@ -65,14 +65,13 @@ typedef struct dap_chain_net dap_chain_net_t;
 
 #define DAP_CHAIN_LEDGER_TOKENS_STR              "tokens"
 #define DAP_CHAIN_LEDGER_EMISSIONS_STR           "emissions"
+#define DAP_CHAIN_LEDGER_STAKE_LOCK_STR          "stake_lock"
 #define DAP_CHAIN_LEDGER_TXS_STR                 "txs"
 #define DAP_CHAIN_LEDGER_SPENT_TXS_STR           "spent_txs"
-#define DAP_CHAIN_LEDGER_SPENT_TXS_TIME_STR      "spent_txs_time"
 #define DAP_CHAIN_LEDGER_BALANCES_STR            "balances"
 
 int dap_chain_ledger_init();
 void dap_chain_ledger_deinit();
-bool dap_chain_global_rwlocks_and_verificators_init(void);
 
 dap_ledger_t* dap_chain_ledger_create(uint16_t a_check_flags, char *a_net_name);
 
@@ -145,6 +144,9 @@ int dap_chain_ledger_token_emission_load(dap_ledger_t *a_ledger, byte_t *a_token
 // Check if it addable
 int dap_chain_ledger_token_emission_add_check(dap_ledger_t *a_ledger, byte_t *a_token_emission, size_t a_token_emission_size);
 
+/* Add stake-lock item */
+int dap_chain_ledger_emission_for_stake_lock_item_add(dap_ledger_t *a_ledger, const dap_chain_hash_fast_t *a_tx_hash);
+
 dap_chain_datum_token_emission_t *dap_chain_ledger_token_emission_find(dap_ledger_t *a_ledger,
         const char *a_token_ticker, const dap_chain_hash_fast_t *a_token_emission_hash);
 
@@ -157,16 +159,15 @@ void dap_chain_ledger_addr_get_token_ticker_all(dap_ledger_t *a_ledger, dap_chai
         char *** a_tickers, size_t * a_tickers_size);
 
 // Checking a new transaction before adding to the cache
-int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, bool a_from_threshold,
-        dap_list_t **a_list_bound_items, dap_list_t **a_list_tx_out);
-
+int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash,
+                                    bool a_from_threshold, dap_list_t **a_list_bound_items, dap_list_t **a_list_tx_out);
 
 /**
  * Delete transaction from the cache
  *
  * return 1 OK, -1 error, -2 tx_hash not found
  */
-int dap_chain_ledger_tx_remove(dap_ledger_t *a_ledger, dap_chain_hash_fast_t *a_tx_hash);
+int dap_chain_ledger_tx_remove(dap_ledger_t *a_ledger, dap_chain_hash_fast_t *a_tx_hash, dap_time_t a_spent_time);
 
 /**
  * Delete all transactions from the cache
@@ -208,6 +209,7 @@ uint256_t dap_chain_ledger_calc_balance_full(dap_ledger_t *a_ledger, const dap_c
  */
  dap_chain_datum_tx_t* dap_chain_ledger_tx_find_by_hash(dap_ledger_t *a_ledger, dap_chain_hash_fast_t *a_tx_hash);
 bool dap_chain_ledger_tx_spent_find_by_hash(dap_ledger_t *a_ledger, dap_chain_hash_fast_t *a_tx_hash);
+dap_hash_fast_t *dap_chain_ledger_get_final_chain_tx_hash(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a_cond_type, dap_chain_hash_fast_t *a_tx_hash);
 
  // Get the transaction in the cache by the addr in out item
 dap_chain_datum_tx_t* dap_chain_ledger_tx_find_by_addr(dap_ledger_t *a_ledger, const char * a_token,
@@ -218,28 +220,31 @@ const dap_chain_datum_tx_t* dap_chain_ledger_tx_find_by_pkey(dap_ledger_t *a_led
         char *a_public_key, size_t a_public_key_size, dap_chain_hash_fast_t *a_tx_first_hash);
 
 // Get the transaction in the cache with the out_cond item
-dap_chain_datum_tx_t* dap_chain_ledger_tx_cache_find_out_cond(dap_ledger_t *a_ledger, dap_chain_hash_fast_t *a_tx_first_hash,
-                                                              dap_chain_tx_out_cond_t **a_out_cond, int *a_out_cond_idx, char *a_token_ticker);
+dap_chain_datum_tx_t* dap_chain_ledger_tx_cache_find_out_cond(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_subtype_t a_cond_type,
+                                                              dap_chain_hash_fast_t *a_tx_first_hash, dap_chain_tx_out_cond_t **a_out_cond,
+                                                              int *a_out_cond_idx, char *a_token_ticker);
 
 // Get all transactions from the cache with the specified out_cond items
 dap_list_t* dap_chain_ledger_tx_cache_find_out_cond_all(dap_ledger_t *a_ledger, dap_chain_net_srv_uid_t a_srv_uid);
 
 // Get the value from all transactions in the cache with out_cond item
-uint256_t dap_chain_ledger_tx_cache_get_out_cond_value(dap_ledger_t *a_ledger, dap_chain_addr_t *a_addr,
-        dap_chain_tx_out_cond_t **tx_out_cond);
+uint256_t dap_chain_ledger_tx_cache_get_out_cond_value(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_subtype_t a_cond_type, dap_chain_addr_t *a_addr,
+                                                       dap_chain_tx_out_cond_t **tx_out_cond);
 
 // Get the list of 'out' items from previous transactions with summary value >= than a_value_need
 // Put this summary value to a_value_transfer
 dap_list_t *dap_chain_ledger_get_list_tx_outs_with_val(dap_ledger_t *a_ledger, const char *a_token_ticker, const dap_chain_addr_t *a_addr_from,
                                                        uint256_t a_value_need, uint256_t *a_value_transfer);
+
 // Get the list of 'out_cond' items with summary value >= than a_value_need
 dap_list_t *dap_chain_ledger_get_list_tx_cond_outs_with_val(dap_ledger_t *a_ledger, const char *a_token_ticker,  const dap_chain_addr_t *a_addr_from,
         dap_chain_tx_out_cond_subtype_t a_subtype, uint256_t a_value_need, uint256_t *a_value_transfer);
+
 // Add new verificator callback with associated subtype. Returns 1 if callback replaced, overwise returns 0
-int dap_chain_ledger_verificator_add(dap_chain_tx_out_cond_subtype_t a_subtype, dap_chain_ledger_verificator_callback_t a_callback, 
+int dap_chain_ledger_verificator_add(dap_chain_tx_out_cond_subtype_t a_subtype, dap_chain_ledger_verificator_callback_t a_callback,
                                      dap_chain_ledger_verificator_callback_out_t a_callback_added);
 
 // Getting a list of transactions from the ledger.
-dap_list_t * dap_chain_ledger_get_txs(dap_ledger_t *a_ledger, size_t a_count, size_t a_page);
+dap_list_t * dap_chain_ledger_get_txs(dap_ledger_t *a_ledger, size_t a_count, size_t a_page, bool a_reverse);
 
-bool dap_chain_ledger_fee_verificator(dap_ledger_t* a_ledger, dap_chain_tx_out_cond_t* a_cond, dap_chain_datum_tx_t* a_tx, bool a_owner);
+//bool dap_chain_ledger_fee_verificator(dap_ledger_t* a_ledger, dap_chain_tx_out_cond_t* a_cond, dap_chain_datum_tx_t* a_tx, bool a_owner);
diff --git a/modules/chain/include/dap_chain_tx.h b/modules/chain/include/dap_chain_tx.h
new file mode 100644
index 0000000000000000000000000000000000000000..fbae57c57cf1bf10389fd5224e63fb006e8aa3c7
--- /dev/null
+++ b/modules/chain/include/dap_chain_tx.h
@@ -0,0 +1,87 @@
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * Cellframe Network https://cellframe.net
+ * Copyright  (c) 2022
+ * All rights reserved.
+
+ This file is part of DAP (Deus Applications Prototypes) the open source project
+
+    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    DAP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+#include "dap_chain_common.h"
+#include "dap_chain_datum_token.h"
+#include "dap_hash.h"
+#include "uthash.h"
+#include "dap_chain_datum_tx.h"
+#include "dap_chain_datum_tx_items.h"
+#include "dap_chain_datum_tx_in.h"
+#include "dap_chain_datum_tx_in_cond.h"
+#include "dap_chain_datum_tx_out_cond.h"
+#include "dap_chain_datum_tx_out_ext.h"
+#include "dap_chain_datum_tx_out.h"
+
+typedef struct dap_chain_tx
+{
+    enum {CHAIN_TX_STORE_TYPE_PACKED, CHAIN_TX_STORE_TYPE_UNPACKED} store_type;
+    dap_chain_datum_tx_t * datum_tx;
+    // Owner
+    dap_chain_addr_t owner;
+    const char * token_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
+    dap_hash_fast_t token_hash;
+    dap_chain_datum_token_t *token;
+
+    // Inputs
+    dap_chain_datum_tx_item_t * in;
+    dap_chain_tx_in_cond_t * in_cond;
+    // Outputs
+    dap_chain_datum_tx_item_t * out;
+    dap_chain_tx_out_cond_t * out_cond;
+
+    // Previous
+    struct dap_chain_tx ** prev;
+    size_t prev_count;
+    dap_hash_fast_t * prev_hash;
+
+    struct dap_chain_tx ** next;
+    size_t next_count;
+    dap_hash_fast_t * next_hash;
+
+    // Hash and UT hash handle
+    dap_hash_fast_t hash;
+    UT_hash_handle hh;
+} dap_chain_tx_t;
+
+dap_chain_tx_t * dap_chain_tx_wrap_packed(dap_chain_datum_tx_t * a_tx_packed);
+void dap_chain_tx_hh_add (dap_chain_tx_t * a_tx_hh, dap_chain_tx_t * a_tx);
+
+/**
+ * @brief Find tx in hashtable by its datum_tx hash
+ * @param a_tx_hh
+ * @param a_tx_hash
+ * @return
+ */
+static inline dap_chain_tx_t * dap_chain_tx_hh_find (dap_chain_tx_t * a_tx_hh, dap_hash_fast_t* a_tx_hash)
+{
+    dap_chain_tx_t * l_ret = NULL;
+    HASH_FIND(hh, a_tx_hh, a_tx_hash, sizeof(*a_tx_hash), l_ret);
+    return l_ret;
+}
+
+void dap_chain_tx_hh_free (dap_chain_tx_t * a_tx_hh);
+dap_chain_tx_t* dap_chain_tx_dup(dap_chain_tx_t * a_tx);
+
+void dap_chain_tx_delete(dap_chain_tx_t * a_tx);
diff --git a/modules/chain/include/dap_chain_vf.h b/modules/chain/include/dap_chain_vf.h
deleted file mode 100644
index 75f479004d47ed7025fab470541b03b14d0fd6ec..0000000000000000000000000000000000000000
--- a/modules/chain/include/dap_chain_vf.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Authors:
- * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * CellFrame       https://cellframe.net
- * Sources         https://gitlab.demlabs.net/cellframe
- * Copyright  (c) 2017-2019
- * All rights reserved.
-
- This file is part of CellFrame SDK
-
-    CellFrame SDK is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    CellFrame SDK is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
-*/
-#pragma once
-#include <stdint.h>
-#include "dap_chain_common.h"
-#include "dap_chain_ledger.h"
-#include "dap_chain_datum_tx_receipt.h"
-#include "dap_chain_datum_tx_in_cond.h"
-#include "dap_chain_datum_tx_out.h"
-
-typedef uint64_t dap_chain_vf_id_t;
-typedef bool (*dap_chain_vf_callback_t) (dap_ledger_t *, dap_chain_datum_tx_receipt_t*, void * ,size_t  );
-
-
-
-// Verificator TX_CHECK argument structure
-typedef struct dap_chain_vf_tx_check {
-    dap_chain_hash_fast_t tx_hash; // Transaction hash that should exists, if not null
-    uint64_t value;     // Total tx value that should be exactly same, if not null
-    uint64_t value_max; // Total tx value not more or equal, if not null
-    uint64_t value_min; // Total tx value not less or equal, if not null
-    char token_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; // Tocken ticker is exactly same, if not null
-} dap_chain_vf_tx_check_t;
-
-typedef struct dap_chain_vf_tx_cond_in_check {
-    /// General TX check
-    dap_chain_vf_tx_check_t tx_check;
-    /// If any field is not null it must be equal to receipt info in the input item.
-    /// Checks first input. TODO: make able to check more than one inputs and input receipts
-    dap_chain_receipt_info_t receipt_info;
-} dap_chain_vf_tx_cond_in_check_t;
-
-
-typedef struct dap_chain_vf_tx_cond_out_srv_pay_check {
-    /// Do the general tx checks if some of them are not null
-    dap_chain_vf_tx_check_t tx_check;
-    /// Check if public key hash its not null
-    dap_chain_hash_fast_t pkey_hash;
-    /// Check for service uid if its not null
-    dap_chain_net_srv_uid_t srv_uid;
-    /// Check for units if not null
-    dap_chain_net_srv_price_unit_uid_t unit;
-    /// Check for maximum price per unit if not null
-    uint64_t unit_price_max_datoshi;
-     /// Chek if params are exactly
-    uint32_t params_size;
-} dap_chain_vf_tx_cond_out_check_t;
-
-
-///              General usage verificators IDs
-
-#define         DAP_CHAIN_VF_ID_TX_CHECK                            0x0000000000000010
-#define         DAP_CHAIN_VF_ID_TX_IN_COND_CHECK                    0x0000000000000020
-#define         DAP_CHAIN_VF_ID_TX_OUT_COND_SRV_PAY_CHECK           0x0000000000000030
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Init general usage verificators
-int dap_chain_vf_init();
-void dap_chain_vf_deinit();
-
-// Add custom verificator
-int dap_chain_vf_add(dap_chain_vf_id_t a_vf_id, dap_chain_vf_callback_t a_callback);
-
-// Check if verificator pass receipt
-bool dap_chain_vf_check(dap_chain_vf_id_t a_vf_id,  dap_ledger_t * a_ledger, dap_chain_datum_tx_receipt_t * a_receipt,
-                        void *a_arg , size_t a_arg_size, const char * a_param_value, const char * a_param_value_size );
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/modules/channel/chain-net/dap_stream_ch_chain_net.c b/modules/channel/chain-net/dap_stream_ch_chain_net.c
index 820ea683a4e0f59526aff15fcb60a7ce23a425ec..335eef1d45485778cafcb3b3296d4b5ab9ab4947 100644
--- a/modules/channel/chain-net/dap_stream_ch_chain_net.c
+++ b/modules/channel/chain-net/dap_stream_ch_chain_net.c
@@ -198,22 +198,30 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
         pthread_mutex_lock(&l_ch_chain_net->mutex);
         dap_stream_ch_pkt_t *l_ch_pkt = (dap_stream_ch_pkt_t *) a_arg;
         dap_stream_ch_chain_net_pkt_t *l_ch_chain_net_pkt = (dap_stream_ch_chain_net_pkt_t *) l_ch_pkt->data;
-        uint16_t l_acl_idx = dap_chain_net_acl_idx_by_id(l_ch_chain_net_pkt->hdr.net_id);
+        dap_chain_net_t *l_net = dap_chain_net_by_id(l_ch_chain_net_pkt->hdr.net_id);
         bool l_error = false;
         char l_err_str[64];
-        if (l_acl_idx == (uint16_t)-1) {
+        if (!l_net) {
             log_it(L_ERROR, "Invalid net id in packet");
             strcpy(l_err_str, "ERROR_NET_INVALID_ID");
             l_error = true;
         }
-        uint8_t l_acl = a_ch->stream->session->acl ? a_ch->stream->session->acl[l_acl_idx] : 1;
-        if (!l_error && !l_acl) {
-            log_it(L_WARNING, "Unauthorized request attempt to network %s",
-                   dap_chain_net_by_id(l_ch_chain_net_pkt->hdr.net_id)->pub.name);
-            strcpy(l_err_str, "ERROR_NET_NOT_AUTHORIZED");
+        if (!l_error && dap_chain_net_get_state(l_net) == NET_STATE_OFFLINE) {
+            log_it(L_ERROR, "Invalid net id in packet");
+            strcpy(l_err_str, "ERROR_NET_IS_OFFLINE");
             l_error = true;
         }
-        if (l_error) {
+        if (!l_error) {
+            uint16_t l_acl_idx = dap_chain_net_get_acl_idx(l_net);
+            uint8_t l_acl = a_ch->stream->session->acl ? a_ch->stream->session->acl[l_acl_idx] : 1;
+            if (!l_acl) {
+                log_it(L_WARNING, "Unauthorized request attempt to network %s",
+                       dap_chain_net_by_id(l_ch_chain_net_pkt->hdr.net_id)->pub.name);
+                strcpy(l_err_str, "ERROR_NET_NOT_AUTHORIZED");
+                l_error = true;
+            }
+        } else {
+
             dap_stream_ch_chain_net_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_ERROR ,
                                               l_ch_chain_net_pkt->hdr.net_id, l_err_str, strlen(l_err_str) + 1);
             dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
diff --git a/modules/channel/chain-voting/dap_stream_ch_chain_voting.c b/modules/channel/chain-voting/dap_stream_ch_chain_voting.c
index ab49b11f39f2216463c69d232bdbce76c6191ba1..7295d303f976b69cbb335c685900f486d6433dd0 100644
--- a/modules/channel/chain-voting/dap_stream_ch_chain_voting.c
+++ b/modules/channel/chain-voting/dap_stream_ch_chain_voting.c
@@ -18,28 +18,22 @@ typedef struct voting_pkt_in_callback{
     voting_ch_callback_t packet_in_callback;
 } voting_pkt_in_callback_t;
 
-typedef struct voting_pkt_addr
-{
-    //dap_client_t *client;
+typedef struct voting_pkt_addr {
     dap_chain_node_addr_t node_addr;
-    //dap_chain_node_client_t *node_client;
     dap_stream_ch_chain_voting_pkt_t *voting_pkt;
 } voting_pkt_addr_t;
 
-typedef struct voting_pkt_items
-{
-    //size_t count;
-    // dap_stream_ch_chain_voting_pkt_t * pkts_out[];
+typedef struct voting_pkt_items {
     pthread_rwlock_t rwlock_out;
     pthread_rwlock_t rwlock_in;
     dap_list_t * pkts_out; // voting_pkt_addr_t
     dap_list_t * pkts_in; // dap_stream_ch_chain_voting_pkt_t
-    // dap_timerfd_t * timer_in;
 } voting_pkt_items_t;
 
 typedef struct voting_node_client_list {
     dap_chain_node_info_t *node_info;
     dap_chain_node_client_t *node_client;
+    dap_events_socket_uuid_t uuid;
     dap_chain_node_addr_t node_addr;
     UT_hash_handle hh;
 } voting_node_client_list_t;
@@ -145,16 +139,18 @@ void dap_stream_ch_chain_voting_pkt_broadcast(dap_chain_net_t *a_net, dap_list_t
         voting_node_client_list_t *l_node_item = NULL;
         if ( l_remote_node_addr->uint64 != dap_chain_net_get_cur_addr_int(a_net) ) {
             HASH_FIND(hh, s_node_client_list, l_remote_node_addr, sizeof(dap_chain_node_addr_t), l_node_item);
-            if ( l_node_item
-                 && l_node_item->node_client
-                 && !dap_client_get_stream(l_node_item->node_client->client) ) {
-                dap_chain_node_client_close(l_node_item->node_client);
-                // DAP_DELETE(l_node_item->node_client);
-                char l_channels[] = {dap_stream_ch_chain_voting_get_id(),0};
-                l_node_item->node_client = dap_chain_node_client_connect_channels(a_net, l_node_item->node_info, l_channels);
-            }
-
-            if (!l_node_item) {
+            if (l_node_item) {
+                dap_chain_node_client_t *l_usable = dap_chain_node_client_find(l_node_item->uuid);
+                if (l_usable && !dap_client_get_stream(l_usable->client)) {
+                        dap_chain_node_client_close(l_node_item->uuid);
+                        l_usable = NULL;
+                }
+                if (!l_usable) {
+                    char l_channels[] = {dap_stream_ch_chain_voting_get_id(),0};
+                    l_node_item->node_client = dap_chain_node_client_connect_channels(a_net, l_node_item->node_info, l_channels);
+                    l_node_item->uuid = l_node_item->node_client->uuid;
+                }
+            } else {
                 size_t node_info_size = 0;
                 char *l_key = dap_chain_node_addr_to_hash_str(l_remote_node_addr);
                 dap_chain_node_info_t *l_node_info =
@@ -173,6 +169,7 @@ void dap_stream_ch_chain_voting_pkt_broadcast(dap_chain_net_t *a_net, dap_list_t
                 l_node_client_item->node_addr = *l_remote_node_addr;
                 l_node_client_item->node_info = l_node_info;
                 l_node_client_item->node_client = l_node_client;
+                l_node_client_item->uuid = l_node_client->uuid;
                 HASH_ADD(hh, s_node_client_list, node_addr, sizeof(dap_chain_node_addr_t), l_node_client_item);
                 l_node_item = l_node_client_item;
             }
@@ -303,7 +300,6 @@ static bool s_packet_in_callback_handler(void *a_arg)
         s_pkt_items->pkts_in = NULL;
         pthread_rwlock_unlock(&s_pkt_items->rwlock_in);
         while(l_list_pkts) {
-            dap_list_t *l_list_next = l_list_pkts->next;
             dap_stream_ch_chain_voting_pkt_t * l_voting_pkt = (dap_stream_ch_chain_voting_pkt_t *)l_list_pkts->data;
             for (size_t i=0; i<s_pkt_in_callback_count; i++) {
                 voting_pkt_in_callback_t * l_callback = s_pkt_in_callback+i;
@@ -313,7 +309,7 @@ static bool s_packet_in_callback_handler(void *a_arg)
                 }
             }
             DAP_DELETE(l_voting_pkt);
-            l_list_pkts = l_list_next;
+            l_list_pkts = l_list_pkts->next;
         }
         dap_list_free(l_list_pkts);
     } else {
@@ -323,12 +319,16 @@ static bool s_packet_in_callback_handler(void *a_arg)
 }
 
 
-static void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg) {
+static void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
+{
     dap_stream_ch_pkt_t * l_ch_pkt = (dap_stream_ch_pkt_t *) a_arg;
+    if (!l_ch_pkt)
+        return;
     pthread_rwlock_wrlock(&s_pkt_items->rwlock_in);
-    uint32_t l_voting_pkt_size = l_ch_pkt->hdr.size;
-    dap_stream_ch_chain_voting_pkt_t * l_voting_pkt = DAP_NEW_SIZE(dap_stream_ch_chain_voting_pkt_t, l_voting_pkt_size);
-    memcpy(l_voting_pkt, &l_ch_pkt->data, l_voting_pkt_size);
+    size_t l_voting_pkt_size = l_ch_pkt->hdr.size;
+    if (!l_voting_pkt_size || l_voting_pkt_size > UINT16_MAX)
+        return;
+    dap_stream_ch_chain_voting_pkt_t *l_voting_pkt = DAP_DUP_SIZE(&l_ch_pkt->data, l_voting_pkt_size);
     s_pkt_items->pkts_in = dap_list_append(s_pkt_items->pkts_in, l_voting_pkt);
     pthread_rwlock_unlock(&s_pkt_items->rwlock_in);
 }
@@ -355,4 +355,4 @@ size_t dap_stream_ch_chain_voting_pkt_write_unsafe(dap_stream_ch_t *a_ch, uint8_
     size_t l_ret  = dap_stream_ch_pkt_write_unsafe(a_ch, a_type , l_chain_pkt, l_chain_pkt_size);
     DAP_DELETE(l_chain_pkt);
     return l_ret;
-}
\ No newline at end of file
+}
diff --git a/modules/channel/chain/dap_stream_ch_chain.c b/modules/channel/chain/dap_stream_ch_chain.c
index 2ffbd5892e77417dc2f0a6f148f9658bb9b34493..5203deaab1d82a03e72d505176dd9363cfa84390 100644
--- a/modules/channel/chain/dap_stream_ch_chain.c
+++ b/modules/channel/chain/dap_stream_ch_chain.c
@@ -320,9 +320,8 @@ static bool s_sync_out_chains_proc_callback(dap_proc_thread_t *a_thread, void *a
             (void ) l_chain->callback_atom_find_by_hash(l_sync_request->chain.request_atom_iter,
                                                           &l_hash_from, &l_first_size);
         }
-
-
         //pthread_rwlock_unlock(&l_chain->atoms_rwlock);
+        l_sync_request->chain.request_atom_iter = NULL;
         dap_proc_thread_worker_exec_callback_inter(a_thread, l_sync_request->worker->id, s_sync_out_chains_first_worker_callback, l_sync_request );
     } else {
         //pthread_rwlock_unlock(&l_chain->atoms_rwlock);
@@ -476,7 +475,7 @@ static bool s_sync_update_gdb_proc_callback(dap_proc_thread_t *a_thread, void *a
         DAP_DELETE(l_sync_request);
         return true;
     }
-    dap_chain_net_add_downlink(l_net, l_ch->stream_worker, l_ch->uuid);
+    dap_chain_net_add_downlink(l_net, l_ch->stream_worker, l_ch->uuid, l_ch->stream->esocket_uuid);
     dap_stream_ch_chain_t *l_ch_chain = DAP_STREAM_CH_CHAIN(l_ch);
     int l_flags = 0;
     if (dap_chain_net_get_extra_gdb_group(l_net, l_sync_request->request.node_addr))
@@ -632,11 +631,11 @@ static void s_gdb_sync_tsd_worker_callback(dap_worker_t *a_worker, void *a_arg)
 }
 
 /**
- * @brief 
- * 
- * @param net_id 
- * @param group_name 
- * @return dap_chain_t* 
+ * @brief
+ *
+ * @param net_id
+ * @param group_name
+ * @return dap_chain_t*
  */
 dap_chain_t *dap_chain_get_chain_from_group_name(dap_chain_net_id_t a_net_id, const char *a_group_name)
 {
@@ -720,12 +719,11 @@ static void s_gdb_in_pkt_proc_callback_get_ts_callback(dap_global_db_context_t *
 
     dap_chain_t *l_chain = dap_chain_get_chain_from_group_name(l_sync_request->request_hdr.net_id, l_obj->group);
 
-    if (l_chain && l_chain->callback_add_datums_with_group) {
+    if (l_chain && l_chain->callback_add_datums) {
         log_it(L_WARNING, "New data goes to GDB chain");
             const void * restrict l_store_obj_value = l_obj->value;
-            l_chain->callback_add_datums_with_group(l_chain,
-                    (dap_chain_datum_t** restrict) &l_store_obj_value, 1,
-                    l_obj->group);
+            l_chain->callback_add_datums(l_chain,
+                    (dap_chain_datum_t** restrict) &l_store_obj_value, 1);
     } else {
         // save data to global_db
         if( dap_global_db_set_raw(l_obj, 1,s_gdb_in_pkt_proc_set_raw_callback, l_sync_request) != 0) {
@@ -941,7 +939,7 @@ static bool s_chain_timer_callback(void *a_arg)
         DAP_DELETE(a_arg);
         l_ch_chain->activity_timer = NULL;
         return false;
-    }   
+    }
     if (l_ch_chain->state != CHAIN_STATE_WAITING && l_ch_chain->sent_breaks)
         s_stream_ch_packet_out(l_ch, NULL);
     // Sending dumb packet with nothing to inform remote thats we're just skiping atoms of GDB's, nothing freezed
@@ -1004,18 +1002,15 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                sizeof(l_chain_pkt->hdr));
         return;
     }
-    s_chain_timer_reset(l_ch_chain);
-
-    size_t l_chain_pkt_data_size = l_ch_pkt->hdr.size-sizeof (l_chain_pkt->hdr) ;
-    uint16_t l_acl_idx = dap_chain_net_acl_idx_by_id(l_chain_pkt->hdr.net_id );
-    if (l_acl_idx == (uint16_t)-1) {
+    size_t l_chain_pkt_data_size = l_ch_pkt->hdr.size-sizeof (l_chain_pkt->hdr);
+    dap_chain_net_t *l_net = dap_chain_net_by_id(l_chain_pkt->hdr.net_id);
+    if (!l_net) {
         if (l_ch_pkt->hdr.type == DAP_STREAM_CH_CHAIN_PKT_TYPE_ERROR) {
             if(l_ch_chain->callback_notify_packet_in) {
                 l_ch_chain->callback_notify_packet_in(l_ch_chain, l_ch_pkt->hdr.type, l_chain_pkt,
                                                       l_chain_pkt_data_size, l_ch_chain->callback_notify_arg);
             }
         } else {
-
             log_it(L_ERROR, "Invalid request from %s with ext_id %016"DAP_UINT64_FORMAT_x" net id 0x%016"DAP_UINT64_FORMAT_x" chain id 0x%016"DAP_UINT64_FORMAT_x" cell_id 0x%016"DAP_UINT64_FORMAT_x" in packet", a_ch->stream->esocket->remote_addr_str?
                        a_ch->stream->esocket->remote_addr_str: "<unknown>", l_chain_pkt->hdr.ext_id,
                    l_chain_pkt->hdr.net_id.uint64, l_chain_pkt->hdr.chain_id.uint64,
@@ -1028,6 +1023,14 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
         }
         return;
     }
+    if (dap_chain_net_get_state(l_net) == NET_STATE_OFFLINE) {
+        s_stream_ch_write_error_unsafe(a_ch, l_chain_pkt->hdr.net_id.uint64,
+                                            l_chain_pkt->hdr.chain_id.uint64, l_chain_pkt->hdr.cell_id.uint64,
+                                            "ERROR_NET_IS_OFFLINE");
+        a_ch->stream->esocket->flags |= DAP_SOCK_SIGNAL_CLOSE;
+        return;
+    }
+    uint16_t l_acl_idx = dap_chain_net_get_acl_idx(l_net);
     uint8_t l_acl = a_ch->stream->session->acl ? a_ch->stream->session->acl[l_acl_idx] : 1;
     if (!l_acl) {
         log_it(L_WARNING, "Unauthorized request attempt from %s to network %s", a_ch->stream->esocket->remote_addr_str?
@@ -1038,6 +1041,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                                             "ERROR_NET_NOT_AUTHORIZED");
         return;
     }
+    s_chain_timer_reset(l_ch_chain);
     switch (l_ch_pkt->hdr.type) {
         /// --- GDB update ---
         // Request for gdbs list update
@@ -1583,8 +1587,8 @@ static void s_ch_chain_go_idle(dap_stream_ch_chain_t *a_ch_chain)
     memset(&a_ch_chain->request_hdr, 0, sizeof(a_ch_chain->request_hdr));
     if (a_ch_chain->request_atom_iter && a_ch_chain->request_atom_iter->chain &&
             a_ch_chain->request_atom_iter->chain->callback_atom_iter_delete) {
-                a_ch_chain->request_atom_iter->chain->callback_atom_iter_delete(a_ch_chain->request_atom_iter);
-                a_ch_chain->request_atom_iter = NULL;
+        a_ch_chain->request_atom_iter->chain->callback_atom_iter_delete(a_ch_chain->request_atom_iter);
+        a_ch_chain->request_atom_iter = NULL;
     }
 
     dap_stream_ch_chain_hash_item_t *l_hash_item = NULL, *l_tmp = NULL;
@@ -1631,7 +1635,8 @@ static void s_stream_ch_io_complete(dap_events_socket_t *a_es, void *a_arg, int
         return;
     if (a_arg) {
         struct chain_io_complete *l_arg = (struct chain_io_complete *)a_arg;
-        DAP_STREAM_CH_CHAIN(l_ch)->state = l_arg->state;
+        if (DAP_STREAM_CH_CHAIN(l_ch)->state == CHAIN_STATE_WAITING)
+            DAP_STREAM_CH_CHAIN(l_ch)->state = l_arg->state;
         dap_stream_ch_chain_pkt_write_unsafe(l_ch, l_arg->type, l_arg->net_id, l_arg->chain_id,
                                              l_arg->cell_id, l_arg->data, l_arg->data_size);
         a_es->callbacks.arg = NULL;
diff --git a/modules/common/dap_chain_common.c b/modules/common/dap_chain_common.c
index fc613668244d38ff576d2b8a2f12b0d151ef95e3..17033619a799a78f5df5fd13544550d0618251f4 100644
--- a/modules/common/dap_chain_common.c
+++ b/modules/common/dap_chain_common.c
@@ -42,10 +42,9 @@ const dap_chain_net_srv_uid_t c_dap_chain_net_srv_uid_null = {0};
 /*
  * Forward declarations
  */
-#define DAP_CHAIN$SZ_MAX128DEC DATOSHI_POW                                           /* "340282366920938463463374607431768211455" */
-#define DAP_CHAIN$SZ_MAX256DEC DATOSHI_POW256                                       /* 2 ^ "340282366920938463463374607431768211455" */
-#define SZ_MAX256SCINOT 83                  //1.15792089237316195423570985008687907853269984665640564039457584007913129639935e77
-
+#define DAP_CHAIN$SZ_MAX128DEC DATOSHI_POW                                          /* "340282366920938463463374607431768211455" */
+#define DAP_CHAIN$SZ_MAX256DEC DATOSHI_POW256                                       /* 2 ^ 256 = 1.15792089237316195423570985008687907853269984665640564039457584007913129639935e77*/
+#define DAP_SZ_MAX256SCINOT (DATOSHI_POW256 + 5)
 
 char        *dap_cvt_uint256_to_str (uint256_t a_uint256);
 uint256_t   dap_cvt_str_to_uint256 (const char *a_256bit_num);
@@ -115,25 +114,6 @@ dap_chain_addr_t* dap_chain_addr_from_str(const char *a_str)
     return NULL;
 }
 
-#if 0
-/**
- * @brief dap_chain_net_id_from_str
- * @param a_net_str
- * @return
- */
-dap_chain_net_id_t dap_chain_net_id_from_str(const char * a_net_str)
-{
-    dap_chain_net_id_t l_ret={ 0 };
-    log_it(L_DEBUG, "net id: %s", a_net_str);
-
-    if (!(l_ret.uint64 = strtoll(a_net_str, NULL, 0))) {
-        log_it(L_ERROR, "Wrong input string \"%s\" not recognized as network id", a_net_str);
-        return l_ret;
-    }
-    return l_ret;
-}
-#endif
-
 /**
  * @brief dap_chain_net_srv_uid_from_str
  * @param a_net_str
@@ -387,7 +367,7 @@ char *dap_chain_balance_to_coins256(uint256_t a_balance)
         l_strlen = l_len;                                                   /* Adjust string len in the buffer */
     }
 
-    for ( l_cp = l_buf + strlen(l_buf) - 1; *l_cp == '0'; l_cp--)
+    for ( l_cp = l_buf + strlen(l_buf) - 1; *l_cp == '0' && l_cp >= l_buf; l_cp--)
         if (*(l_cp - 1) != '.')
             *l_cp = '\0';
 
@@ -569,23 +549,22 @@ uint256_t dap_chain_coins_to_balance256(const char *a_coins)
 {
     int l_len, l_pos;
     char    l_buf  [DAP_CHAIN$SZ_MAX256DEC + 8] = {0}, *l_point;
-    uint256_t l_nul = {0};
 
     /* "12300000000.0000456" */
-    if ( (l_len = strnlen(a_coins, DATOSHI_POW256 + 1)) > DATOSHI_POW256)/* Check for legal length */ /* 1 symbol for \0, one for '.', if more, there is an error */
+    if ( (l_len = strnlen(a_coins, DATOSHI_POW256 + 2)) > DATOSHI_POW256 + 1)/* Check for legal length */ /* 1 symbol for \0, one for '.', if more, there is an error */
         return  log_it(L_WARNING, "Incorrect balance format of '%s' - too long (%d > %d)", a_coins,
-                       l_len, DATOSHI_POW256), l_nul;
+                       l_len, DATOSHI_POW256 + 1), uint256_0;
 
     /* Find , check and remove 'precision' dot symbol */
     memcpy (l_buf, a_coins, l_len);                                         /* Make local copy */
     if ( !(l_point = memchr(l_buf, '.', l_len)) )                           /* Is there 'dot' ? */
         return  log_it(L_WARNING, "Incorrect balance format of '%s' - no precision mark", a_coins),
-                l_nul;
+                uint256_0;
 
     l_pos = l_len - (l_point - l_buf);                                      /* Check number of decimals after dot */
     l_pos--;
     if ( (l_pos ) >  DATOSHI_DEGREE )
-        return  log_it(L_WARNING, "Incorrect balance format of '%s' - too much precision", l_buf), l_nul;
+        return  log_it(L_WARNING, "Incorrect balance format of '%s' - too much precision", l_buf), uint256_0;
 
     /* "123.456" -> "123456" */
     memmove(l_point, l_point + 1, l_pos);                                   /* Shift left a right part of the decimal string
@@ -608,26 +587,19 @@ uint256_t dap_chain_coins_to_balance256(const char *a_coins)
 
 
 char *dap_cvt_uint256_to_str(uint256_t a_uint256) {
-    char *l_buf = DAP_NEW_Z_SIZE(char, DATOSHI_POW256 + 1);
-#ifdef DAP_GLOBAL_IS_INT128
+    char *l_buf = DAP_NEW_Z_SIZE(char, DATOSHI_POW256 + 2); // for decimal dot and trailing zero
     int l_pos = 0;
     uint256_t l_value = a_uint256;
     uint256_t uint256_ten = GET_256_FROM_64(10);
     uint256_t rem;
     do {
         divmod_impl_256(l_value, uint256_ten, &l_value, &rem);
+#ifdef DAP_GLOBAL_IS_INT128
         l_buf[l_pos++] = rem.lo + '0';
-    } while (!IS_ZERO_256(l_value));
 #else
-    int l_pos = 0;
-    uint256_t l_value = a_uint256;
-    uint256_t uint256_ten = GET_256_FROM_64(10);
-    uint256_t rem;
-    do {
-        divmod_impl_256(l_value, uint256_ten, &l_value, &rem);
         l_buf[l_pos++] = rem.lo.lo + (unsigned long long) '0';
-    } while (!IS_ZERO_256(l_value));
 #endif
+    } while (!IS_ZERO_256(l_value));
     int l_strlen = strlen(l_buf) - 1;
     for (int i = 0; i < (l_strlen + 1) / 2; i++) {
         char c = l_buf[i];
@@ -806,7 +778,6 @@ const union __c_pow10_double__ {
 
 /*
  *   DESCRIPTION: Convert decimal text string into the uint256_t binary representative.
- *      We calling twice 128 bit variant of convertors
  *
  *   INPUTS:
  *      a_256bit_num:   Decimal string to be converted
@@ -826,20 +797,19 @@ uint256_t dap_cvt_str_to_uint256(const char *a_256bit_num)
     char l_256bit_num[DAP_CHAIN$SZ_MAX256DEC + 1];
     int overflow_flag = 0;
 
-
     if (!a_256bit_num) {
         return log_it(L_ERROR, "NULL as an argument"), l_nul;
     }
 
-    /* Compute & check length */
-    if ( (l_strlen = strnlen(a_256bit_num, SZ_MAX256SCINOT + 1) ) > SZ_MAX256SCINOT)
-        return  log_it(L_ERROR, "Too many digits in `%s` (%d > %d)", a_256bit_num, l_strlen, SZ_MAX256SCINOT), l_nul;
-
     /* Convert number from xxx.yyyyE+zz to xxxyyyy0000... */
     char *l_eptr = strchr(a_256bit_num, 'e');
     if (!l_eptr)
         l_eptr = strchr(a_256bit_num, 'E');
     if (l_eptr) {
+        /* Compute & check length */
+        if ( (l_strlen = strnlen(a_256bit_num, DAP_SZ_MAX256SCINOT + 1) ) > DAP_SZ_MAX256SCINOT)
+            return  log_it(L_ERROR, "Too many digits in `%s` (%d > %d)", a_256bit_num, l_strlen, DAP_SZ_MAX256SCINOT), l_nul;
+
         char *l_exp_ptr = l_eptr + 1;
         if (*l_exp_ptr == '+')
             l_exp_ptr++;
@@ -850,33 +820,34 @@ uint256_t dap_cvt_str_to_uint256(const char *a_256bit_num)
         if (!l_dot_ptr || l_dot_ptr > l_eptr)
             return  log_it(L_ERROR, "Invalid number format with exponent %d", l_exp), uint256_0;
         int l_dot_len = l_dot_ptr - a_256bit_num;
-        if (l_dot_len >= SZ_MAX256SCINOT)
+        if (l_dot_len >= DATOSHI_POW256)
             return log_it(L_ERROR, "Too many digits in '%s'", a_256bit_num), uint256_0;
         int l_exp_len = l_eptr - a_256bit_num - l_dot_len - 1;
-        if (l_exp_len + l_dot_len + 1 >= SZ_MAX256SCINOT)
+        if (l_exp_len + l_dot_len + 1 >= DATOSHI_POW256)
             return log_it(L_ERROR, "Too many digits in '%s'", a_256bit_num), uint256_0;
         if (l_exp < l_exp_len) {
             //todo: we need to handle numbers like 1.23456789000000e9
-            return log_it(L_ERROR, "Invalid number format with exponent %d and nuber coun after dot %d", l_exp,
+            return log_it(L_ERROR, "Invalid number format with exponent %d and number count after dot %d", l_exp,
                           l_exp_len), uint256_0;
         }
         memcpy(l_256bit_num, a_256bit_num, l_dot_len);
         memcpy(l_256bit_num + l_dot_len, a_256bit_num + l_dot_len + 1, l_exp_len);
         int l_zero_cnt = l_exp - l_exp_len;
-        if (l_zero_cnt > DAP_CHAIN$SZ_MAX256DEC) {
+        if (l_zero_cnt > DATOSHI_POW256) {
             //todo: need to handle leading zeroes, like 0.000...123e100
             return log_it(L_ERROR, "Too long number for 256 bit: `%s` (%d > %d)", a_256bit_num, l_strlen, DAP_CHAIN$SZ_MAX256DEC), l_nul;
         }
         size_t l_pos = l_dot_len + l_exp_len;
-        for (int i = l_zero_cnt; i && l_pos < DAP_CHAIN$SZ_MAX256DEC; i--)
+        for (int i = l_zero_cnt; i && l_pos < DATOSHI_POW256; i--)
             l_256bit_num[l_pos++] = '0';
         l_256bit_num[l_pos] = '\0';
         l_strlen = l_pos;
 
     } else {
-        //we ahve an decimal string, not sci notation
-        if ( (l_strlen = strnlen(a_256bit_num, DAP_CHAIN$SZ_MAX256DEC + 1) ) > DAP_CHAIN$SZ_MAX256DEC)
-            return  log_it(L_ERROR, "Too many digits in `%s` (%d > %d)", a_256bit_num, l_strlen, DAP_CHAIN$SZ_MAX256DEC), l_nul;
+        // We have a decimal string, not sci notation
+        /* Compute & check length */
+        if ( (l_strlen = strnlen(a_256bit_num, DATOSHI_POW256 + 1) ) > DATOSHI_POW256)
+            return  log_it(L_ERROR, "Too many digits in `%s` (%d > %d)", a_256bit_num, l_strlen, DATOSHI_POW256), l_nul;
         memcpy(l_256bit_num, a_256bit_num, l_strlen);
         l_256bit_num[l_strlen] = '\0';
     }
@@ -962,7 +933,7 @@ uint256_t dap_cvt_str_to_uint256(const char *a_256bit_num)
 }
 
 
-uint256_t dap_chain_coins_to_balance(const char *a_coins)
+inline uint256_t dap_chain_coins_to_balance(const char *a_coins)
 {
     return  dap_chain_coins_to_balance256(a_coins);
     // return GET_256_FROM_128(dap_chain_coins_to_balance128(a_coins));
@@ -970,14 +941,14 @@ uint256_t dap_chain_coins_to_balance(const char *a_coins)
 
 
 
-char *dap_chain_balance_to_coins(uint256_t a_balance)
+inline char *dap_chain_balance_to_coins(uint256_t a_balance)
 {
     return dap_chain_balance_to_coins256(a_balance); /* @RRL */
     //return dap_chain_balance_to_coins128(a_balance.lo);
 }
 
 
-#define __NEW_STARLET__ "BMF"
+//#define __NEW_STARLET__ "BMF"
 #ifdef  __NEW_STARLET__
 
 
diff --git a/modules/common/dap_chain_datum.c b/modules/common/dap_chain_datum.c
index 68eb357f2dff9b129fcaef22cd45443d0912a274..7240e64b6c64e7ca89568132c3ab978830ba167d 100644
--- a/modules/common/dap_chain_datum.c
+++ b/modules/common/dap_chain_datum.c
@@ -30,7 +30,6 @@
 #include "dap_chain_datum_token.h"
 #include "dap_chain_datum_tx_items.h"
 #include "dap_chain_datum_hashtree_roots.h"
-#include "dap_chain_datum_token.h"
 #include "dap_enc_base58.h"
 
 #define LOG_TAG "dap_chain_datum"
@@ -399,13 +398,13 @@ bool dap_chain_datum_dump_tx(dap_chain_datum_tx_t *a_datum,
         case TX_ITEM_TYPE_OUT_COND: {
             char *l_value_str = dap_chain_balance_print(((dap_chain_tx_out_cond_t*)item)->header.value);
             char *l_coins_str = dap_chain_balance_to_coins(((dap_chain_tx_out_cond_t*)item)->header.value);
+            dap_time_t l_ts_exp = ((dap_chain_tx_out_cond_t*)item)->header.ts_expires;
             dap_string_append_printf(a_str_out, "\t OUT COND:\n"
                                                 "\t Header:\n"
-                                                "\t\t\t ts_expires: %s\t"
-                                                "\t\t\t value: %s (%s)\n"
-                                                "\t\t\t subtype: %s\n"
-                                                "\t\t SubType:\n",
-                                     dap_ctime_r((dap_time_t*)((dap_chain_tx_out_cond_t*)item)->header.ts_expires, l_tmp_buf),
+                                                "\t\t ts_expires: %s"
+                                                "\t\t value: %s (%s)\n"
+                                                "\t\t subtype: %s\n",
+                                     l_ts_exp ? dap_ctime_r(&l_ts_exp, l_tmp_buf) : "never\n",
                                      l_coins_str,
                                      l_value_str,
                                      dap_chain_tx_out_cond_subtype_to_str(((dap_chain_tx_out_cond_t*)item)->header.subtype));
@@ -460,6 +459,20 @@ bool dap_chain_datum_dump_tx(dap_chain_datum_tx_t *a_datum,
                     DAP_DELETE(l_value_str);
                     DAP_DELETE(l_coins_str);
                 } break;
+                case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK: {
+                    dap_time_t l_ts_exp = ((dap_chain_tx_out_cond_t*)item)->subtype.srv_stake_lock.time_unlock;
+                    char *l_value_str = dap_chain_balance_print(((dap_chain_tx_out_cond_t*)item)->header.value);
+                    char *l_coins_str = dap_chain_balance_to_coins(((dap_chain_tx_out_cond_t*)item)->header.value);
+                    dap_string_append_printf(a_str_out, "\t\t\t uid: 0x%016"DAP_UINT64_FORMAT_x"\n"
+                                                        "\t\t\t value: %s (%s)\n"
+                                                        "\t\t\t time_unlock %s\n",
+                                             ((dap_chain_tx_out_cond_t*)item)->header.srv_uid.uint64,
+                                             l_coins_str,
+                                             l_value_str,
+                                             dap_ctime_r(&l_ts_exp, l_tmp_buf));
+                    DAP_DELETE(l_value_str);
+                    DAP_DELETE(l_coins_str);
+                } break;
                 default: break;
             }
         } break;
@@ -544,8 +557,18 @@ void dap_chain_datum_dump(dap_string_t *a_str_out, dap_chain_datum_t *a_datum, c
                     DAP_DEL_Z(l_value_str);
                 }break;
                 case DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE:{
+                    char *l_value_str = dap_chain_balance_print(l_token->total_supply);
                     dap_string_append(a_str_out,"type: PRIVATE_UPDATE\n");
+                    dap_string_append(a_str_out, "decimals: 18\n");
+                    dap_string_append_printf(a_str_out, "auth signs (valid/total) %u/%u\n", l_token->signs_valid, l_token->signs_total);
+                    dap_string_append_printf(a_str_out, "total_supply: %s\n", l_value_str);
+                    dap_string_append(a_str_out,"flags: ");
+                    dap_chain_datum_token_flags_dump(a_str_out, l_token->header_private_update.flags);
                     s_datum_token_dump_tsd(a_str_out, l_token, l_token_size, a_hash_out_type);
+                    size_t l_certs_field_size = l_token_size - sizeof(*l_token) - l_token->header_private_update.tsd_total_size;
+                    dap_chain_datum_token_certs_dump(a_str_out, l_token->data_n_tsd + l_token->header_private_update.tsd_total_size,
+                                                     l_certs_field_size, a_hash_out_type);
+                    DAP_DEL_Z(l_value_str);
                 }break;
                 case DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL:{
                     char *l_value_str = dap_chain_balance_print(l_token->total_supply);
@@ -562,8 +585,18 @@ void dap_chain_datum_dump(dap_string_t *a_str_out, dap_chain_datum_t *a_datum, c
                     DAP_DEL_Z(l_value_str);
                 }break;
                 case DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_UPDATE:{
+                    char *l_value_str = dap_chain_balance_print(l_token->total_supply);
                     dap_string_append_printf(a_str_out,"type: CF20_UPDATE\n");
+                    dap_string_append(a_str_out, "decimals: 18\n");
+                    dap_string_append_printf(a_str_out, "auth signs (valid/total) %u/%u\n", l_token->signs_valid, l_token->signs_total);
+                    dap_string_append_printf(a_str_out, "total_supply: %s\n", l_value_str);
+                    dap_string_append(a_str_out, "flags: ");
+                    dap_chain_datum_token_flags_dump(a_str_out, l_token->header_native_update.flags);
                     s_datum_token_dump_tsd(a_str_out, l_token, l_token_size, a_hash_out_type);
+                    size_t l_certs_field_size = l_token_size - sizeof(*l_token) - l_token->header_native_update.tsd_total_size;
+                    dap_chain_datum_token_certs_dump(a_str_out, l_token->data_n_tsd + l_token->header_native_update.tsd_total_size,
+                                                     l_certs_field_size, a_hash_out_type);
+                    DAP_DEL_Z(l_value_str);
                 }break;
                 case DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL:{
                     char *l_value_str = dap_chain_balance_print(l_token->total_supply);
diff --git a/modules/common/dap_chain_datum_token.c b/modules/common/dap_chain_datum_token.c
index a2e464d01027e6f220b8441fea3964bcab9a2ba4..87b17712b23fda755554c268b1ec95011ac4e5cb 100644
--- a/modules/common/dap_chain_datum_token.c
+++ b/modules/common/dap_chain_datum_token.c
@@ -38,12 +38,6 @@ const char *c_dap_chain_datum_token_emission_type_str[]={
     [DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_ALGO] = "ALGO",
     [DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_ATOM_OWNER] = "OWNER",
     [DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_SMART_CONTRACT] = "SMART_CONTRACT"
-// 256 types
-    // [DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_256_UNDEFINED] = "UNDEFINED",
-    // [DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_256_AUTH] = "AUTH",
-    // [DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_256_ALGO] = "ALGO",
-    // [DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_256_ATOM_OWNER] = "OWNER",
-    // [DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_256_SMART_CONTRACT] = "SMART_CONTRACT"
 };
 
 const char *c_dap_chain_datum_token_flag_str[] = {
@@ -182,18 +176,27 @@ dap_sign_t ** dap_chain_datum_token_signs_parse(dap_chain_datum_token_t * a_datu
     size_t l_offset = 0;
     size_t l_signs_offset = 0;
     switch (a_datum_token->type) {
-        case DAP_CHAIN_DATUM_TOKEN_TYPE_OLD_SIMPLE:
-            l_signs_offset = sizeof(dap_chain_datum_token_old_t);
-            break;
-        case DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE:
-            l_signs_offset = sizeof(dap_chain_datum_token_t);
-            break;
-        case DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL:
-        case DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL:
-            l_signs_offset = sizeof(dap_chain_datum_token_t) + a_datum_token->header_native_decl.tsd_total_size;
-            break;
-        default:
-            break;
+    case DAP_CHAIN_DATUM_TOKEN_TYPE_OLD_SIMPLE:
+        l_signs_offset = sizeof(dap_chain_datum_token_old_t);
+        break;
+    case DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE:
+        l_signs_offset = sizeof(dap_chain_datum_token_t);
+        break;
+    case DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL:
+        l_signs_offset = sizeof(dap_chain_datum_token_t) + a_datum_token->header_native_decl.tsd_total_size;
+        break;
+    case DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL:
+        l_signs_offset = sizeof(dap_chain_datum_token_t) + a_datum_token->header_private_decl.tsd_total_size;
+        break;
+    case DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_UPDATE:
+        l_signs_offset = sizeof(dap_chain_datum_token_t) + a_datum_token->header_native_update.tsd_total_size;
+        break;
+    case DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE:
+        l_signs_offset = sizeof(dap_chain_datum_token_t) + a_datum_token->header_private_update.tsd_total_size;
+        break;
+    default:
+        l_signs_offset = sizeof(dap_chain_datum_token_t);
+        break;
     }
     dap_sign_t **l_ret = DAP_NEW_Z_SIZE(dap_sign_t*, sizeof(dap_sign_t*) * a_datum_token->signs_total);
     if (!l_ret) {
diff --git a/modules/common/dap_chain_datum_tx.c b/modules/common/dap_chain_datum_tx.c
index 927f078cfba81dbea2dc87fb3175c4ea2a78c973..82d01e2becb1f3d12096024e8f6cf51838ae1097 100644
--- a/modules/common/dap_chain_datum_tx.c
+++ b/modules/common/dap_chain_datum_tx.c
@@ -158,22 +158,6 @@ int dap_chain_datum_tx_add_fee_item(dap_chain_datum_tx_t **a_tx, uint256_t a_val
     return -1;
 }
 
-/**
- * Create 'out_cond' item with fee stake value and insert to transaction
- *
- * return 1 Ok, -1 Error
- */
-int dap_chain_datum_tx_add_fee_stake_item(dap_chain_datum_tx_t **a_tx, uint256_t a_value)
-{
-    dap_chain_tx_out_cond_t *l_tx_out_fee_stake = dap_chain_datum_tx_item_out_cond_create_fee_stake(a_value);
-    if(l_tx_out_fee_stake) {
-        dap_chain_datum_tx_add_item(a_tx, (const uint8_t*) l_tx_out_fee_stake);
-        DAP_DELETE(l_tx_out_fee_stake);
-        return 1;
-    }
-    return -1;
-}
-
 /**
  * Create 'out' item and insert to transaction
  *
@@ -270,7 +254,7 @@ int dap_chain_datum_tx_verify_sign(dap_chain_datum_tx_t *tx)
                 log_it(L_WARNING,"Incorrect signature's header, possible corrupted data");
                 return -4;
             }
-            if (!dap_sign_verify_size(l_sign, tx_items_size) || dap_sign_verify(l_sign, tx->tx_items, tx_items_pos) != 1) {
+            if (dap_sign_verify_all(l_sign, tx_items_size, tx->tx_items, tx_items_pos)) {
                 // invalid signature
                 ret = 0;
                 tx_items_pos += l_item_tx_size;
diff --git a/modules/common/dap_chain_datum_tx_items.c b/modules/common/dap_chain_datum_tx_items.c
index ddf05b010414d73285fed2a3962e011dc283fb51..ddbd99d53b56f1879b8135d13dbf1a31877f38f5 100644
--- a/modules/common/dap_chain_datum_tx_items.c
+++ b/modules/common/dap_chain_datum_tx_items.c
@@ -76,7 +76,8 @@ static size_t dap_chain_tx_out_ext_get_size(const dap_chain_tx_out_ext_t *a_item
 
 static size_t dap_chain_tx_out_cond_get_size(const dap_chain_tx_out_cond_t *a_item)
 {
-    return sizeof(dap_chain_tx_out_cond_t) + a_item->params_size;
+    size_t size = sizeof(dap_chain_tx_out_cond_t) + a_item->tsd_size;
+    return size;
 }
 
 static size_t dap_chain_tx_pkey_get_size(const dap_chain_tx_pkey_t *a_item)
@@ -149,8 +150,6 @@ dap_chain_tx_out_cond_subtype_t dap_chain_tx_out_cond_subtype_from_str(const cha
         return DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE;
     else if (!dap_strcmp(a_subtype_str, "srv_stake_lock"))
         return DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK;
-    else if(!dap_strcmp(a_subtype_str, "srv_stake_update"))
-        return DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE_UPDATE;
     else if(!dap_strcmp(a_subtype_str, "fee"))
         return DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE;
     return DAP_CHAIN_TX_OUT_COND_SUBTYPE_UNDEFINED;
@@ -228,7 +227,7 @@ dap_chain_tx_token_t *dap_chain_datum_tx_item_token_create(dap_chain_id_t a_id,
     dap_chain_tx_token_t *l_item = DAP_NEW_Z(dap_chain_tx_token_t);
     l_item->header.type = TX_ITEM_TYPE_TOKEN;
     l_item->header.token_emission_chain_id.uint64 = a_id.uint64;
-    memcpy (& l_item->header.token_emission_hash, a_datum_token_hash, sizeof ( *a_datum_token_hash ) );
+    l_item->header.token_emission_hash = *a_datum_token_hash;;
     strncpy(l_item->header.ticker, a_ticker, sizeof(l_item->header.ticker) - 1);
     return l_item;
 }
@@ -310,22 +309,6 @@ dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_fee(uint256_t a
     return l_item;
 }
 
-/**
- * Create item dap_chain_tx_out_cond_t with fee stake subtype
- *
- * return item, NULL Error
- */
-dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_fee_stake(uint256_t a_value)
-{
-    if (IS_ZERO_256(a_value))
-        return NULL;
-    dap_chain_tx_out_cond_t *l_item = DAP_NEW_Z(dap_chain_tx_out_cond_t);
-    l_item->header.item_type = TX_ITEM_TYPE_OUT_COND;
-    l_item->header.value = a_value;
-    l_item->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STAKE;
-    return l_item;
-}
-
 /**
  * Create item dap_chain_tx_out_cond_t
  *
@@ -352,8 +335,8 @@ dap_chain_tx_out_cond_t* dap_chain_datum_tx_item_out_cond_create_srv_pay(dap_pke
     l_item->subtype.srv_pay.unit_price_max_datoshi = a_value_max_per_unit;
     dap_hash_fast(a_key->pkey, a_key->header.size, &l_item->subtype.srv_pay.pkey_hash);
     if (a_params && a_params_size) {
-        l_item->params_size = (uint32_t)a_params_size;
-        memcpy(l_item->params, a_params, a_params_size);
+        l_item->tsd_size = (uint32_t)a_params_size;
+        memcpy(l_item->tsd, a_params, a_params_size);
     }
     return l_item;
 }
@@ -361,6 +344,7 @@ dap_chain_tx_out_cond_t* dap_chain_datum_tx_item_out_cond_create_srv_pay(dap_pke
 dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_srv_xchange(dap_chain_net_srv_uid_t a_srv_uid, dap_chain_net_id_t a_sell_net_id,
                                                                              uint256_t a_value_sell, dap_chain_net_id_t a_buy_net_id,
                                                                              const char *a_token, uint256_t a_value_buy,
+                                                                             const dap_chain_addr_t *a_seller_addr,
                                                                              const void *a_params, uint32_t a_params_size)
 {
     if (!a_token)
@@ -376,9 +360,10 @@ dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_srv_xchange(dap
     l_item->subtype.srv_xchange.sell_net_id = a_sell_net_id;
     strncpy(l_item->subtype.srv_xchange.buy_token, a_token, DAP_CHAIN_TICKER_SIZE_MAX);
     l_item->subtype.srv_xchange.buy_value = a_value_buy;
-    l_item->params_size = a_params_size;
+    l_item->subtype.srv_xchange.seller_addr = *a_seller_addr;
+    l_item->tsd_size = a_params_size;
     if (a_params_size) {
-        memcpy(l_item->params, a_params, a_params_size);
+        memcpy(l_item->tsd, a_params, a_params_size);
     }
     return l_item;
 }
@@ -441,12 +426,12 @@ dap_sign_t* dap_chain_datum_tx_item_sign_get_sig(dap_chain_tx_sig_t *a_tx_sig)
  * Get item from transaction
  *
  * a_tx [in] transaction
- * a_item_idx_start[in/out] start index / found index of item in transaction, if 0 then from beginning
+ * a_item_idx[in/out] start index / found index of item in transaction, if 0 then from beginning
  * a_type[in] type of item being find, if TX_ITEM_TYPE_ANY - any item
  * a_item_out_size size[out] size of returned item
  * return item data, NULL Error index or bad format transaction
  */
-uint8_t* dap_chain_datum_tx_item_get( dap_chain_datum_tx_t *a_tx, int *a_item_idx_start,
+uint8_t* dap_chain_datum_tx_item_get( dap_chain_datum_tx_t *a_tx, int *a_item_idx,
         dap_chain_tx_item_type_t a_type, int *a_item_out_size)
 {
     if(!a_tx)
@@ -459,7 +444,7 @@ uint8_t* dap_chain_datum_tx_item_get( dap_chain_datum_tx_t *a_tx, int *a_item_id
         if(!l_item_size)
             return NULL;
         // check index
-        if(!a_item_idx_start || l_item_idx >= *a_item_idx_start) {
+        if(!a_item_idx || l_item_idx >= *a_item_idx) {
             // check type
             dap_chain_tx_item_type_t l_type = dap_chain_datum_tx_item_get_type(l_item);
             if (a_type == TX_ITEM_TYPE_ANY || a_type == l_type ||
@@ -467,8 +452,8 @@ uint8_t* dap_chain_datum_tx_item_get( dap_chain_datum_tx_t *a_tx, int *a_item_id
                     (a_type == TX_ITEM_TYPE_OUT_ALL && l_type == TX_ITEM_TYPE_OUT_OLD) ||
                     (a_type == TX_ITEM_TYPE_OUT_ALL && l_type == TX_ITEM_TYPE_OUT_COND) ||
                     (a_type == TX_ITEM_TYPE_OUT_ALL && l_type == TX_ITEM_TYPE_OUT_EXT)) {
-                if(a_item_idx_start)
-                    *a_item_idx_start = l_item_idx;
+                if(a_item_idx)
+                    *a_item_idx = l_item_idx;
                 if(a_item_out_size)
                     *a_item_out_size = l_item_size;
                 return l_item;
@@ -494,7 +479,7 @@ dap_list_t* dap_chain_datum_tx_items_get(dap_chain_datum_tx_t *a_tx, dap_chain_t
     int l_items_count = 0, l_item_idx_start = 0;
     uint8_t *l_tx_item;
 
-    // Get a_type item from transaction
+    // Get a_type items from transaction
     while ((l_tx_item = dap_chain_datum_tx_item_get(a_tx, &l_item_idx_start, a_type, NULL)) != NULL)
     {
         items_list = dap_list_append(items_list, l_tx_item);
@@ -508,29 +493,44 @@ dap_list_t* dap_chain_datum_tx_items_get(dap_chain_datum_tx_t *a_tx, dap_chain_t
     return items_list;
 }
 
+uint8_t *dap_chain_datum_tx_item_get_nth(dap_chain_datum_tx_t *a_tx, dap_chain_tx_item_type_t a_type, int a_item_idx)
+{
+    uint8_t *l_tx_item;
+    int l_item_idx = 0;
+    for (int l_type_idx = 0; l_type_idx <= a_item_idx; l_type_idx++) {
+        l_tx_item = dap_chain_datum_tx_item_get(a_tx, &l_item_idx, a_type, NULL);
+        if (!l_tx_item)
+            break;
+        l_item_idx++;
+    }
+    return l_tx_item;
+}
+
 /**
  * Get tx_out_cond item from transaction
  *
  * a_tx [in] transaction
- * a_out_num[in/out] start index / found index of item in transaction, if 0 then from beginning
+ * a_cond_type [in] type of condition to find
+ * a_out_num[out] found index of item in transaction, -1 if not found
  * return tx_out_cond, or NULL
  */
-dap_chain_tx_out_cond_t *dap_chain_datum_tx_out_cond_get(dap_chain_datum_tx_t *a_tx, int *a_out_num)
+dap_chain_tx_out_cond_t *dap_chain_datum_tx_out_cond_get(dap_chain_datum_tx_t *a_tx, dap_chain_tx_item_type_t a_cond_type, int *a_out_num)
 {
     dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_OUT_ALL, NULL);
-    int l_prev_cond_idx = l_list_out_items ? 0 : -1;
+    int l_prev_cond_idx = l_list_out_items ? (a_out_num ? *a_out_num : 0) : -1;
     dap_chain_tx_out_cond_t *l_res = NULL;
     for (dap_list_t *l_list_tmp = l_list_out_items; l_list_tmp; l_list_tmp = dap_list_next(l_list_tmp), l_prev_cond_idx++) {
         // Start from *a_out_num item if a_out_num != NULL
         if(a_out_num && *a_out_num && l_prev_cond_idx <= *a_out_num)
             continue;
-        if (*(uint8_t *)l_list_tmp->data == TX_ITEM_TYPE_OUT_COND) {
+        if (*(uint8_t *)l_list_tmp->data == TX_ITEM_TYPE_OUT_COND &&
+                ((dap_chain_tx_out_cond_t *)l_list_tmp->data)->header.subtype == a_cond_type) {
             l_res = l_list_tmp->data;
             break;
         }
     }
     dap_list_free(l_list_out_items);
-    if (a_out_num) {
+    if (a_out_num && l_res) {
         *a_out_num = l_prev_cond_idx;
     }
     return l_res;
diff --git a/modules/common/include/dap_chain_common.h b/modules/common/include/dap_chain_common.h
index fe8c66d844b38fc22f4844d8c876ecd998491fdb..1ec63018bce6e77c14cd4e00360086a9b50c2ba3 100644
--- a/modules/common/include/dap_chain_common.h
+++ b/modules/common/include/dap_chain_common.h
@@ -214,10 +214,11 @@ enum dap_chain_tx_item_type {
 
     TX_ITEM_TYPE_RECEIPT = 0x70,
 
+    TX_ITEM_TYPE_IN_ALL = 0xfd,
     TX_ITEM_TYPE_OUT_ALL = 0xfe,
-    TX_ITEM_TYPE_ANY = 0xff,
-    TX_ITEM_TYPE_UNKNOWN = 0xff
+    TX_ITEM_TYPE_ANY = 0xff
 };
+#define TX_ITEM_TYPE_UNKNOWN TX_ITEM_TYPE_ANY
 typedef byte_t dap_chain_tx_item_type_t;
 
 typedef struct dap_chain_receipt_info {
@@ -242,9 +243,6 @@ size_t dap_chain_hash_slow_to_str(dap_chain_hash_slow_t * a_hash, char * a_str,
 char* dap_chain_addr_to_str(const dap_chain_addr_t *a_addr);
 dap_chain_addr_t* dap_chain_addr_from_str(const char *str);
 
-#if 0
-dap_chain_net_id_t dap_chain_net_id_from_str(const char* a_str);
-#endif
 dap_chain_net_srv_uid_t dap_chain_net_srv_uid_from_str(const char* a_str);
 
 void dap_chain_addr_fill(dap_chain_addr_t *a_addr, dap_sign_type_t a_type, dap_chain_hash_fast_t *a_pkey_hash, dap_chain_net_id_t a_net_id);
@@ -264,9 +262,7 @@ DAP_STATIC_INLINE uint64_t dap_chain_coins_to_datoshi(long double a_count)
 
 DAP_STATIC_INLINE uint128_t dap_chain_uint128_from(uint64_t a_from)
 {
-    uint128_t l_ret = uint128_0;
-    ADD_64_INTO_128(a_from, &l_ret );
-    return l_ret;
+    return GET_128_FROM_64(a_from);
 }
 
 // 256
@@ -275,18 +271,12 @@ uint128_t dap_chain_uint128_from_uint256(uint256_t a_from);
 // 256
 DAP_STATIC_INLINE uint256_t dap_chain_uint256_from(uint64_t a_from)
 {
-    uint128_t l_temp_128 = uint128_0;
-    uint256_t l_ret_256 = uint256_0;
-    ADD_64_INTO_128(a_from, &l_temp_128);
-    ADD_128_INTO_256(l_temp_128, &l_ret_256);
-    return l_ret_256;
+    return GET_256_FROM_64(a_from);
 }
 
 DAP_STATIC_INLINE uint256_t dap_chain_uint256_from_uint128(uint128_t a_from)
 {
-    uint256_t l_ret_256 = uint256_0;
-    ADD_128_INTO_256(a_from, &l_ret_256);
-    return l_ret_256;
+    return GET_256_FROM_128(a_from);
 }
 
 uint64_t dap_chain_uint128_to(uint128_t a_from);
diff --git a/modules/common/include/dap_chain_datum.h b/modules/common/include/dap_chain_datum.h
index 402ba868899b69f3f88d55b4fd9f8a1829df147a..6a61ea4b0eb4a032b7719d42f171dcdf4d336325 100644
--- a/modules/common/include/dap_chain_datum.h
+++ b/modules/common/include/dap_chain_datum.h
@@ -28,6 +28,7 @@
 #include "dap_math_ops.h"
 #include "dap_chain_common.h"
 #include "dap_chain_datum_tx.h"
+#include "dap_chain_datum_token.h"
 
 #define DAP_CHAIN_DATUM_VERSION 0x00
 
@@ -68,7 +69,7 @@
 
 #define DAP_CHAIN_DATUM_CUSTOM               0xffff
 
-#define DAP_DATUM_TYPE_STR(t, s)                \
+#define DAP_DATUM_TYPE_STR(t, s)            \
     switch (t) {                            \
         case DAP_CHAIN_DATUM_TX:            \
             s = "DATUM_TX"; break;          \
@@ -84,7 +85,7 @@
             s = "DATUM_EVM_DATA"; break;    \
         case DAP_CHAIN_DATUM_CA:            \
             s = "DATUM_CA"; break;          \
-	case DAP_CHAIN_DATUM_SIGNER:        \
+        case DAP_CHAIN_DATUM_SIGNER:        \
             s = "DATUM_SIGNER"; break;      \
         case DAP_CHAIN_DATUM_CUSTOM:        \
             s = "DATUM_CUSTOM"; break;      \
@@ -162,6 +163,7 @@ static inline const char *dap_chain_datum_type_id_to_str(uint16_t a_type_id)
     return l_ret;
 }
 
+void s_datum_token_dump_tsd(dap_string_t *a_str_out, dap_chain_datum_token_t *a_token, size_t a_token_size, const char *a_hash_out_type);
 void dap_chain_datum_dump(dap_string_t *a_str_out, dap_chain_datum_t *a_datum, const char *a_hash_out_type);
 bool dap_chain_datum_dump_tx(dap_chain_datum_tx_t *a_datum,
                              const char *a_ticker,
diff --git a/modules/common/include/dap_chain_datum_token.h b/modules/common/include/dap_chain_datum_token.h
index cf3c2cc8b296524b59654e2eee8013b7363b6ada..ffbdd96a6d8b5c0359af575faf4ab89ff6e857c1 100644
--- a/modules/common/include/dap_chain_datum_token.h
+++ b/modules/common/include/dap_chain_datum_token.h
@@ -70,12 +70,13 @@ typedef struct dap_chain_datum_token{
     union {
         // Simple token declaration. Useful for 100% premined emission without any plays with token and owners after that
         struct {
-             // Nothing here
+             uint16_t decimals;
         } DAP_ALIGN_PACKED header_simple;
         // Private token declarations, with flags, manipulations and updates
         struct {
             uint16_t flags; // Token declaration flags
             uint64_t tsd_total_size; // Data size section with values in key-length-value list trailing the signs section
+            uint16_t decimals;
         } DAP_ALIGN_PACKED header_private_decl;
         //native tokens
         struct {
@@ -85,11 +86,15 @@ typedef struct dap_chain_datum_token{
         } DAP_ALIGN_PACKED header_native_decl;
         // Private token update
         struct {
-            uint64_t tsd_total_size; // Data size section with extended values in key-length-value list.
+            uint16_t flags; // Token declaration flags
+            uint64_t tsd_total_size; // Data size section with values in key-length-value list trailing the signs section
+            uint16_t decimals;
         } DAP_ALIGN_PACKED header_private_update;
         // native token update
         struct {
-            uint64_t tsd_total_size; // Data size section with extended values in key-length-value list.
+            uint16_t flags; // Token declaration flags
+            uint64_t tsd_total_size; // Data size section with values in key-length-value list trailing the signs section
+            uint16_t decimals;
         } DAP_ALIGN_PACKED header_native_update;
         // Public token declaration
         struct {
@@ -269,25 +274,25 @@ typedef struct { char *key; uint64_t val; } t_datum_token_flag_struct;
 
 // new__
 static t_datum_token_flag_struct s_flags_table[] = {
-    { "NO_FLAGS", DAP_CHAIN_DATUM_TOKEN_FLAG_NONE}, 
-    { "ALL_BLOCKED", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_SENDER_BLOCKED | DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_RECEIVER_BLOCKED}, 
-    { "ALL_FROZEN", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_SENDER_FROZEN | DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_RECEIVER_FROZEN }, 
+    { "NO_FLAGS", DAP_CHAIN_DATUM_TOKEN_FLAG_NONE},
+    { "ALL_BLOCKED", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_SENDER_BLOCKED | DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_RECEIVER_BLOCKED},
+    { "ALL_FROZEN", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_SENDER_FROZEN | DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_RECEIVER_FROZEN },
     { "ALL_ALLOWED", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_SENDER_ALLOWED | DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_RECEIVER_ALLOWED},
-    { "ALL_UNFROZEN", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_SENDER_UNFROZEN | DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_RECEIVER_UNFROZEN }, 
+    { "ALL_UNFROZEN", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_SENDER_UNFROZEN | DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_RECEIVER_UNFROZEN },
     { "STATIC_ALL", DAP_CHAIN_DATUM_TOKEN_FLAG_STATIC_ALL},
-    { "STATIC_FLAGS", DAP_CHAIN_DATUM_TOKEN_FLAG_STATIC_FLAGS }, 
-    { "STATIC_PERMISSIONS_ALL", DAP_CHAIN_DATUM_TOKEN_FLAG_STATIC_PERMISSIONS_ALL }, 
-    { "STATIC_PERMISSIONS_DATUM_TYPE", DAP_CHAIN_DATUM_TOKEN_FLAG_STATIC_PERMISSIONS_DATUM_TYPE }, 
+    { "STATIC_FLAGS", DAP_CHAIN_DATUM_TOKEN_FLAG_STATIC_FLAGS },
+    { "STATIC_PERMISSIONS_ALL", DAP_CHAIN_DATUM_TOKEN_FLAG_STATIC_PERMISSIONS_ALL },
+    { "STATIC_PERMISSIONS_DATUM_TYPE", DAP_CHAIN_DATUM_TOKEN_FLAG_STATIC_PERMISSIONS_DATUM_TYPE },
     { "STATIC_PERMISSIONS_TX_SENDER", DAP_CHAIN_DATUM_TOKEN_FLAG_STATIC_PERMISSIONS_TX_SENDER },
     { "STATIC_PERMISSIONS_TX_RECEIVER", DAP_CHAIN_DATUM_TOKEN_FLAG_STATIC_PERMISSIONS_TX_RECEIVER },
-    { "ALL_SENDER_BLOCKED", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_SENDER_BLOCKED}, 
-    { "ALL_SENDER_FROZEN", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_SENDER_FROZEN}, 
+    { "ALL_SENDER_BLOCKED", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_SENDER_BLOCKED},
+    { "ALL_SENDER_FROZEN", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_SENDER_FROZEN},
     { "ALL_SENDER_ALLOWED", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_SENDER_ALLOWED},
-    { "ALL_SENDER_UNFROZEN", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_SENDER_UNFROZEN}, 
-    { "ALL_RECEIVER_BLOCKED", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_RECEIVER_BLOCKED}, 
-    { "ALL_RECEIVER_FROZEN", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_RECEIVER_FROZEN }, 
+    { "ALL_SENDER_UNFROZEN", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_SENDER_UNFROZEN},
+    { "ALL_RECEIVER_BLOCKED", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_RECEIVER_BLOCKED},
+    { "ALL_RECEIVER_FROZEN", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_RECEIVER_FROZEN },
     { "ALL_RECEIVER_ALLOWED", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_RECEIVER_ALLOWED},
-    { "ALL_RECEIVER_UNFROZEN", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_RECEIVER_UNFROZEN }, 
+    { "ALL_RECEIVER_UNFROZEN", DAP_CHAIN_DATUM_TOKEN_FLAG_ALL_RECEIVER_UNFROZEN },
 };
 
 
@@ -329,7 +334,7 @@ static inline char* s_flag_str_from_code(uint64_t code)
                 s_multiple_flag = dap_strjoin(";", s_multiple_flag, s_flags_table[i].key, (char*)NULL);
             else
                 s_multiple_flag = dap_strjoin(NULL, s_multiple_flag, s_flags_table[i].key, (char*)NULL);
-        }         
+        }
     }
 
     char* s_no_flags = "NO FLAGS";
@@ -346,7 +351,7 @@ static inline char* s_flag_str_from_code(uint64_t code)
  * @return
  */
 static inline char* dap_chain_datum_str_token_flag_from_code(uint64_t code)
-{   
+{
     return s_flag_str_from_code(code);
 }
 
@@ -359,7 +364,7 @@ static inline uint16_t dap_chain_datum_token_flag_from_str(const char* a_str)
 {
     if (a_str == NULL)
         return DAP_CHAIN_DATUM_TOKEN_FLAG_NONE;
-    
+
     return s_flag_code_from_str(a_str);
 }
 
@@ -382,7 +387,7 @@ typedef struct dap_chain_datum_token_emission{
             uint64_t value;
             uint256_t value_256;
         };
-        uint8_t nonce[DAP_CHAIN_DATUM_NONCE_SIZE];       
+        uint8_t nonce[DAP_CHAIN_DATUM_NONCE_SIZE];
     } DAP_ALIGN_PACKED hdr;
     union {
         struct {
diff --git a/modules/common/include/dap_chain_datum_tx.h b/modules/common/include/dap_chain_datum_tx.h
index 0b903b6761d9b3525b832029e5afa0659d3fb922..d4f53f1efcf6324d533891b827a4e3a2a0d8f742 100644
--- a/modules/common/include/dap_chain_datum_tx.h
+++ b/modules/common/include/dap_chain_datum_tx.h
@@ -109,13 +109,6 @@ int dap_chain_datum_tx_add_out_item(dap_chain_datum_tx_t **a_tx, const dap_chain
  */
 int dap_chain_datum_tx_add_fee_item(dap_chain_datum_tx_t **a_tx, uint256_t a_value);
 
-/**
- * Create 'out_cond' item with fee stake value and insert to transaction
- *
- * return 1 Ok, -1 Error
- */
-int dap_chain_datum_tx_add_fee_stake_item(dap_chain_datum_tx_t **a_tx, uint256_t a_value);
-
 /**
  * Create 'out'_ext item and insert to transaction
  *
diff --git a/modules/common/include/dap_chain_datum_tx_items.h b/modules/common/include/dap_chain_datum_tx_items.h
index 6326b567f5a44f37f20658d3295ae95dc591eb10..afb2bae94cb72143c602341b56769d3c0876348d 100644
--- a/modules/common/include/dap_chain_datum_tx_items.h
+++ b/modules/common/include/dap_chain_datum_tx_items.h
@@ -49,6 +49,12 @@
  */
 dap_chain_tx_item_type_t dap_chain_datum_tx_item_get_type(const void *a_item);
 
+typedef struct dap_chain_datum_tx_item
+{
+    dap_chain_tx_item_type_t type;
+    byte_t data[];
+} DAP_ALIGN_PACKED dap_chain_datum_tx_item_t;
+
 /**
  * Get item name by item type
  *
@@ -156,7 +162,7 @@ dap_chain_tx_out_cond_t* dap_chain_datum_tx_item_out_cond_create_srv_pay(dap_pke
  */
 dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_srv_xchange(dap_chain_net_srv_uid_t a_srv_uid, dap_chain_net_id_t a_sell_net_id,
                                                                              uint256_t a_value_sell, dap_chain_net_id_t a_buy_net_id,
-                                                                             const char *a_token, uint256_t a_value_buy,
+                                                                             const char *a_token, uint256_t a_value_buy, const dap_chain_addr_t *a_seller_addr,
                                                                              const void *a_params, uint32_t a_params_size);
 /**
  * Create item dap_chain_tx_out_cond_t for stake service
@@ -191,8 +197,9 @@ dap_sign_t *dap_chain_datum_tx_item_sign_get_sig(dap_chain_tx_sig_t *a_tx_sig);
  */
 uint8_t* dap_chain_datum_tx_item_get( dap_chain_datum_tx_t *a_tx, int *a_item_idx_start,
         dap_chain_tx_item_type_t a_type, int *a_item_out_size);
-
+// Get Nth item of pointed type
+uint8_t *dap_chain_datum_tx_item_get_nth(dap_chain_datum_tx_t *a_tx, dap_chain_tx_item_type_t a_type, int a_item_idx);
 // Get all item from transaction by type
 dap_list_t* dap_chain_datum_tx_items_get(dap_chain_datum_tx_t *a_tx, dap_chain_tx_item_type_t a_type, int *a_item_count);
 // Get conditional out item with it's idx
-dap_chain_tx_out_cond_t *dap_chain_datum_tx_out_cond_get(dap_chain_datum_tx_t *a_tx, int *a_out_num);
+dap_chain_tx_out_cond_t *dap_chain_datum_tx_out_cond_get(dap_chain_datum_tx_t *a_tx, dap_chain_tx_item_type_t a_cond_type, int *a_out_num);
diff --git a/modules/common/include/dap_chain_datum_tx_out_cond.h b/modules/common/include/dap_chain_datum_tx_out_cond.h
index 8eb3989e115176ebf66e4d1b6adeb8915e226304..2e41d3497b6cb32aa59bb839a7c4bdda3fa101e6 100644
--- a/modules/common/include/dap_chain_datum_tx_out_cond.h
+++ b/modules/common/include/dap_chain_datum_tx_out_cond.h
@@ -30,27 +30,22 @@
 #include "dap_chain_common.h"
 #include "dap_chain_datum_tx.h"
 
-// Maximum fee stake, if the actual fee is less, the difference will be returned to the sender
-#define MAX_FEE_STAKE   GET_256_FROM_64(1000)
-
 enum dap_chain_tx_out_cond_subtype {
     DAP_CHAIN_TX_OUT_COND_SUBTYPE_UNDEFINED = 0x0,
     DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY = 0x01,
     DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE = 0x02,
     DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE = 0x3,
-    DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE_UPDATE = 0xFA,       // Virtual type for stake update verificator //TODO change it to new type of callback for ledger tx add
     DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE = 0x04,
-    DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STAKE = 0x05,
     DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK = 0x06,
+    DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL = 0xFF
 };
 typedef byte_t dap_chain_tx_out_cond_subtype_t;
 
 DAP_STATIC_INLINE const char *dap_chain_tx_out_cond_subtype_to_str(dap_chain_tx_out_cond_subtype_t a_subtype){
     switch (a_subtype) {
     case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY: return "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY";
-    case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE: return "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE";
+    case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE: return "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE";
     case DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE: return "DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE";
-    case DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STAKE: return "DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STAKE";
     case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE: return "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE";
     case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK: return "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK";
     default: {}
@@ -70,6 +65,7 @@ typedef struct dap_chain_tx_out_cond {
         dap_chain_tx_out_cond_subtype_t subtype;
         /// Number of Datoshis ( DAP/10^18 ) to be reserved for service
         uint256_t value;
+        byte_t paddding_ext[6];
         /// When time expires this output could be used only by transaction owner
         dap_time_t ts_expires;
         /// Service uid that only could be used for this out
@@ -77,7 +73,7 @@ typedef struct dap_chain_tx_out_cond {
 #if DAP_CHAIN_NET_SRV_UID_SIZE == 8
         byte_t padding[8];
 #endif
-    } header;
+    } DAP_ALIGN_PACKED header;
     union {
         /// Structure with specific for service pay condition subtype
         struct {
@@ -87,7 +83,7 @@ typedef struct dap_chain_tx_out_cond {
             dap_chain_net_srv_price_unit_uid_t unit;
             /// Maximum price per unit
             uint256_t unit_price_max_datoshi;
-        } srv_pay;
+        } DAP_ALIGN_PACKED srv_pay;
         struct {
             // Chain network to change from
             dap_chain_net_id_t sell_net_id;
@@ -97,7 +93,9 @@ typedef struct dap_chain_tx_out_cond {
             uint256_t buy_value;
             // Token ticker to change to
             char buy_token[DAP_CHAIN_TICKER_SIZE_MAX];
-        } srv_xchange;
+            // Seller address
+            dap_chain_addr_t seller_addr;
+        } DAP_ALIGN_PACKED srv_xchange;
         struct {
             // Stake holder address
             dap_chain_addr_t hldr_addr;
@@ -109,14 +107,21 @@ typedef struct dap_chain_tx_out_cond {
             dap_chain_addr_t signing_addr;
             // Node address of signer with this stake
             dap_chain_node_addr_t signer_node_addr;
-        } srv_stake;
+        } DAP_ALIGN_PACKED srv_stake;
+        struct {
+            dap_time_t		time_unlock;
+            dap_hash_fast_t	pkey_delegated;
+            uint256_t		reinvest_percent;
+            uint32_t		flags;
+            byte_t          padding[4];
+        } DAP_ALIGN_PACKED srv_stake_lock;
         struct {
             // Nothing here
-        } fee;
-        byte_t free_space[128]; // for future changes
-    } subtype;
-    uint32_t params_size; // Condition parameters size
-    uint8_t params[]; // condition parameters, pkey, hash or smth like this
+        } DAP_ALIGN_PACKED fee;
+        byte_t free_space[272]; // TODO increase it to 512 with version update
+    } DAP_ALIGN_PACKED subtype;
+    uint32_t tsd_size; // Condition parameters size
+    uint8_t tsd[]; // condition parameters, pkey, hash or smth like this
 } DAP_ALIGN_PACKED dap_chain_tx_out_cond_t;
 
 
diff --git a/modules/consensus/block-poa/dap_chain_cs_block_poa.c b/modules/consensus/block-poa/dap_chain_cs_block_poa.c
index 5b105ac6608d646825a5cb4128b8cd5e71e4a19d..28ecf8f8dfbbc5bc2e7bb3ff261afe8f0d052307 100644
--- a/modules/consensus/block-poa/dap_chain_cs_block_poa.c
+++ b/modules/consensus/block-poa/dap_chain_cs_block_poa.c
@@ -310,8 +310,9 @@ static int s_callback_block_verify(dap_chain_cs_blocks_t * a_blocks, dap_chain_b
     }
     // Parse the rest signs
     size_t l_offset = (byte_t *)l_sign - a_block->meta_n_datum_n_sign;
+    size_t l_signs_section_size = a_block_size - dap_chain_block_get_sign_offset(a_block, a_block_size);
     while (l_offset < a_block_size - sizeof(a_block->hdr)) {
-        if (!dap_sign_verify_size(l_sign, a_block_size)) {
+        if (!dap_sign_verify_size(l_sign, l_signs_section_size)) {
             log_it(L_ERROR, "Corrupted block: sign size is bigger than block size");
             return -3;
         }
diff --git a/modules/consensus/block-pos/dap_chain_cs_block_pos.c b/modules/consensus/block-pos/dap_chain_cs_block_pos.c
index b72b59ffe265654fb8cfa3f2604d1e89e8737a18..69f2a241ebff348536ec49b094da7b1b16072bbf 100644
--- a/modules/consensus/block-pos/dap_chain_cs_block_pos.c
+++ b/modules/consensus/block-pos/dap_chain_cs_block_pos.c
@@ -201,12 +201,12 @@ static size_t s_callback_block_sign(dap_chain_cs_blocks_t *a_blocks, dap_chain_b
 }
 
 /**
- * @brief 
+ * @brief
  * function makes block singing verification
  * @param a_block a_blocks dap_chain_cs_blocks_t
  * @param a_block dap_chain_block_t
  * @param a_block_size size_t size of block object
- * @return int 
+ * @return int
  */
 static int s_callback_block_verify(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_t *a_block, size_t a_block_size)
 {
@@ -230,6 +230,7 @@ static int s_callback_block_verify(dap_chain_cs_blocks_t *a_blocks, dap_chain_bl
     }
 
     uint16_t l_verified_num = 0;
+    size_t l_signs_section_size = a_block_size - dap_chain_block_get_sign_offset(a_block, a_block_size);
     for (size_t l_sig_pos = 0; l_sig_pos < l_signs_count; l_sig_pos++) {
         dap_sign_t *l_sign = dap_chain_block_sign_get(a_block, a_block_size, l_sig_pos);
         if (l_sign == NULL) {
@@ -237,7 +238,7 @@ static int s_callback_block_verify(dap_chain_cs_blocks_t *a_blocks, dap_chain_bl
             return -4;
         }
 
-        bool l_sign_size_correct = dap_sign_verify_size(l_sign, a_block_size);
+        bool l_sign_size_correct = dap_sign_verify_size(l_sign, l_signs_section_size);
         if (!l_sign_size_correct) {
             log_it(L_WARNING, "Block's sign #%zu size is incorrect", l_sig_pos);
             return -44;
diff --git a/modules/consensus/block-ton/dap_chain_cs_block_ton.c b/modules/consensus/block-ton/dap_chain_cs_block_ton.c
index 9d69a9a92d0908f784385b44980392843a06e278..e49adde197cb06184f206caf4b47a6907838f9d6 100644
--- a/modules/consensus/block-ton/dap_chain_cs_block_ton.c
+++ b/modules/consensus/block-ton/dap_chain_cs_block_ton.c
@@ -14,37 +14,32 @@
 #define LOG_TAG "dap_chain_cs_blocks_ton"
 
 static int s_callback_new(dap_chain_t *a_chain, dap_config_t *a_chain_cfg);
-static void s_session_packet_in(void * a_arg, dap_chain_node_addr_t * a_sender_node_addr, 
-								dap_chain_hash_fast_t *a_data_hash, uint8_t *a_data, size_t a_data_size);
+static void s_session_packet_in(void * a_arg, dap_chain_node_addr_t * a_sender_node_addr,
+                                dap_chain_hash_fast_t *a_data_hash, uint8_t *a_data, size_t a_data_size);
 static void s_session_candidate_to_chain(
             dap_chain_cs_block_ton_session_t *a_session, dap_chain_hash_fast_t *a_candidate_hash,
-							dap_chain_block_t *a_candidate, size_t a_candidate_size);
+                            dap_chain_block_t *a_candidate, size_t a_candidate_size);
 static void s_session_candidate_submit(dap_chain_cs_block_ton_session_t *a_session);
-static bool s_session_timer();
+static void s_session_timer(void *a_arg);
 static int s_session_atom_validation(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_t *a_block, size_t a_block_size);
 static uint8_t *s_message_data_sign(dap_chain_cs_block_ton_session_t *a_session,
-						dap_chain_cs_block_ton_message_t *a_message, size_t *a_sign_size);
+                        dap_chain_cs_block_ton_message_t *a_message, size_t *a_sign_size);
 static void s_message_send(dap_chain_cs_block_ton_session_t *a_session, uint8_t a_message_type,
-									uint8_t *a_data, size_t a_data_size, dap_list_t *a_validators);
+                                    uint8_t *a_data, size_t a_data_size, dap_list_t *a_validators);
 static void s_message_chain_add(dap_chain_cs_block_ton_session_t * a_session, dap_chain_node_addr_t * a_sender_node_addr,
-									dap_chain_cs_block_ton_message_t * a_message,
-									size_t a_message_size, dap_chain_hash_fast_t *a_message_hash);
-
+                                    dap_chain_cs_block_ton_message_t * a_message,
+                                    size_t a_message_size, dap_chain_hash_fast_t *a_message_hash);
 static void s_session_round_start(dap_chain_cs_block_ton_session_t *a_session);
 static bool s_session_send_startsync(dap_chain_cs_block_ton_session_t *a_session);
 static bool  s_session_round_start_callback_load_session_store(dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const size_t a_values_total,  const size_t a_values_shift,
                                                   const size_t a_values_count, dap_global_db_obj_t * a_values, void * a_arg);
-
-
-static void s_session_block_new_delete(dap_chain_cs_block_ton_session_t *a_session);
 static void s_session_my_candidate_delete(dap_chain_cs_block_ton_session_t *a_session);
-static void s_session_round_finish(dap_chain_cs_block_ton_session_t *a_session, bool a_is_time_proc_lock);
+static void s_session_round_finish(dap_chain_cs_block_ton_session_t *a_session, bool a_failed);
 static dap_chain_node_addr_t *s_session_get_validator(
                     dap_chain_cs_block_ton_session_t *a_session, dap_chain_node_addr_t *a_addr,
-						dap_list_t *a_validators);
-static uint16_t s_session_message_count(
-            dap_chain_cs_block_ton_session_t *a_session, uint8_t a_round_name, uint8_t a_type,
-						dap_chain_hash_fast_t *a_candidate_hash, uint16_t *a_attempt_number);
+                        dap_list_t *a_validators);
+static uint16_t s_session_message_count(dap_chain_cs_block_ton_session_t *a_session, uint8_t a_type,
+                        dap_chain_hash_fast_t *a_candidate_hash, uint16_t *a_attempt_number);
 static void s_callback_delete(dap_chain_cs_blocks_t *a_blocks);
 static int s_callback_created(dap_chain_t *a_chain, dap_config_t *a_chain_net_cfg);
 static size_t s_callback_block_sign(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_t **a_block_ptr, size_t a_block_size);
@@ -54,10 +49,8 @@ static int s_compare_validators_list_stake(const void * a_item1, const void * a_
 static int s_compare_validators_list_addr(const void * a_item1, const void * a_item2, void *a_unused);
 static dap_list_t *s_get_validators_addr_list(dap_chain_cs_block_ton_session_t *a_session); //(dap_chain_t *a_chain);
 
-static bool s_hash_is_null(dap_chain_hash_fast_t *a_hash);
-
 static dap_chain_cs_block_ton_session_t * s_session_items;
-static dap_timerfd_t * s_session_cs_timer = NULL; 
+static dap_interval_timer_t s_session_cs_timer = NULL;
 
 typedef struct dap_chain_cs_block_ton_pvt
 {
@@ -72,22 +65,22 @@ typedef struct dap_chain_cs_block_ton_pvt
     uint16_t poa_validators_count;
     bool flag_sign_verify;
 
-	bool debug;
-	bool validators_list_by_stake;
-	uint16_t round_start_sync_timeout;
-	uint16_t round_start_multiple_of;
-	uint32_t allowed_clock_offset;
-	uint32_t session_idle_min;
-	uint16_t round_candidates_max;
-	uint16_t next_candidate_delay;
-	uint16_t round_attempts_max;
-	uint16_t round_attempt_duration;
-	uint16_t first_message_delay;
-   	uint16_t my_candidate_attempts_max;
-
-	dap_list_t *ton_nodes_addrs; // dap_chain_node_addr_t
-
-   	uint16_t auth_certs_count;
+    bool debug;
+    bool validators_list_by_stake;
+    uint16_t round_start_sync_timeout;
+    uint16_t round_start_multiple_of;
+    uint32_t allowed_clock_offset;
+    uint32_t session_idle_min;
+    uint16_t round_candidates_max;
+    uint16_t next_candidate_delay;
+    uint16_t round_attempts_max;
+    uint16_t round_attempt_duration;
+    uint16_t first_message_delay;
+    uint16_t my_candidate_attempts_max;
+
+    dap_list_t *ton_nodes_addrs; // dap_chain_node_addr_t
+
+    uint16_t auth_certs_count;
     char *auth_certs_prefix;
     dap_cert_t ** auth_certs;
 } dap_chain_cs_block_ton_pvt_t;
@@ -95,8 +88,8 @@ typedef struct dap_chain_cs_block_ton_pvt
 #define PVT(a) ((dap_chain_cs_block_ton_pvt_t *)a->_pvt)
 
 int dap_chain_cs_block_ton_init() {
-	dap_stream_ch_chain_voting_init();
-	dap_chain_cs_add("block_ton", s_callback_new);
+    dap_stream_ch_chain_voting_init();
+    dap_chain_cs_add("block_ton", s_callback_new);
     return 0;
 }
 
@@ -133,70 +126,70 @@ static int s_callback_new(dap_chain_t *a_chain, dap_config_t *a_chain_cfg) {
     l_ton_pvt->tokens_hold_size = l_tokens_hold_size;
     l_ton_pvt->tokens_hold = DAP_NEW_Z_SIZE(char *, sizeof(char *) * l_tokens_hold_size);
     l_ton_pvt->tokens_hold_value = DAP_NEW_Z_SIZE(uint64_t, l_tokens_hold_value_size * sizeof(uint64_t));
-	l_ton_pvt->debug = dap_config_get_item_bool_default(a_chain_cfg,"block-ton","consensus_debug", true);
-
-	l_ton_pvt->validators_list_by_stake = dap_config_get_item_bool_default(a_chain_cfg,"block-ton","validators_list_by_stake", false);
-	l_ton_pvt->round_start_sync_timeout = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "round_start_sync_timeout", 10);
-	l_ton_pvt->round_start_multiple_of = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "round_start_multiple_of", 30);
-	l_ton_pvt->allowed_clock_offset = dap_config_get_item_uint32_default(a_chain_cfg,"block-ton", "allowed_clock_offset", 5);
-	l_ton_pvt->session_idle_min = dap_config_get_item_uint32_default(a_chain_cfg,"block-ton", "session_idle_min", 15);
-	l_ton_pvt->round_candidates_max = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "round_candidates_max", 3);
-	l_ton_pvt->next_candidate_delay = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "next_candidate_delay", 2);
-	l_ton_pvt->round_attempts_max = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "round_attempts_max", 4);
-	l_ton_pvt->round_attempt_duration = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "round_attempt_duration", 10);
-	l_ton_pvt->first_message_delay = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "first_message_delay", 3);
-	l_ton_pvt->my_candidate_attempts_max = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "my_candidate_attempts_max", 2);
-    
+    l_ton_pvt->debug = dap_config_get_item_bool_default(a_chain_cfg,"block-ton","consensus_debug", true);
+
+    l_ton_pvt->validators_list_by_stake = dap_config_get_item_bool_default(a_chain_cfg,"block-ton","validators_list_by_stake", false);
+    l_ton_pvt->round_start_sync_timeout = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "round_start_sync_timeout", 10);
+    l_ton_pvt->round_start_multiple_of = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "round_start_multiple_of", 30);
+    l_ton_pvt->allowed_clock_offset = dap_config_get_item_uint32_default(a_chain_cfg,"block-ton", "allowed_clock_offset", 5);
+    l_ton_pvt->session_idle_min = dap_config_get_item_uint32_default(a_chain_cfg,"block-ton", "session_idle_min", 15);
+    l_ton_pvt->round_candidates_max = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "round_candidates_max", 3);
+    l_ton_pvt->next_candidate_delay = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "next_candidate_delay", 2);
+    l_ton_pvt->round_attempts_max = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "round_attempts_max", 4);
+    l_ton_pvt->round_attempt_duration = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "round_attempt_duration", 10);
+    l_ton_pvt->first_message_delay = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "first_message_delay", 3);
+    l_ton_pvt->my_candidate_attempts_max = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "my_candidate_attempts_max", 2);
+
     l_ton_pvt->ton_nodes_addrs = NULL;
     l_ton_pvt->auth_certs_prefix = strdup( dap_config_get_item_str_default(a_chain_cfg,"block-ton","auth_certs_prefix", "ton") );
-   	l_ton_pvt->auth_certs_count = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton","auth_certs_number", 0);
+    l_ton_pvt->auth_certs_count = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton","auth_certs_number", 0);
     if ( !l_ton_pvt->validators_list_by_stake ) { // auth by cert for PoA mode
-	    if (l_ton_pvt->auth_certs_count) {
+        if (l_ton_pvt->auth_certs_count) {
             l_ton_pvt->auth_certs = DAP_NEW_Z_SIZE(dap_cert_t *, l_ton_pvt->auth_certs_count * sizeof(dap_cert_t*));
-	        char l_cert_name[512];
-	        for (size_t i = 0; i < l_ton_pvt->auth_certs_count; i++ ){
-	            dap_snprintf(l_cert_name, sizeof(l_cert_name), "%s.%zu", l_ton_pvt->auth_certs_prefix, i);
-	            if ((l_ton_pvt->auth_certs[i] = dap_cert_find_by_name( l_cert_name)) == NULL) {
-	                dap_snprintf(l_cert_name, sizeof(l_cert_name), "%s.%zu.pub", l_ton_pvt->auth_certs_prefix, i);
-	                if ((l_ton_pvt->auth_certs[i] = dap_cert_find_by_name(l_cert_name)) == NULL) {
-	                    log_it(L_ERROR, "TON: Can't find cert \"%s\"", l_cert_name);
-	                    return -1;
-	                }
-	            }
-	            log_it(L_NOTICE, "TON: Initialized auth cert \"%s\"", l_cert_name);
-	        }
-	    }
-	
-	    uint16_t l_node_addrs_count;
-	    char **l_addrs = dap_config_get_array_str(a_chain_cfg, "block-ton", "ton_nodes_addrs", &l_node_addrs_count);
-	    l_ton_pvt->poa_validators_count = l_node_addrs_count;
-	    for(size_t i = 0; i < l_node_addrs_count; i++) {
-	        dap_chain_node_addr_t *l_node_addr = DAP_NEW_Z(dap_chain_node_addr_t);
+            char l_cert_name[512];
+            for (size_t i = 0; i < l_ton_pvt->auth_certs_count; i++ ){
+                dap_snprintf(l_cert_name, sizeof(l_cert_name), "%s.%zu", l_ton_pvt->auth_certs_prefix, i);
+                if ((l_ton_pvt->auth_certs[i] = dap_cert_find_by_name( l_cert_name)) == NULL) {
+                    dap_snprintf(l_cert_name, sizeof(l_cert_name), "%s.%zu.pub", l_ton_pvt->auth_certs_prefix, i);
+                    if ((l_ton_pvt->auth_certs[i] = dap_cert_find_by_name(l_cert_name)) == NULL) {
+                        log_it(L_ERROR, "TON: Can't find cert \"%s\"", l_cert_name);
+                        return -1;
+                    }
+                }
+                log_it(L_NOTICE, "TON: Initialized auth cert \"%s\"", l_cert_name);
+            }
+        }
+
+        uint16_t l_node_addrs_count;
+        char **l_addrs = dap_config_get_array_str(a_chain_cfg, "block-ton", "ton_nodes_addrs", &l_node_addrs_count);
+        l_ton_pvt->poa_validators_count = l_node_addrs_count;
+        for(size_t i = 0; i < l_node_addrs_count; i++) {
+            dap_chain_node_addr_t *l_node_addr = DAP_NEW_Z(dap_chain_node_addr_t);
             if (dap_sscanf(l_addrs[i],NODE_ADDR_FP_STR, NODE_ADDR_FPS_ARGS(l_node_addr) ) != 4 ){
-	            log_it(L_ERROR,"TON: Wrong address format,  should be like 0123::4567::890AB::CDEF");
-	            DAP_DELETE(l_node_addr);
-	            //DAP_DELETE(l_node_info);
-	            l_node_addr = NULL;
-	            continue;
-	        }
-	        if (l_node_addr) {
-	            log_it(L_MSG, "TON: add validator addr:"NODE_ADDR_FP_STR"", NODE_ADDR_FP_ARGS(l_node_addr));
-	        	l_ton_pvt->ton_nodes_addrs = dap_list_append(l_ton_pvt->ton_nodes_addrs, l_node_addr);
-	        }
-	    }
-
-	}
-	else { // stake
-	    for (size_t i = 0; i < l_tokens_hold_value_size; i++) {
-	        l_ton_pvt->tokens_hold[i] = dap_strdup(l_tokens_hold[i]);
-	        if ((l_ton_pvt->tokens_hold_value[i] =
-	               strtoull(l_tokens_hold_value_str[i],NULL,10)) == 0) {
-	             log_it(L_CRITICAL, "Token %s has inproper hold value %s",
-	                                l_ton_pvt->tokens_hold[i], l_tokens_hold_value_str[i]);
-	             goto lb_err;
-	        }
-	    }
-	}
+                log_it(L_ERROR,"TON: Wrong address format,  should be like 0123::4567::890AB::CDEF");
+                DAP_DELETE(l_node_addr);
+                //DAP_DELETE(l_node_info);
+                l_node_addr = NULL;
+                continue;
+            }
+            if (l_node_addr) {
+                log_it(L_MSG, "TON: add validator addr:"NODE_ADDR_FP_STR"", NODE_ADDR_FP_ARGS(l_node_addr));
+                l_ton_pvt->ton_nodes_addrs = dap_list_append(l_ton_pvt->ton_nodes_addrs, l_node_addr);
+            }
+        }
+
+    }
+    else { // stake
+        for (size_t i = 0; i < l_tokens_hold_value_size; i++) {
+            l_ton_pvt->tokens_hold[i] = dap_strdup(l_tokens_hold[i]);
+            if ((l_ton_pvt->tokens_hold_value[i] =
+                   strtoull(l_tokens_hold_value_str[i],NULL,10)) == 0) {
+                 log_it(L_CRITICAL, "Token %s has inproper hold value %s",
+                                    l_ton_pvt->tokens_hold[i], l_tokens_hold_value_str[i]);
+                 goto lb_err;
+            }
+        }
+    }
 
 
     // Save old callback if present and set the call of its own (chain callbacks)
@@ -219,6 +212,7 @@ lb_err:
 }
 
 static void s_callback_delete(dap_chain_cs_blocks_t *a_blocks) {
+    dap_interval_timer_delete(s_session_cs_timer);
     dap_chain_cs_block_ton_t *l_ton = DAP_CHAIN_CS_BLOCK_TON(a_blocks);
     if (l_ton->_pvt)
         DAP_DELETE(l_ton->_pvt);
@@ -250,37 +244,37 @@ static dap_list_t *s_get_validators_addr_list(dap_chain_cs_block_ton_session_t *
     dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_session->chain);
     dap_chain_cs_block_ton_t *l_ton = DAP_CHAIN_CS_BLOCK_TON(l_blocks);
     dap_chain_cs_block_ton_pvt_t *l_ton_pvt = PVT(l_ton);
-	dap_list_t *l_ret = NULL;
-
-	if ( l_ton_pvt->validators_list_by_stake) {
-		dap_list_t *l_validators = dap_chain_net_srv_stake_get_validators();
-		l_validators = dap_list_sort(l_validators, s_compare_validators_list_stake);
-		dap_list_t *l_list = dap_list_first(l_validators);
-		while (l_list){
-	        dap_list_t *l_next = l_list->next;
-	        dap_chain_node_addr_t *l_addr =
-	        		(dap_chain_node_addr_t *)DAP_DUP_SIZE(
-	        			&((dap_chain_net_srv_stake_item_t * )l_list->data)->node_addr,
-	        				sizeof(dap_chain_node_addr_t));
-	        DAP_DELETE(l_list->data);
-	        l_ret = dap_list_append(l_ret, l_addr);
-	        l_list = l_next;
-	    }
-	    dap_list_free(l_list);
-	}
-	else {
-		// dap_chain_net_t *l_net = dap_chain_net_by_id(a_session->chain->net_id);
-		dap_list_t *l_list = dap_list_first(PVT(a_session->ton)->ton_nodes_addrs);
-		while (l_list) {
-			dap_chain_node_addr_t *l_addr =
-					(dap_chain_node_addr_t *)DAP_DUP_SIZE(
-							l_list->data, sizeof(dap_chain_node_addr_t));
-			l_ret = dap_list_append(l_ret, l_addr);
-			l_list = l_list->next;
-		}
-		l_ret = dap_list_sort(l_ret, s_compare_validators_list_addr);
-	}
-   	return l_ret;
+    dap_list_t *l_ret = NULL;
+
+    if ( l_ton_pvt->validators_list_by_stake) {
+        dap_list_t *l_validators = dap_chain_net_srv_stake_get_validators();
+        l_validators = dap_list_sort(l_validators, s_compare_validators_list_stake);
+        dap_list_t *l_list = dap_list_first(l_validators);
+        while (l_list){
+            dap_list_t *l_next = l_list->next;
+            dap_chain_node_addr_t *l_addr =
+                    (dap_chain_node_addr_t *)DAP_DUP_SIZE(
+                        &((dap_chain_net_srv_stake_item_t * )l_list->data)->node_addr,
+                            sizeof(dap_chain_node_addr_t));
+            DAP_DELETE(l_list->data);
+            l_ret = dap_list_append(l_ret, l_addr);
+            l_list = l_next;
+        }
+        dap_list_free(l_list);
+    }
+    else {
+        // dap_chain_net_t *l_net = dap_chain_net_by_id(a_session->chain->net_id);
+        dap_list_t *l_list = dap_list_first(PVT(a_session->ton)->ton_nodes_addrs);
+        while (l_list) {
+            dap_chain_node_addr_t *l_addr =
+                    (dap_chain_node_addr_t *)DAP_DUP_SIZE(
+                            l_list->data, sizeof(dap_chain_node_addr_t));
+            l_ret = dap_list_append(l_ret, l_addr);
+            l_list = l_list->next;
+        }
+        l_ret = dap_list_sort(l_ret, s_compare_validators_list_addr);
+    }
+    return l_ret;
 }
 
 static int s_callback_created(dap_chain_t *a_chain, dap_config_t *a_chain_net_cfg) {
@@ -304,144 +298,67 @@ static int s_callback_created(dap_chain_t *a_chain, dap_config_t *a_chain_net_cf
         log_it(L_ERROR, "No sign certificate provided, can't sign any blocks");
     }
 
-	dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
+    dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
     dap_chain_cs_block_ton_session_t *l_session = DAP_NEW_Z(dap_chain_cs_block_ton_session_t);
-	l_session->chain = a_chain;
-	l_session->ton = l_ton;
+    l_session->chain = a_chain;
+    l_session->ton = l_ton;
 
     l_session->my_candidate = NULL;
     l_session->my_candidate_size = 0;
     l_session->my_candidate_attempts_count = 0;
 
-	l_session->old_round.validators_list = 
-				l_session->cur_round.validators_list = 
-								s_get_validators_addr_list(l_session);
-	l_session->cur_round.validators_count = dap_list_length(l_session->cur_round.validators_list);
+    l_session->cur_round.validators_list = s_get_validators_addr_list(l_session);
+    l_session->cur_round.validators_count = dap_list_length(l_session->cur_round.validators_list);
 
     l_session->my_addr = DAP_NEW(dap_chain_node_addr_t);
-	l_session->my_addr->uint64 = dap_chain_net_get_cur_addr_int(l_net);
-
-	l_session->cur_round.id.uint64 = 1000;
-	l_session->old_round.id.uint64 = 0;
-	l_session->gdb_group_store = dap_strdup_printf("local.ton.%s.%s.store", 
-										a_chain->net_name, a_chain->name);
-	l_session->gdb_group_message = dap_strdup_printf("local.ton.%s.%s.message",
-										a_chain->net_name, a_chain->name);
-	l_session->state = DAP_STREAM_CH_CHAIN_SESSION_STATE_IDLE;
-	l_session->time_proc_lock = false;
-	
-	dap_time_t l_time = dap_time_now();
-	while (true) {
-		l_time++;
-		if ( (l_time % PVT(l_session->ton)->round_start_multiple_of) == 0) {
-			l_session->ts_round_sync_start = l_time;
-			break;
-		}
-	}
-	pthread_rwlock_init(&l_session->rwlock, NULL);
-
-	log_it(L_INFO, "TON: init session for net:%s, chain:%s", a_chain->net_name, a_chain->name);
-	DL_APPEND(s_session_items, l_session);
+    l_session->my_addr->uint64 = dap_chain_net_get_cur_addr_int(l_net);
+
+    l_session->cur_round.id.uint64 = 1000;
+    l_session->gdb_group_store = dap_strdup_printf("local.ton.%s.%s.store",
+                                        a_chain->net_name, a_chain->name);
+    l_session->gdb_group_message = dap_strdup_printf("local.ton.%s.%s.message",
+                                        a_chain->net_name, a_chain->name);
+    l_session->state = DAP_STREAM_CH_CHAIN_SESSION_STATE_IDLE;
+
+    dap_time_t l_time = dap_time_now();
+    while (true) {
+        l_time++;
+        if ( (l_time % l_ton_pvt->round_start_multiple_of) == 0) {
+            l_session->ts_round_sync_start = l_time;
+            break;
+        }
+    }
+    pthread_rwlock_init(&l_session->rwlock, NULL);
+
+    log_it(L_INFO, "TON: init session for net:%s, chain:%s", a_chain->net_name, a_chain->name);
+    DL_APPEND(s_session_items, l_session);
     dap_chain_node_role_t l_role = dap_chain_net_get_role(l_net);
-    if ( PVT(l_session->ton)->validators_list_by_stake ||
+    if (l_ton_pvt->validators_list_by_stake ||
                     (l_role.enums == NODE_ROLE_MASTER || l_role.enums == NODE_ROLE_ROOT) ) {
-		if ( s_session_get_validator(l_session, l_session->my_addr, l_session->cur_round.validators_list) ) {
-			if (!s_session_cs_timer) {
-				s_session_cs_timer = dap_timerfd_start(1*1000, 
-		                        (dap_timerfd_callback_t)s_session_timer, 
-		                        NULL);
-				if (PVT(l_session->ton)->debug)
-					log_it(L_MSG, "TON: Consensus main timer is started");
-			}
-			dap_stream_ch_chain_voting_in_callback_add(l_session, s_session_packet_in);
-		}
-	}
-	return 0;
-}
-
-/**
- * @brief s_session_round_start_callback_load_session_store
- * @param a_global_db_context
- * @param a_rc
- * @param a_group
- * @param a_key
- * @param a_values_total
- * @param a_values_shift
- * @param a_values_count
- * @param a_values
- * @param a_arg
- */
-static bool  s_session_round_start_callback_load_session_store(dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const size_t a_values_total,  const size_t a_values_shift,
-                                                  const size_t a_values_count, dap_global_db_obj_t * a_values, void * a_arg)
-{
-    dap_chain_cs_block_ton_session_t *l_session = (dap_chain_cs_block_ton_session_t*) a_arg;
-    if (a_values_count) {
-        dap_chain_cs_block_ton_store_t *l_store_candidate_ready = NULL;
-        for (size_t i = 0; i < a_values_count; i++) {
-            if (!a_values[i].value_len)
-                continue;
-            dap_chain_cs_block_ton_store_t *l_store =
-                                        (dap_chain_cs_block_ton_store_t *)a_values[i].value;
-            if ( l_store->hdr.round_id.uint64 != l_session->cur_round.id.uint64 ) {
-                // dap_chain_global_db_gr_del(dap_strdup(l_objs[i].key), a_session->gdb_group_store);
-                if ( l_store->hdr.sign_collected ) {
-                    l_store_candidate_ready = l_store;
-                }
+        if ( s_session_get_validator(l_session, l_session->my_addr, l_session->cur_round.validators_list) ) {
+            if (!s_session_cs_timer) {
+                s_session_cs_timer = dap_interval_timer_create(1000, s_session_timer, NULL);
+                if (l_ton_pvt->debug)
+                    log_it(L_MSG, "TON: Consensus main timer is started");
             }
-        }
-        if (l_store_candidate_ready) {
-            s_session_candidate_to_chain(l_session, &l_store_candidate_ready->hdr.candidate_hash,
-                            (dap_chain_block_t*)l_store_candidate_ready->candidate_n_signs, l_store_candidate_ready->hdr.candidate_size);
+            dap_stream_ch_chain_voting_in_callback_add(l_session, s_session_packet_in);
         }
     }
-
-    dap_list_free_full(l_session->cur_round.validators_list, NULL);
-    l_session->cur_round.validators_list = s_get_validators_addr_list(l_session);
-    l_session->cur_round.validators_count = dap_list_length(l_session->cur_round.validators_list);
-
-    dap_timerfd_start(PVT(l_session->ton)->first_message_delay*1000,
-        (dap_timerfd_callback_t)s_session_send_startsync,
-            l_session);
-
-    if (PVT(l_session->ton)->debug)
-        log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Start syncing validators ",
-                l_session->chain->net_name, l_session->chain->name,
-                    l_session->cur_round.id.uint64, l_session->attempt_current_number);
-
-    l_session->time_proc_lock = false; // unlock
-    pthread_rwlock_unlock(&l_session->rwlock);
-    return true;
+    return 0;
 }
 
-
 /**
  * @brief s_session_round_start
  * @param a_session
  */
 static void s_session_round_start(dap_chain_cs_block_ton_session_t *a_session)
 {
-
-	a_session->cur_round.validators_start = NULL;
-	a_session->cur_round.validators_start_count = 0;
-
-	a_session->cur_round.validators_list = NULL;
-	a_session->cur_round.validators_count = 0;
-
-	a_session->cur_round.candidates_count = 0;
-
-	a_session->ts_round_start = 0;
-	a_session->ts_round_state_commit = 0;
-	a_session->attempt_current_number = 1;
-
-	a_session->cur_round.my_candidate_hash = NULL;
-	a_session->cur_round.last_message_hash = NULL;
-	a_session->cur_round.messages_count = 0;
-	a_session->cur_round.submit = false;
-
-	a_session->ts_round_sync_start = dap_time_now();
-	a_session->cur_round.id.uint64++;
-
-    dap_global_db_get_all(a_session->gdb_group_store, 0, s_session_round_start_callback_load_session_store, a_session);
+    memset(&a_session->cur_round, 0, sizeof(a_session->cur_round));
+    a_session->ts_round_start = 0;
+    a_session->ts_round_state_commit = 0;
+    a_session->attempt_current_number = 1;
+    a_session->ts_round_sync_start = dap_time_now();
+    a_session->cur_round.id.uint64++;
 }
 
 /**
@@ -451,36 +368,36 @@ static void s_session_round_start(dap_chain_cs_block_ton_session_t *a_session)
  */
 static bool s_session_send_startsync(dap_chain_cs_block_ton_session_t *a_session)
 {
-	dap_chain_cs_block_ton_message_startsync_t *l_startsync =
-											DAP_NEW_Z(dap_chain_cs_block_ton_message_startsync_t);
-	l_startsync->ts = a_session->ts_round_sync_start;
-	l_startsync->round_id.uint64 = a_session->cur_round.id.uint64;
-	s_message_send(a_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_START_SYNC, 
-							(uint8_t*)l_startsync, sizeof(dap_chain_cs_block_ton_message_startsync_t),
-								a_session->cur_round.validators_list);
-	if (PVT(a_session->ton)->debug)
+    dap_chain_cs_block_ton_message_startsync_t *l_startsync =
+                                            DAP_NEW_Z(dap_chain_cs_block_ton_message_startsync_t);
+    l_startsync->ts = a_session->ts_round_sync_start;
+    l_startsync->round_id.uint64 = a_session->cur_round.id.uint64;
+    s_message_send(a_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_START_SYNC,
+                            (uint8_t*)l_startsync, sizeof(dap_chain_cs_block_ton_message_startsync_t),
+                                a_session->cur_round.validators_list);
+    if (PVT(a_session->ton)->debug)
         log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U" Sent START_SYNC pkt",
-					a_session->chain->net_name, a_session->chain->name, a_session->cur_round.id.uint64);
+                    a_session->chain->net_name, a_session->chain->name, a_session->cur_round.id.uint64);
 
-	DAP_DELETE(l_startsync);
-	return false;
+    DAP_DELETE(l_startsync);
+    return false;
 }
 
 typedef struct s_session_send_votefor_data {
-	dap_chain_cs_block_ton_message_votefor_t *votefor;
+    dap_chain_cs_block_ton_message_votefor_t *votefor;
     dap_chain_cs_block_ton_session_t *session;
 } DAP_ALIGN_PACKED s_session_send_votefor_data_t;
 
 static bool s_session_send_votefor(s_session_send_votefor_data_t *a_data){
-	dap_chain_cs_block_ton_message_votefor_t *l_votefor = a_data->votefor;
+    dap_chain_cs_block_ton_message_votefor_t *l_votefor = a_data->votefor;
     dap_chain_cs_block_ton_session_t *l_session = a_data->session;
-	l_votefor->round_id.uint64 = l_session->cur_round.id.uint64;
-	s_message_send(l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE_FOR,
-	 					(uint8_t*)l_votefor, sizeof(dap_chain_cs_block_ton_message_votefor_t),
-	 						l_session->cur_round.validators_start);
-	DAP_DELETE(l_votefor);
-	DAP_DELETE(a_data);
-	return false;
+    l_votefor->round_id.uint64 = l_session->cur_round.id.uint64;
+    s_message_send(l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE_FOR,
+                        (uint8_t*)l_votefor, sizeof(dap_chain_cs_block_ton_message_votefor_t),
+                            l_session->cur_round.validators_start);
+    DAP_DELETE(l_votefor);
+    DAP_DELETE(a_data);
+    return false;
 }
 
 /**
@@ -545,8 +462,6 @@ static bool s_session_round_start_callback_load_session_store_coordinator_state_
                     l_session->attempt_current_number, l_hash_str);
         DAP_DELETE(l_hash_str);
     }
-
-    l_session->time_proc_lock = false; // unlock
     pthread_rwlock_unlock(&l_session->rwlock);
     return true;
 }
@@ -581,6 +496,15 @@ static void s_session_proc_state( dap_chain_cs_block_ton_session_t * a_session)
                 // round start
                 a_session->state = DAP_STREAM_CH_CHAIN_SESSION_STATE_WAIT_START;
                 s_session_round_start(a_session);
+                dap_list_free_full(a_session->cur_round.validators_list, free);
+                a_session->cur_round.validators_list = s_get_validators_addr_list(a_session);
+                a_session->cur_round.validators_count = dap_list_length(a_session->cur_round.validators_list);
+                dap_timerfd_start(PVT(a_session->ton)->first_message_delay*1000,
+                    (dap_timerfd_callback_t)s_session_send_startsync, a_session);
+                if (PVT(a_session->ton)->debug)
+                    log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Start syncing validators ",
+                            a_session->chain->net_name, a_session->chain->name,
+                                a_session->cur_round.id.uint64, a_session->attempt_current_number);
                 goto session_processed; // Unlock happens after round start in its callbacks
             }
             goto session_unlock;
@@ -588,7 +512,7 @@ static void s_session_proc_state( dap_chain_cs_block_ton_session_t * a_session)
         case DAP_STREAM_CH_CHAIN_SESSION_STATE_WAIT_START: {
             if ( (l_time-a_session->ts_round_sync_start) >= PVT(a_session->ton)->round_start_sync_timeout ) { // timeout start sync
                 uint16_t l_startsync_count = a_session->cur_round.validators_start_count;
-                if ( ((float)l_startsync_count/a_session->cur_round.validators_count) >= ((float)2/3) ) {
+                if (l_startsync_count * 3 >= a_session->cur_round.validators_count * 2) {
                     // if sync more 2/3 validators then start round and submit candidate
                     if (PVT(a_session->ton)->debug)
                         log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu More than 2/3 of the validators are synchronized, so starting the round and send the candidate",
@@ -721,13 +645,13 @@ session_processed: // Stay locked
  * @brief s_session_timer
  * @return
  */
-static bool s_session_timer()
+static void s_session_timer(void *a_arg)
 {
+    UNUSED(a_arg);
     dap_chain_cs_block_ton_session_t *l_session = NULL;
-	DL_FOREACH(s_session_items, l_session) {
+    DL_FOREACH(s_session_items, l_session) {
         s_session_proc_state(l_session);
-	}
-	return true;
+    }
 }
 
 /**
@@ -742,235 +666,179 @@ static void s_session_candidate_to_chain(
                             dap_chain_block_t *a_candidate, size_t a_candidate_size)
 {
 
-	dap_list_t *l_commitsign_list = NULL;
+    dap_list_t *l_commitsign_list = NULL;
+    dap_chain_hash_fast_t *l_candidate_hash = NULL;
     dap_chain_cs_block_ton_message_item_t *l_message_item=NULL, *l_message_tmp=NULL;
-    HASH_ITER(hh, a_session->old_round.messages_items, l_message_item, l_message_tmp) {
-    	uint8_t l_message_type = l_message_item->message->hdr.type;
-    	if ( l_message_type == DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN ) {
-    		dap_chain_hash_fast_t *l_candidate_hash = 
-    				&((dap_chain_cs_block_ton_message_commitsign_t *)
-    						(l_message_item->message->sign_n_message+l_message_item->message->hdr.sign_size))->candidate_hash;
-    		if ( memcmp(l_candidate_hash, a_candidate_hash, sizeof(dap_chain_hash_fast_t)) == 0) {
-    			l_commitsign_list = dap_list_append(l_commitsign_list, (void*)l_message_item->message);
-    		}
-    	}
+    HASH_ITER(hh, a_session->cur_round.messages_items, l_message_item, l_message_tmp) {
+        uint8_t l_message_type = l_message_item->message->hdr.type;
+        if ( l_message_type == DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN ) {
+            l_candidate_hash = &((dap_chain_cs_block_ton_message_commitsign_t *)
+                            (l_message_item->message->sign_n_message+l_message_item->message->hdr.sign_size))->candidate_hash;
+            if ( memcmp(l_candidate_hash, a_candidate_hash, sizeof(dap_chain_hash_fast_t)) == 0) {
+                l_commitsign_list = dap_list_append(l_commitsign_list, (void*)l_message_item->message);
+            }
+        }
     }
     if (!l_commitsign_list) {
-    	return;
+        return;
     }
-    dap_chain_block_t *l_candidate = 
-    	(dap_chain_block_t *)DAP_DUP_SIZE(a_candidate, a_candidate_size);
-
-	size_t l_signs_count = 0;
-	dap_list_t *l_validators_list = dap_list_first(a_session->old_round.validators_start);
-	while(l_validators_list) {
-		dap_chain_node_addr_t *l_validator = (dap_chain_node_addr_t *)l_validators_list->data;
-		l_validators_list = l_validators_list->next;
-		dap_list_t *l_submit_temp = dap_list_first(l_commitsign_list);
-		while(l_submit_temp) {
-			dap_chain_cs_block_ton_message_t *l_message = (dap_chain_cs_block_ton_message_t *)l_submit_temp->data;
-			dap_chain_cs_block_ton_message_commitsign_t *l_commitsign = 
-						(dap_chain_cs_block_ton_message_commitsign_t *)
-									(l_message->sign_n_message+l_message->hdr.sign_size);
-			if( l_message->hdr.is_verified 
-					&& l_message->hdr.sender_node_addr.uint64 == l_validator->uint64) {
-				dap_sign_t *l_candidate_sign = (dap_sign_t *)l_commitsign->candidate_sign;
-				size_t l_candidate_sign_size = dap_sign_get_size(l_candidate_sign);
-				if (!l_candidate_sign_size) {
-        			continue;
-				}
-        		l_candidate = DAP_REALLOC(l_candidate, a_candidate_size+l_candidate_sign_size);
-				memcpy(((byte_t *)l_candidate)+a_candidate_size, l_candidate_sign, l_candidate_sign_size);
-				a_candidate_size += l_candidate_sign_size;
-				l_signs_count++;
-			}
-			l_submit_temp = l_submit_temp->next;
-		}
-	}
-
-	if ( ((float)l_signs_count/a_session->old_round.validators_count) >= ((float)2/3) ) {
-		//dap_chain_t *l_chain = a_session->chain;
-		//dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(l_chain);
-		dap_chain_atom_verify_res_t l_res = a_session->chain->callback_atom_add(a_session->chain, l_candidate, a_candidate_size);
-		char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(a_candidate_hash);
-		switch (l_res) {
-			case ATOM_ACCEPT: {
-				// block save to chain
-		        if (dap_chain_atom_save(a_session->chain, (uint8_t *)l_candidate, a_candidate_size, a_session->chain->cells->id) < 0) {
-		            log_it(L_ERROR, "TON: Can't save atom %s to the file", l_candidate_hash_str);
-		        }
-		        else {
-					log_it(L_INFO, "TON: atom %s added in chain successfully", l_candidate_hash_str);
-		        }
-		    } break;
-		    case ATOM_MOVE_TO_THRESHOLD: {
-		        log_it(L_INFO, "TON: Thresholded atom with hash %s", l_candidate_hash_str);
-		    } break;
-		    case ATOM_PASS: {
-		    	log_it(L_WARNING, "TON: Atom with hash %s not accepted (code ATOM_PASS, already present)", l_candidate_hash_str);
+    dap_chain_block_t *l_candidate =
+        (dap_chain_block_t *)DAP_DUP_SIZE(a_candidate, a_candidate_size);
+
+    size_t l_signs_count = 0;
+    dap_list_t *l_validators_list = dap_list_first(a_session->cur_round.validators_start);
+    while(l_validators_list) {
+        dap_chain_node_addr_t *l_validator = (dap_chain_node_addr_t *)l_validators_list->data;
+        l_validators_list = l_validators_list->next;
+        dap_list_t *l_submit_temp = dap_list_first(l_commitsign_list);
+        while(l_submit_temp) {
+            dap_chain_cs_block_ton_message_t *l_message = (dap_chain_cs_block_ton_message_t *)l_submit_temp->data;
+            dap_chain_cs_block_ton_message_commitsign_t *l_commitsign =
+                        (dap_chain_cs_block_ton_message_commitsign_t *)
+                                    (l_message->sign_n_message+l_message->hdr.sign_size);
+            if( l_message->hdr.is_verified
+                    && l_message->hdr.sender_node_addr.uint64 == l_validator->uint64) {
+                dap_sign_t *l_candidate_sign = (dap_sign_t *)l_commitsign->candidate_sign;
+                size_t l_candidate_sign_size = dap_sign_get_size(l_candidate_sign);
+                if (!l_candidate_sign_size) {
+                    continue;
+                }
+                l_candidate = DAP_REALLOC(l_candidate, a_candidate_size+l_candidate_sign_size);
+                memcpy(((byte_t *)l_candidate)+a_candidate_size, l_candidate_sign, l_candidate_sign_size);
+                a_candidate_size += l_candidate_sign_size;
+                l_signs_count++;
+            }
+            l_submit_temp = l_submit_temp->next;
+        }
+    }
+
+    if (l_signs_count * 3 >= a_session->cur_round.validators_count * 2) {
+        dap_chain_atom_verify_res_t l_res = a_session->chain->callback_atom_add(a_session->chain, l_candidate, a_candidate_size);
+        char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(a_candidate_hash);
+        switch (l_res) {
+            case ATOM_ACCEPT: {
+                // block save to chain
+                if (dap_chain_atom_save(a_session->chain, (uint8_t *)l_candidate, a_candidate_size, a_session->chain->cells->id) < 0) {
+                    log_it(L_ERROR, "TON: Can't save atom %s to the file", l_candidate_hash_str);
+                }
+                else {
+                    log_it(L_INFO, "TON: atom %s added in chain successfully", l_candidate_hash_str);
+                }
+            } break;
+            case ATOM_MOVE_TO_THRESHOLD: {
+                log_it(L_INFO, "TON: Thresholded atom with hash %s", l_candidate_hash_str);
+            } break;
+            case ATOM_PASS: {
+                log_it(L_WARNING, "TON: Atom with hash %s not accepted (code ATOM_PASS, already present)", l_candidate_hash_str);
                 DAP_DELETE(l_candidate);
-		    } break;
-		    case ATOM_REJECT: {
-		        log_it(L_WARNING,"TON: Atom with hash %s rejected", l_candidate_hash_str);
+            } break;
+            case ATOM_REJECT: {
+                log_it(L_WARNING,"TON: Atom with hash %s rejected", l_candidate_hash_str);
                 DAP_DELETE(l_candidate);
-		    } break;
-		    default:
+            } break;
+            default:
                  log_it(L_CRITICAL, "TON: Wtf is this ret code ? Atom hash %s code %d", l_candidate_hash_str, l_res);
                  DAP_DELETE(l_candidate);
-		}
-		DAP_DELETE(l_candidate_hash_str);
-		dap_chain_hash_fast_t l_my_candidate_hash;
-		dap_hash_fast(a_session->my_candidate, a_session->my_candidate_size, &l_my_candidate_hash);
-		if (memcmp(&l_my_candidate_hash, a_candidate_hash,
-							sizeof(dap_chain_hash_fast_t)) == 0) {
-			s_session_my_candidate_delete(a_session);
-		}
-	}
-    //DAP_DELETE(l_candidate);
-}
-
-/**
- * @brief Callback in session state processing timer's context to process session state after GDB callback
- * @param a_worker
- * @param a_arg
- */
-static void s_callback_worker_session_proc_state(dap_worker_t * a_worker, void * a_arg)
-{
-    dap_chain_cs_block_ton_session_t * l_session = (dap_chain_cs_block_ton_session_t*) a_arg;
-    s_session_proc_state(l_session);
+        }
+        DAP_DELETE(l_candidate_hash_str);
+        dap_chain_hash_fast_t l_my_candidate_hash;
+        dap_hash_fast(a_session->my_candidate, a_session->my_candidate_size, &l_my_candidate_hash);
+        if (dap_hash_fast_compare(&l_my_candidate_hash, a_candidate_hash))
+            s_session_my_candidate_delete(a_session);
+    }
 }
 
-/**
- * @brief s_callback_block_new_add_datums_op_results
- * @param a_cs_blocks
- * @param a_rc
- * @param a_arg
- */
-static void s_callback_block_new_add_datums_op_results (dap_chain_cs_blocks_t * a_cs_blocks, int a_rc, void * a_arg)
+static void s_session_candidate_submit(dap_chain_cs_block_ton_session_t *a_session)
 {
-    dap_chain_cs_block_ton_session_t * l_session = (dap_chain_cs_block_ton_session_t*) a_arg;
-    dap_chain_t *l_chain = l_session->chain;
+    dap_chain_t *l_chain = a_session->chain;
+    s_session_my_candidate_delete(a_session);
+    a_session->worker = dap_worker_get_current();
+    assert (a_session->worker); // It must be called from worker's timer
     dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(l_chain);
-
-    if ( l_blocks->block_new_size && l_blocks->block_new) {
-        l_session->my_candidate = (dap_chain_block_t *)DAP_DUP_SIZE(l_blocks->block_new, l_blocks->block_new_size);
-        l_session->my_candidate_size = l_blocks->block_new_size;
-        s_session_block_new_delete(l_session);
-    }
-
-    size_t l_submit_size = l_session->my_candidate ?
-                sizeof(dap_chain_cs_block_ton_message_submit_t)+l_session->my_candidate_size
+    a_session->my_candidate = l_blocks->callback_new_block_move(l_blocks, &a_session->my_candidate_size);
+    size_t l_submit_size = a_session->my_candidate ?
+                sizeof(dap_chain_cs_block_ton_message_submit_t)+a_session->my_candidate_size
                     : sizeof(dap_chain_cs_block_ton_message_submit_t);
-
     dap_chain_cs_block_ton_message_submit_t *l_submit =
                             DAP_NEW_SIZE(dap_chain_cs_block_ton_message_submit_t, l_submit_size);
-    l_submit->round_id.uint64 = l_session->cur_round.id.uint64;
-    l_submit->candidate_size = l_session->my_candidate_size;
+    l_submit->round_id.uint64 = a_session->cur_round.id.uint64;
+    l_submit->candidate_size = a_session->my_candidate_size;
 
-    bool l_candidate_exists = false;
-    if ( l_session->my_candidate ) {
+    if ( a_session->my_candidate ) {
         dap_chain_hash_fast_t l_candidate_hash;
-        dap_hash_fast(l_session->my_candidate, l_session->my_candidate_size, &l_candidate_hash);
-        // pass if this candidate participated in old round
-        if ( !l_session->old_round.my_candidate_hash
-                        || memcmp(&l_candidate_hash, l_session->old_round.my_candidate_hash,
-                                        sizeof(dap_chain_hash_fast_t)) != 0 ) {
-            l_submit->candidate_hash = l_candidate_hash;
-            l_session->cur_round.my_candidate_hash =
-                    (dap_chain_hash_fast_t*)DAP_DUP_SIZE(&l_candidate_hash, sizeof(dap_chain_hash_fast_t));
-            memcpy(l_submit->candidate, l_session->my_candidate, l_session->my_candidate_size);
-            if (PVT(l_session->ton)->debug) {
-                char *l_hash_str = dap_chain_hash_fast_to_str_new(&l_candidate_hash);
-                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U" Submit my candidate:%s",
-                        l_session->chain->net_name, l_session->chain->name,
-                            l_session->cur_round.id.uint64, l_hash_str);
-                DAP_DELETE(l_hash_str);
-            }
-            l_session->my_candidate_attempts_count++;
-            l_candidate_exists = true;
+        dap_hash_fast(a_session->my_candidate, a_session->my_candidate_size, &l_candidate_hash);
+        a_session->cur_round.my_candidate_hash = l_submit->candidate_hash = l_candidate_hash;
+        memcpy(l_submit->candidate, a_session->my_candidate, a_session->my_candidate_size);
+        if (PVT(a_session->ton)->debug) {
+            char *l_hash_str = dap_chain_hash_fast_to_str_new(&l_candidate_hash);
+            log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U" Submit my candidate:%s",
+                    a_session->chain->net_name, a_session->chain->name,
+                        a_session->cur_round.id.uint64, l_hash_str);
+            DAP_DELETE(l_hash_str);
         }
-    }
-
-    if (!l_candidate_exists) { // no my candidate, send null hash
-        l_submit->candidate_hash = (dap_chain_hash_fast_t) { };
-        l_session->cur_round.my_candidate_hash = NULL;
-        if (PVT(l_session->ton)->debug)
+        a_session->my_candidate_attempts_count++;
+    } else { // no my candidate, send null hash
+        a_session->cur_round.my_candidate_hash = l_submit->candidate_hash = (dap_chain_hash_fast_t){};
+        if (PVT(a_session->ton)->debug)
             log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu I don't have a candidate. I submit a null candidate.",
-                        l_session->chain->net_name, l_session->chain->name,
-                            l_session->cur_round.id.uint64, l_session->attempt_current_number);
+                        a_session->chain->net_name, a_session->chain->name,
+                            a_session->cur_round.id.uint64, a_session->attempt_current_number);
     }
-    s_message_send(l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT,
-                    (uint8_t*)l_submit, l_submit_size, l_session->cur_round.validators_start);
+    s_message_send(a_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT,
+                    (uint8_t*)l_submit, l_submit_size, a_session->cur_round.validators_start);
     DAP_DELETE(l_submit);
-
-    l_session->time_proc_lock = false; // unlock
-    l_session->state = DAP_STREAM_CH_CHAIN_SESSION_STATE_CS_PROC_AFTER_SUBMIT; // Seconds stage after candidate submitted
-
-    dap_worker_t * l_worker = l_session->worker;
-    dap_global_db_context_t * l_gdb_context = (dap_global_db_context_t*) dap_context_current()->_inheritor;
-    assert(l_worker);
-    assert(l_gdb_context);
-    pthread_rwlock_unlock(&l_session->rwlock);
-    dap_worker_exec_callback_inter( l_gdb_context->queue_worker_callback_input[l_worker->id],s_callback_worker_session_proc_state, l_session );
-}
-
-static void s_session_candidate_submit(dap_chain_cs_block_ton_session_t *a_session) {
-	dap_chain_t *l_chain = a_session->chain;
-    s_session_my_candidate_delete(a_session);
-    a_session->worker = dap_worker_get_current();
-    assert (a_session->worker); // It must be called from worker's timer
-
-    dap_chain_cs_new_block_add_datums(l_chain, s_callback_block_new_add_datums_op_results, a_session); // add new datums from queue
 }
 
 static int s_session_atom_validation(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_t *a_block, size_t a_block_size){
     dap_chain_cs_block_ton_t *l_ton = DAP_CHAIN_CS_BLOCK_TON(a_blocks);
-	dap_chain_atom_verify_res_t l_res = ATOM_ACCEPT;
-	PVT(l_ton)->flag_sign_verify = false;
-	l_res = a_blocks->chain->callback_atom_verify(a_blocks->chain, a_block, a_block_size);
-	PVT(l_ton)->flag_sign_verify = true;
-	if(l_res == ATOM_ACCEPT){
-		return 0;
-	}
+    dap_chain_atom_verify_res_t l_res = ATOM_ACCEPT;
+    PVT(l_ton)->flag_sign_verify = false;
+    l_res = a_blocks->chain->callback_atom_verify(a_blocks->chain, a_block, a_block_size);
+    PVT(l_ton)->flag_sign_verify = true;
+    if(l_res == ATOM_ACCEPT){
+        return 0;
+    }
     return -1;
 }
 
-static void s_session_block_new_delete(dap_chain_cs_block_ton_session_t *a_session) {
-	dap_chain_t *l_chain = a_session->chain;
-	dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(l_chain);
-	l_blocks->callback_new_block_del(l_blocks);
-}
-
 static void s_session_my_candidate_delete(dap_chain_cs_block_ton_session_t *a_session) {
-	if (a_session->my_candidate){
-		if (PVT(a_session->ton)->debug) {
-			dap_chain_hash_fast_t l_candidate_hash;
-			dap_hash_fast(a_session->my_candidate, a_session->my_candidate_size, &l_candidate_hash);
-			char *l_hash_str = dap_chain_hash_fast_to_str_new(&l_candidate_hash);
-		    log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Delete my candidate %s",
-					a_session->chain->net_name, a_session->chain->name, a_session->cur_round.id.uint64,
-						a_session->attempt_current_number, l_hash_str );
-			DAP_DELETE(l_hash_str);
-		}
-		DAP_DEL_Z(a_session->my_candidate);
-	}
+    if (a_session->my_candidate){
+        if (PVT(a_session->ton)->debug) {
+            dap_chain_hash_fast_t l_candidate_hash;
+            dap_hash_fast(a_session->my_candidate, a_session->my_candidate_size, &l_candidate_hash);
+            char *l_hash_str = dap_chain_hash_fast_to_str_new(&l_candidate_hash);
+            log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Delete my candidate %s",
+                    a_session->chain->net_name, a_session->chain->name, a_session->cur_round.id.uint64,
+                        a_session->attempt_current_number, l_hash_str );
+            DAP_DELETE(l_hash_str);
+        }
+        DAP_DEL_Z(a_session->my_candidate);
+    }
     a_session->my_candidate_size = 0;
-   	a_session->my_candidate_attempts_count = 0;
+    a_session->my_candidate_attempts_count = 0;
 }
 
-static bool s_hash_is_null(dap_chain_hash_fast_t *a_hash){
-	if (!a_hash)
-		return true;
-	dap_chain_hash_fast_t l_candidate_hash_null={0};
-    return (memcmp(&l_candidate_hash_null, a_hash,
-                            sizeof(dap_chain_hash_fast_t)) == 0)
-						? true : false;
-}
+static void s_session_round_clear(dap_chain_cs_block_ton_session_t *a_session)
+{
+    // Truncate this group
+    dap_global_db_del(a_session->gdb_group_store, NULL, NULL, NULL);
+    dap_chain_cs_block_ton_message_item_t *l_message_item=NULL, *l_message_tmp=NULL;
+    HASH_ITER(hh, a_session->cur_round.messages_items, l_message_item, l_message_tmp) {
+        HASH_DEL(a_session->cur_round.messages_items, l_message_item);
+        DAP_DELETE(l_message_item->message);
+        DAP_DELETE(l_message_item);
+    }
 
-struct session_round_finish_args{
-    dap_chain_cs_block_ton_session_t *session;
-    bool is_time_proc_lock;
-};
+    if (a_session->cur_round.validators_start)
+        // delete only links
+        dap_list_free(a_session->cur_round.validators_start);
+    if (a_session->cur_round.validators_list)
+        // delete validators
+        dap_list_free_full(a_session->cur_round.validators_list, free);
+
+    dap_chain_cs_block_ton_round_id_t l_round_id = a_session->cur_round.id;
+    a_session->cur_round = (dap_chain_cs_block_ton_round_t){.id = l_round_id};
+}
 
 /**
  * @brief s_session_round_finish_callback_load_store
@@ -988,119 +856,38 @@ static bool s_session_round_finish_callback_load_store(dap_global_db_context_t *
                                                   const size_t a_values_count, dap_global_db_obj_t * a_values, void * a_arg)
 
 {
-    dap_chain_cs_block_ton_session_t *l_session = ((struct session_round_finish_args *)a_arg)->session;
-    bool l_is_time_proc_lock = ((struct session_round_finish_args *)a_arg)->is_time_proc_lock;
-    DAP_DELETE(a_arg);
+    dap_chain_cs_block_ton_session_t *l_session = (dap_chain_cs_block_ton_session_t *)a_arg;
 
-    if(! l_is_time_proc_lock){ // If its not locked we lock it by ourself for writting
-        pthread_rwlock_wrlock(&l_session->rwlock); // lock for writting
-    }
+    pthread_rwlock_wrlock(&l_session->rwlock); // lock for writting
 
     l_session->state = DAP_STREAM_CH_CHAIN_SESSION_STATE_IDLE;
     l_session->ts_round_finish = dap_time_now();
 
-    if (a_values_count) {
-        dap_chain_cs_block_ton_store_t *l_store_candidate_ready = NULL;
-        size_t l_candidate_ready_size = 0;
-        for (size_t i = 0; i < a_values_count; i++) {
-            if (!a_values[i].value_len)
-                continue;
-            dap_chain_cs_block_ton_store_t *l_store =
-                                        (dap_chain_cs_block_ton_store_t *)a_values[i].value;
-            if ( l_store->hdr.round_id.uint64 != l_session->cur_round.id.uint64
-                    ||  (l_store->hdr.round_id.uint64 == l_session->cur_round.id.uint64
-                            && !l_store->hdr.sign_collected) ) {
-                dap_global_db_del_unsafe(a_global_db_context,l_session->gdb_group_store,a_values[i].key );
-                if ( l_store->hdr.sign_collected ) {
-                    l_store_candidate_ready = l_store;
-                }
+    for (size_t i = 0; i < a_values_count; i++) {
+        if (!a_values[i].value_len)
+            continue;
+        dap_chain_cs_block_ton_store_t *l_store = (dap_chain_cs_block_ton_store_t*)a_values[i].value;
+        if (l_store->hdr.round_id.uint64 != l_session->cur_round.id.uint64)
+            continue;
+        if (l_store->hdr.sign_collected)
+            s_session_candidate_to_chain(l_session, &l_store->hdr.candidate_hash,
+                                             (dap_chain_block_t*)l_store->candidate_n_signs,
+                                             l_store->hdr.candidate_size);
+        else if (dap_hash_fast_compare(&l_store->hdr.candidate_hash, &l_session->cur_round.my_candidate_hash)) {
+            if (PVT(l_session->ton)->debug) {
+                char *l_hash_str = dap_chain_hash_fast_to_str_new(&l_store->hdr.candidate_hash);
+                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu My candidate:%s %s Delete block_new.",
+                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
+                            l_session->attempt_current_number, l_hash_str,
+                            (l_store->hdr.approve_collected ? "approved with consensus" : "didn't collect 2/3 approve."));
+                DAP_DELETE(l_hash_str);
             }
+            s_session_my_candidate_delete(l_session);
+            memset(&l_session->cur_round.my_candidate_hash, 0, sizeof(l_session->cur_round.my_candidate_hash));
 
-            if ( l_store->hdr.round_id.uint64 == l_session->cur_round.id.uint64 ) {
-                if ( l_session->cur_round.my_candidate_hash
-                        //&& !l_store->hdr.approve_collected
-                        && memcmp(&l_store->hdr.candidate_hash,
-                                l_session->cur_round.my_candidate_hash, sizeof(dap_chain_hash_fast_t)) == 0) {
-
-                    // delete my candidate if it passed consensus or not collected 2/3 approve
-                    if ( !l_store->hdr.approve_collected || l_store->hdr.sign_collected ) {
-                        // s_session_my_candidate_delete(a_session);
-                        // DAP_DELETE(a_session->cur_round.my_candidate_hash);
-                        // a_session->cur_round.my_candidate_hash=NULL;
-                        if (PVT(l_session->ton)->debug) {
-                            char *l_hash_str = dap_chain_hash_fast_to_str_new(&l_store->hdr.candidate_hash);
-                            log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu My candidate:%s %s Delete block_new.",
-                                    l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                                        l_session->attempt_current_number, l_hash_str,
-                                        (l_store->hdr.sign_collected ? "passed consensus!" : "didn't collected 2/3 approve.") );
-                            DAP_DELETE(l_hash_str);
-                        }
-                    }
-                }
-            }
         }
-        // if (l_store_candidate_ready) {
-        // 	s_session_candidate_to_chain(a_session, &l_store_candidate_ready->hdr.candidate_hash,
-        // 					(dap_chain_block_t*)l_store_candidate_ready->candidate_n_signs, l_store_candidate_ready->hdr.candidate_size);
-        // }
-    }
-
-    dap_chain_cs_block_ton_message_item_t *l_message_item=NULL, *l_message_tmp=NULL;
-    HASH_ITER(hh, l_session->old_round.messages_items, l_message_item, l_message_tmp) {
-        // Clang bug at this, l_message_item should change at every loop cycle
-        DAP_DELETE(l_message_item->message);
-        HASH_DEL(l_session->old_round.messages_items, l_message_item);
-        DAP_DELETE(l_message_item);
-    }
-
-    if ( l_session->old_round.validators_start ) {
-        // delete only links
-        dap_list_free(l_session->old_round.validators_start);
-    }
-    l_session->old_round.validators_start = NULL;
-
-    if ( l_session->old_round.validators_list ) {
-        // delete validators
-        dap_list_free_full(l_session->old_round.validators_list, NULL);
-    }
-    l_session->old_round.validators_list = NULL;
-
-    if ( l_session->old_round.last_message_hash ) {
-        DAP_DELETE(l_session->old_round.last_message_hash);
-        l_session->old_round.last_message_hash = NULL;
     }
-
-    if ( l_session->old_round.my_candidate_hash ) {
-        DAP_DELETE(l_session->old_round.my_candidate_hash);
-        l_session->old_round.my_candidate_hash = NULL;
-    }
-
-    // move cur round to old
-    l_session->old_round.id.uint64 = l_session->cur_round.id.uint64;
-
-    l_session->old_round.messages_items = l_session->cur_round.messages_items;
-    l_session->cur_round.messages_items = NULL;
-
-    l_session->old_round.validators_start_count = l_session->cur_round.validators_start_count;
-    l_session->old_round.validators_start = l_session->cur_round.validators_start;
-    l_session->cur_round.validators_start = NULL;
-
-    l_session->old_round.validators_count = l_session->cur_round.validators_count;
-    l_session->old_round.validators_list = l_session->cur_round.validators_list;
-    l_session->cur_round.validators_list = NULL;
-
-    l_session->old_round.candidates_count = l_session->cur_round.candidates_count;
-
-    l_session->old_round.last_message_hash = l_session->cur_round.last_message_hash;
-    l_session->cur_round.last_message_hash = NULL;
-    l_session->old_round.messages_count = l_session->cur_round.messages_count;
-
-    l_session->old_round.my_candidate_hash = l_session->cur_round.my_candidate_hash;
-    l_session->cur_round.my_candidate_hash = NULL;
-
-    if(l_is_time_proc_lock) // If its time proc locked we have to drop the flag
-        l_session->time_proc_lock = false; // unlock
-
+    s_session_round_clear(l_session);
     pthread_rwlock_unlock(&l_session->rwlock); // then unlock anyway
     return true;
 }
@@ -1110,73 +897,69 @@ static bool s_session_round_finish_callback_load_store(dap_global_db_context_t *
  * @param a_is_time_proc_lock
  * @return
  */
-static void s_session_round_finish(dap_chain_cs_block_ton_session_t *a_session, bool a_is_time_proc_lock)
+static void s_session_round_finish(dap_chain_cs_block_ton_session_t *a_session, bool a_failed)
 {
-    struct session_round_finish_args * l_args = DAP_NEW_Z(struct session_round_finish_args);
-    l_args->session = a_session;
-    l_args->is_time_proc_lock = a_is_time_proc_lock;
-    if (dap_global_db_get_all(a_session->gdb_group_store,0,s_session_round_finish_callback_load_store, l_args) != 0){
-        DAP_DELETE(l_args);
-        log_it(L_ERROR,"Can't process get_all request for group \"%s\"", a_session->gdb_group_store);
+    if (a_failed) {
+        s_session_round_clear(a_session);
+        return;
     }
+    if (dap_global_db_get_all(a_session->gdb_group_store,0,s_session_round_finish_callback_load_store, a_session) != 0)
+        log_it(L_ERROR,"Can't process get_all request for group \"%s\"", a_session->gdb_group_store);
 }
 
 // this is planned for get validator addr if validator addr list to be changed to stakes,
 // but currently it using for check validator addr exists
-static dap_chain_node_addr_t *s_session_get_validator(
-                    dap_chain_cs_block_ton_session_t * a_session, dap_chain_node_addr_t * a_addr,
-						dap_list_t *a_validators) {
-	// dap_chain_cs_block_ton_round_t *l_round = a_round_name == DAP_TON$ROUND_CUR ? // 'c' or 'o'
-	// 					&a_session->cur_round : &a_session->old_round;
-	dap_list_t* l_list_validator = dap_list_first(a_validators);
-	while(l_list_validator) {
-		dap_list_t *l_list_validator_next = l_list_validator->next;
-		if ( ((dap_chain_node_addr_t *)l_list_validator->data)->uint64 == a_addr->uint64 )
-			return l_list_validator->data;
-		l_list_validator = l_list_validator_next;
-	}
-	return NULL;
+static dap_chain_node_addr_t *s_session_get_validator(dap_chain_cs_block_ton_session_t *a_session,
+                                                      dap_chain_node_addr_t *a_addr,
+                                                      dap_list_t *a_validators)
+{
+
+    // dap_chain_cs_block_ton_round_t *l_round = a_round_name == DAP_TON$ROUND_CUR ? // 'c' or 'o'
+    // 					&a_session->cur_round : &a_session->old_round;
+    dap_list_t* l_list_validator = dap_list_first(a_validators);
+    while(l_list_validator) {
+        dap_list_t *l_list_validator_next = l_list_validator->next;
+        if ( ((dap_chain_node_addr_t *)l_list_validator->data)->uint64 == a_addr->uint64 )
+            return l_list_validator->data;
+        l_list_validator = l_list_validator_next;
+    }
+    return NULL;
 }
 
-static uint16_t s_session_message_count(
-            dap_chain_cs_block_ton_session_t *a_session, uint8_t a_round_name, uint8_t a_type,
-						dap_chain_hash_fast_t *a_candidate_hash, uint16_t *a_attempt_number) {
-	dap_chain_cs_block_ton_message_item_t *l_messages_items = NULL;
-	l_messages_items = a_round_name == DAP_TON$ROUND_CUR ? // 'c' or 'o'
-						a_session->cur_round.messages_items
-					  : a_session->old_round.messages_items;
-	uint16_t l_message_count = 0;
-	dap_chain_cs_block_ton_message_item_t *l_chain_message=NULL, *l_chain_message_tmp=NULL;
-	HASH_ITER(hh, l_messages_items, l_chain_message, l_chain_message_tmp) {
-		dap_chain_cs_block_ton_message_getinfo_t *l_getinfo = 
-					(dap_chain_cs_block_ton_message_getinfo_t *)
-							(l_chain_message->message->sign_n_message+l_chain_message->message->hdr.sign_size);
-		if (
-				l_chain_message->message->hdr.type == a_type
-				&& (!a_candidate_hash || memcmp(&l_getinfo->candidate_hash, a_candidate_hash,
-											sizeof(dap_chain_hash_fast_t)) == 0)
-			) {
-				switch(a_type) {
-					// case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT:
-					case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE_FOR:
-					case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE: {
-						if ( a_attempt_number && *a_attempt_number == l_getinfo->attempt_number) {
-							l_message_count++;
-						}
-					} break;
-					case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE:
-					case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN: {
-						if (l_chain_message->message->hdr.is_verified){
-							l_message_count++;
-						}
-					} break;
-					default:
-						l_message_count++;
-						break;
-				}
-		}
-	}
-	return l_message_count;
+static uint16_t s_session_message_count(dap_chain_cs_block_ton_session_t *a_session, uint8_t a_type,
+                                        dap_chain_hash_fast_t *a_candidate_hash, uint16_t *a_attempt_number)
+{
+    dap_chain_cs_block_ton_message_item_t *l_messages_items = NULL;
+    l_messages_items = a_session->cur_round.messages_items;
+    uint16_t l_message_count = 0;
+    dap_chain_cs_block_ton_message_item_t *l_chain_message=NULL, *l_chain_message_tmp=NULL;
+    HASH_ITER(hh, l_messages_items, l_chain_message, l_chain_message_tmp) {
+        dap_chain_cs_block_ton_message_getinfo_t *l_getinfo = (dap_chain_cs_block_ton_message_getinfo_t *)
+                            (l_chain_message->message->sign_n_message+l_chain_message->message->hdr.sign_size);
+        if (l_chain_message->message->hdr.type == a_type &&
+                (!a_candidate_hash || memcmp(&l_getinfo->candidate_hash, a_candidate_hash,
+                                            sizeof(dap_chain_hash_fast_t)) == 0)) {
+            switch(a_type) {
+                // case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT:
+                case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE_FOR:
+                case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE: {
+                    if ( a_attempt_number && *a_attempt_number == l_getinfo->attempt_number) {
+                        l_message_count++;
+                    }
+                } break;
+                case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE:
+                case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN: {
+                    if (l_chain_message->message->hdr.is_verified){
+                        l_message_count++;
+                    }
+                } break;
+                default:
+                    l_message_count++;
+                    break;
+            }
+        }
+    }
+    return l_message_count;
 }
 
 struct vote_for_load_store_args
@@ -1282,26 +1065,6 @@ static bool s_session_packet_in_callback_vote_for_load_store (dap_global_db_cont
     return true;
 }
 
-/**
- * @brief s_session_packet_in_handler_finish_save
- * @param l_session
- * @param a_sender_node_addr
- * @param a_message
- * @param a_message_size
- * @param a_finalize_consensus
- */
-static void s_session_packet_in_handler_finish_save(dap_chain_cs_block_ton_session_t *l_session, dap_chain_node_addr_t *a_sender_node_addr,
-                                                    dap_chain_cs_block_ton_message_t * a_message,size_t a_message_size,
-                                               bool a_finalize_consensus)
-{
-    // save to messages chain
-    dap_chain_hash_fast_t l_message_hash;
-    s_message_chain_add(l_session, a_sender_node_addr, a_message, a_message_size, &l_message_hash);
-    if (a_finalize_consensus) {
-        s_session_round_finish(l_session,false);
-    }
-}
-
 /**
  * @brief The proc_msg_type_commit_sign struct
  */
@@ -1348,7 +1111,6 @@ static void s_callback_get_candidate_block_and_commit_sign (dap_global_db_contex
 
     size_t l_store_size = a_value_size;
     dap_chain_cs_block_ton_store_t *l_store = (dap_chain_cs_block_ton_store_t *) a_value;
-    bool l_finalize_consensus = false;
 
     pthread_rwlock_rdlock(&l_session->rwlock);
 
@@ -1367,30 +1129,26 @@ static void s_callback_get_candidate_block_and_commit_sign (dap_global_db_contex
             if (dap_global_db_set(l_session->gdb_group_store, l_candidate_hash_str, l_store,
                             l_store_size, true, NULL, NULL) == 0 ) {
                 uint16_t l_commitsign_count = s_session_message_count(
-                    l_session, DAP_TON$ROUND_CUR, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN,
+                                l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN,
                                 &l_candidate_hash, NULL);
                 l_commitsign_count++;
-                if ( 3* l_commitsign_count >= 2*l_round->validators_count ) {
-                    // s_session_round_finish(l_session,false);
-                    if (l_round_id.uint64 == l_session->cur_round.id.uint64) {
-                        l_finalize_consensus = true;
-                    }
+                if (l_commitsign_count * 3 >= l_round->validators_count * 2) {
                     if (PVT(l_session->ton)->debug)
-                        log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Candidate:%s collected COMMIT_SIGN more than 2/3 of the validators, so to finished this round",
+                        log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Candidate:%s collected COMMIT_SIGN more than 2/3 of the validators, so finish this round",
                                 l_session->chain->net_name, l_session->chain->name, l_round->id.uint64,
                                     l_session->attempt_current_number, l_candidate_hash_str);
+                    if (l_round_id.uint64 == l_session->cur_round.id.uint64) {
+                        s_message_chain_add(l_session, &l_sender_node_addr, l_message, l_message_size, NULL);
+                        s_session_round_finish(l_session, false);
+                    }
                 }
             }
-        }
-        else {
+        } else
             log_it(L_WARNING, "Candidate:%s sign is incorrect: code %d", l_candidate_hash_str, l_sign_verified);
-        }
     }
     pthread_rwlock_unlock(&l_session->rwlock);
     DAP_DELETE(l_store);
     DAP_DELETE(l_candidate_hash_str);
-    s_session_packet_in_handler_finish_save(l_session, &l_sender_node_addr,l_message, l_message_size, l_finalize_consensus);
-
 }
 
 
@@ -1513,15 +1271,13 @@ static void s_callback_get_candidate_block_and_vote (dap_global_db_context_t * a
         if (dap_global_db_set_unsafe(a_global_db_context, l_session->gdb_group_store, l_candidate_hash_str,
                               l_store,	l_store_size, true ) == 0 ) {
             // Send PreCommit
-            dap_chain_cs_block_ton_message_precommit_t *l_precommit =
-                                        DAP_NEW_Z(dap_chain_cs_block_ton_message_precommit_t);
-            l_precommit->round_id.uint64 = l_session->cur_round.id.uint64;
-//            memcpy(&l_precommit->candidate_hash, &l_candidate_hash, sizeof(dap_chain_hash_fast_t));
-            l_precommit->candidate_hash = l_candidate_hash;
-            l_precommit->attempt_number = l_session->attempt_current_number;
-            s_message_send(l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT, (uint8_t*)l_precommit,
+            dap_chain_cs_block_ton_message_precommit_t l_precommit = {
+                .round_id.uint64 = l_session->cur_round.id.uint64,
+                .candidate_hash = l_candidate_hash,
+                .attempt_number = l_session->attempt_current_number
+            };
+            s_message_send(l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT, (uint8_t*)&l_precommit,
                             sizeof(dap_chain_cs_block_ton_message_precommit_t), l_session->cur_round.validators_start);
-            DAP_DELETE(l_precommit);
             if (PVT(l_session->ton)->debug)
                 log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Candidate:%s collected VOTE more than 2/3 of the validators, so to sent a PRE_COMMIT",
                         l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
@@ -1634,11 +1390,9 @@ static void s_callback_check_and_save_candidate_block  (dap_global_db_context_t
     dap_chain_block_t * l_candidate = l_args->candidate;
     size_t l_candidate_size = l_args->candidate_size;
     dap_nanotime_t l_time = l_args->time;
-    dap_chain_hash_fast_t l_candidate_hash;
-    memcpy(&l_candidate_hash, &l_args->candidate_hash, sizeof(l_args->candidate_hash));
+    dap_chain_hash_fast_t l_candidate_hash = l_args->candidate_hash;
     DAP_DELETE(l_args);
 
-    size_t l_store_temp_size = a_value_size;
     dap_chain_cs_block_ton_store_t *l_store_temp = (dap_chain_cs_block_ton_store_t *) a_value;
     if (l_store_temp) {
         log_it(L_WARNING, "TON: Duplicate candidate:%s", l_candidate_hash_str);
@@ -1646,12 +1400,10 @@ static void s_callback_check_and_save_candidate_block  (dap_global_db_context_t
         DAP_DELETE(l_candidate);
         return;
     }
+    // store for new candidate
+    size_t l_store_size = sizeof(dap_chain_cs_block_ton_store_hdr_t) + l_candidate_size;
+    dap_chain_cs_block_ton_store_t *l_store = DAP_NEW_Z_SIZE(dap_chain_cs_block_ton_store_t, l_store_size);
 
-    pthread_rwlock_rdlock(&l_session->rwlock);
-    // stor for new candidate
-    size_t l_store_size = sizeof(dap_chain_cs_block_ton_store_hdr_t)+l_candidate_size;
-    dap_chain_cs_block_ton_store_t *l_store =
-                            DAP_NEW_Z_SIZE(dap_chain_cs_block_ton_store_t, l_store_size);
     l_store->hdr.sign_collected = false;
     l_store->hdr.approve_collected = false;
     l_store->hdr.vote_collected = false;
@@ -1659,10 +1411,10 @@ static void s_callback_check_and_save_candidate_block  (dap_global_db_context_t
     l_store->hdr.candidate_size = l_candidate_size;
     l_store->hdr.ts_candidate_submit = l_time;
     l_store->hdr.round_id.uint64 = l_session->cur_round.id.uint64;
-    memcpy( &l_store->hdr.candidate_hash, &l_candidate_hash, sizeof(dap_chain_hash_fast_t));
-    memcpy( &l_store->candidate_n_signs, l_candidate, l_candidate_size);
+    l_store->hdr.candidate_hash = l_candidate_hash;
+    memcpy(&l_store->candidate_n_signs, l_candidate, l_candidate_size);
 
-    pthread_rwlock_rdlock(&l_session->rwlock);
+    pthread_rwlock_wrlock(&l_session->rwlock);
     // save new block candidate
     if (dap_global_db_set_unsafe(a_global_db_context, l_session->gdb_group_store, l_candidate_hash_str, l_store,
                                             l_store_size, true) == 0) {
@@ -1727,18 +1479,18 @@ static void s_callback_check_and_save_candidate_block  (dap_global_db_context_t
  * @param a_data
  * @param a_data_size
  */
-static void s_session_packet_in(void *a_arg, dap_chain_node_addr_t *a_sender_node_addr, 
+static void s_session_packet_in(void *a_arg, dap_chain_node_addr_t *a_sender_node_addr,
                                 dap_chain_hash_fast_t *a_data_hash, uint8_t *a_data, size_t a_data_size)
 {
     dap_chain_cs_block_ton_session_t *l_session = (dap_chain_cs_block_ton_session_t *)a_arg;
-	dap_chain_cs_block_ton_message_t *l_message =
-			(dap_chain_cs_block_ton_message_t *)DAP_DUP_SIZE(a_data, a_data_size);
+    dap_chain_cs_block_ton_message_t *l_message =
+            (dap_chain_cs_block_ton_message_t *)DAP_DUP_SIZE(a_data, a_data_size);
 
-	if (PVT(l_session->ton)->debug)
+    if (PVT(l_session->ton)->debug)
         log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive pkt type:%x from addr:"NODE_ADDR_FP_STR", my_addr:"NODE_ADDR_FP_STR"",
-				l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-					l_session->attempt_current_number, l_message->hdr.type,
-						NODE_ADDR_FP_ARGS(a_sender_node_addr), NODE_ADDR_FP_ARGS(l_session->my_addr));
+                l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
+                    l_session->attempt_current_number, l_message->hdr.type,
+                        NODE_ADDR_FP_ARGS(a_sender_node_addr), NODE_ADDR_FP_ARGS(l_session->my_addr));
 
     if( sizeof(*l_message)+l_message->hdr.sign_size > a_data_size){
         log_it(L_WARNING, "TON: incorrect message size in header is %zu when data size is only %zu and header size is %zu",
@@ -1748,361 +1500,356 @@ static void s_session_packet_in(void *a_arg, dap_chain_node_addr_t *a_sender_nod
     size_t l_message_data_size = a_data_size - sizeof(*l_message) - l_message->hdr.sign_size ;
     byte_t * l_message_data = l_message->sign_n_message + l_message->hdr.sign_size;
 
-	if ( !PVT(l_session->ton)->validators_list_by_stake ) {
-		size_t l_data_size = 0;
-		dap_sign_t *l_sign = (dap_sign_t*)l_message->sign_n_message;
-		uint8_t *l_data = s_message_data_sign(l_session, l_message, &l_data_size);
-		bool l_verify_passed = false;
-		for (uint16_t j = 0; j < PVT(l_session->ton)->auth_certs_count; j++) {
-		    if ( dap_cert_compare_with_sign(PVT(l_session->ton)->auth_certs[j], l_sign) == 0
-		    		&& dap_sign_verify(l_sign, l_data, l_data_size) == 1 ) {
-		    	l_verify_passed = true;
-		    	break;
-		    }
-		}
-		//DAP_DELETE(l_sign);
-		DAP_DELETE(l_data);
-		if (!l_verify_passed) {
-			if (PVT(l_session->ton)->debug)
-		        log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected from addr:"NODE_ADDR_FP_STR" not passed verification",
-						l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-							l_session->attempt_current_number, NODE_ADDR_FP_ARGS(a_sender_node_addr));
-		    goto handler_finish;
-		}
-	}
-    
+    if ( !PVT(l_session->ton)->validators_list_by_stake ) {
+        size_t l_data_size = 0;
+        dap_sign_t *l_sign = (dap_sign_t*)l_message->sign_n_message;
+        uint8_t *l_data = s_message_data_sign(l_session, l_message, &l_data_size);
+        bool l_verify_passed = false;
+        for (uint16_t j = 0; j < PVT(l_session->ton)->auth_certs_count; j++) {
+            if ( dap_cert_compare_with_sign(PVT(l_session->ton)->auth_certs[j], l_sign) == 0
+                    && dap_sign_verify(l_sign, l_data, l_data_size) == 1 ) {
+                l_verify_passed = true;
+                break;
+            }
+        }
+        //DAP_DELETE(l_sign);
+        DAP_DELETE(l_data);
+        if (!l_verify_passed) {
+            if (PVT(l_session->ton)->debug)
+                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected from addr:"NODE_ADDR_FP_STR" not passed verification",
+                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
+                            l_session->attempt_current_number, NODE_ADDR_FP_ARGS(a_sender_node_addr));
+            goto handler_finish;
+        }
+    }
+
     if (l_message->hdr.chain_id.uint64 != l_session->chain->id.uint64 ) {
-    	goto handler_finish;
+        goto handler_finish;
     }
 
     dap_time_t l_time = dap_time_now();
-	l_message->hdr.is_verified=false;
+    l_message->hdr.is_verified=false;
 
     dap_chain_hash_fast_t l_data_hash = {};
     dap_hash_fast(a_data, a_data_size, &l_data_hash);
     if (memcmp(a_data_hash, &l_data_hash, sizeof(dap_chain_hash_fast_t)) != 0) {
-		if (PVT(l_session->ton)->debug)
+        if (PVT(l_session->ton)->debug)
             log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: message hash does not match",
-					l_session->chain->net_name, l_session->chain->name,
-						l_session->cur_round.id.uint64, l_session->attempt_current_number);
-		goto handler_finish;
+                    l_session->chain->net_name, l_session->chain->name,
+                        l_session->cur_round.id.uint64, l_session->attempt_current_number);
+        goto handler_finish;
     }
 
-	// consensus round start sync
-	if ( l_message->hdr.type == DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_START_SYNC ) {
-		// check time offset
-		dap_chain_cs_block_ton_message_startsync_t *l_startsync =
-							(dap_chain_cs_block_ton_message_startsync_t *)
-									(l_message->sign_n_message+l_message->hdr.sign_size);
+    // consensus round start sync
+    if ( l_message->hdr.type == DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_START_SYNC ) {
+        // check time offset
+        dap_chain_cs_block_ton_message_startsync_t *l_startsync =
+                            (dap_chain_cs_block_ton_message_startsync_t *)
+                                    (l_message->sign_n_message+l_message->hdr.sign_size);
 
-		if (PVT(l_session->ton)->debug)
+        if (PVT(l_session->ton)->debug)
             log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive START_SYNC: from addr:"NODE_ADDR_FP_STR"",
-					l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-						l_session->attempt_current_number, NODE_ADDR_FP_ARGS(a_sender_node_addr));
-
-		dap_chain_node_addr_t *l_validator = 
-				s_session_get_validator(l_session, a_sender_node_addr, l_session->cur_round.validators_list);
-
-		if (!l_validator) {
-			if (PVT(l_session->ton)->debug)
-            	log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: validator addr:"NODE_ADDR_FP_STR" not on the list.",
-					l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-						l_session->attempt_current_number, NODE_ADDR_FP_ARGS(a_sender_node_addr));
-			goto handler_finish;
-		}
-
-		if ( 
-			(l_time>l_startsync->ts && (l_time-l_startsync->ts) > PVT(l_session->ton)->allowed_clock_offset )
-				|| (l_time<l_startsync->ts && (l_startsync->ts-l_time) > PVT(l_session->ton)->allowed_clock_offset )
-					) {
-			// offset is more than allowed_clock_offset
-			// skip this validator 
-			if (PVT(l_session->ton)->debug)
+                    l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
+                        l_session->attempt_current_number, NODE_ADDR_FP_ARGS(a_sender_node_addr));
+
+        dap_chain_node_addr_t *l_validator =
+                s_session_get_validator(l_session, a_sender_node_addr, l_session->cur_round.validators_list);
+
+        if (!l_validator) {
+            if (PVT(l_session->ton)->debug)
+                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: validator addr:"NODE_ADDR_FP_STR" not in the list.",
+                    l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
+                        l_session->attempt_current_number, NODE_ADDR_FP_ARGS(a_sender_node_addr));
+            goto handler_finish;
+        }
+
+        if (
+            (l_time>l_startsync->ts && (l_time-l_startsync->ts) > PVT(l_session->ton)->allowed_clock_offset )
+                || (l_time<l_startsync->ts && (l_startsync->ts-l_time) > PVT(l_session->ton)->allowed_clock_offset )
+                    ) {
+            // offset is more than allowed_clock_offset
+            // skip this validator
+            if (PVT(l_session->ton)->debug)
                 log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: too much time difference: my time:%"DAP_UINT64_FORMAT_U" sender time:%"DAP_UINT64_FORMAT_U"",
-						l_session->chain->net_name, l_session->chain->name,
-							l_session->cur_round.id.uint64, l_session->attempt_current_number, l_time, l_startsync->ts);
-			goto handler_finish;
-		}
-
-		// add check&save sender addr
-		dap_list_t *l_list_temp = dap_list_first(l_session->cur_round.validators_start);
-		while(l_list_temp) {
-			dap_list_t *l_list_next = l_list_temp->next;
-			if (((dap_chain_node_addr_t *)l_list_temp->data)->uint64 == l_validator->uint64) {
-				if (PVT(l_session->ton)->debug)
+                        l_session->chain->net_name, l_session->chain->name,
+                            l_session->cur_round.id.uint64, l_session->attempt_current_number, l_time, l_startsync->ts);
+            goto handler_finish;
+        }
+
+        // add check&save sender addr
+        dap_list_t *l_list_temp = dap_list_first(l_session->cur_round.validators_start);
+        while(l_list_temp) {
+            dap_list_t *l_list_next = l_list_temp->next;
+            if (((dap_chain_node_addr_t *)l_list_temp->data)->uint64 == l_validator->uint64) {
+                if (PVT(l_session->ton)->debug)
                     log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: repeated sync message from addr:"NODE_ADDR_FP_STR"",
-							l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-								l_session->attempt_current_number, NODE_ADDR_FP_ARGS(a_sender_node_addr));
-				goto handler_finish;
-			}
-			l_list_temp = l_list_next;
-		}
-
-		//sync round_id
-		if ( l_session->cur_round.id.uint64 < l_startsync->round_id.uint64 ) {
-			l_session->cur_round.id.uint64 = l_startsync->round_id.uint64;
-		}
-
-		l_session->cur_round.validators_start = dap_list_append(l_session->cur_round.validators_start, l_validator);
-		l_session->cur_round.validators_start_count = dap_list_length(l_session->cur_round.validators_start);
-		// if ( l_session->ts_round_start_pub < l_startsync->ts )
-		// 	l_session->ts_round_start_pub = l_startsync->ts;
-		// l_session->ts_round_start = (dap_chain_time_t)time(NULL); // l_startsync->ts; // set max time of start consensus
-		goto handler_finish;
-	}
-
-	// validator check
-	uint64_t l_round_id =
-				((dap_chain_cs_block_ton_message_getinfo_t *)
-						(l_message->sign_n_message+l_message->hdr.sign_size))->round_id.uint64;
-	dap_chain_node_addr_t *l_validator = NULL;
-	l_validator = l_round_id == l_session->old_round.id.uint64 ? 
-								  s_session_get_validator(l_session, a_sender_node_addr, l_session->old_round.validators_start)
-								: s_session_get_validator(l_session, a_sender_node_addr, l_session->cur_round.validators_start);
-	if (!l_validator) {
-		if (PVT(l_session->ton)->debug) 
-            log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: validator addr:"NODE_ADDR_FP_STR" not on the list.",
-					l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-						l_session->attempt_current_number, NODE_ADDR_FP_ARGS(a_sender_node_addr));
-		goto handler_finish;
-	}
-
-	// round check
-	if ( l_message->hdr.type != DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN ) {
-		if ( l_session->state != DAP_STREAM_CH_CHAIN_SESSION_STATE_CS_PROC
-				&& l_session->state != DAP_STREAM_CH_CHAIN_SESSION_STATE_WAIT_SIGNS ) {
-			goto handler_finish;
-		}
-		if ( l_round_id != l_session->cur_round.id.uint64) {
-			if (PVT(l_session->ton)->debug)
+                            l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
+                                l_session->attempt_current_number, NODE_ADDR_FP_ARGS(a_sender_node_addr));
+                goto handler_finish;
+            }
+            l_list_temp = l_list_next;
+        }
+
+        //sync round_id
+        if ( l_session->cur_round.id.uint64 < l_startsync->round_id.uint64 ) {
+            l_session->cur_round.id.uint64 = l_startsync->round_id.uint64;
+        }
+
+        l_session->cur_round.validators_start = dap_list_append(l_session->cur_round.validators_start, l_validator);
+        l_session->cur_round.validators_start_count = dap_list_length(l_session->cur_round.validators_start);
+        // if ( l_session->ts_round_start_pub < l_startsync->ts )
+        // 	l_session->ts_round_start_pub = l_startsync->ts;
+        // l_session->ts_round_start = (dap_chain_time_t)time(NULL); // l_startsync->ts; // set max time of start consensus
+        goto handler_finish;
+    }
+
+    // validator check
+    uint64_t l_round_id =
+                ((dap_chain_cs_block_ton_message_getinfo_t *)
+                        (l_message->sign_n_message+l_message->hdr.sign_size))->round_id.uint64;
+    dap_chain_node_addr_t *l_validator = NULL;
+    if (l_round_id == l_session->cur_round.id.uint64)
+        l_validator = s_session_get_validator(l_session, a_sender_node_addr, l_session->cur_round.validators_start);
+    if (!l_validator) {
+        if (PVT(l_session->ton)->debug)
+            log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: validator addr:"NODE_ADDR_FP_STR" not in the list.",
+                    l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
+                        l_session->attempt_current_number, NODE_ADDR_FP_ARGS(a_sender_node_addr));
+        goto handler_finish;
+    }
+
+    // round check
+    if ( l_message->hdr.type != DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN ) {
+        if ( l_session->state != DAP_STREAM_CH_CHAIN_SESSION_STATE_CS_PROC
+                && l_session->state != DAP_STREAM_CH_CHAIN_SESSION_STATE_WAIT_SIGNS ) {
+            goto handler_finish;
+        }
+        if ( l_round_id != l_session->cur_round.id.uint64) {
+            if (PVT(l_session->ton)->debug)
                 log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: round in message does not match to current round",
-						l_session->chain->net_name, l_session->chain->name,
-							l_session->cur_round.id.uint64, l_session->attempt_current_number);
-			goto handler_finish;
-		}
-	} else {
-		if ( l_round_id != l_session->cur_round.id.uint64
-					&& l_round_id != l_session->old_round.id.uint64 ) {
-			if (PVT(l_session->ton)->debug)
+                        l_session->chain->net_name, l_session->chain->name,
+                            l_session->cur_round.id.uint64, l_session->attempt_current_number);
+            goto handler_finish;
+        }
+    } else {
+        if (l_round_id != l_session->cur_round.id.uint64) {
+            if (PVT(l_session->ton)->debug)
                 log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: round in message does not match to current round",
-						l_session->chain->net_name, l_session->chain->name,
-							l_session->cur_round.id.uint64, l_session->attempt_current_number);
-			goto handler_finish;
-		}
-	}
-
-	if ( l_session->attempt_current_number != 1 ) {
-		switch (l_message->hdr.type) { // this types allow only in first attempt
-			case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT:
-			case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE:
-			case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT: {
-			if (PVT(l_session->ton)->debug)
+                        l_session->chain->net_name, l_session->chain->name,
+                            l_session->cur_round.id.uint64, l_session->attempt_current_number);
+            goto handler_finish;
+        }
+    }
+
+    if ( l_session->attempt_current_number != 1 ) {
+        switch (l_message->hdr.type) { // this types allow only in first attempt
+            case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT:
+            case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE:
+            case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT: {
+            if (PVT(l_session->ton)->debug)
                 log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: message type:%x allowed only in first attempt",
-						l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-							l_session->attempt_current_number, l_message->hdr.type);
-				goto handler_finish;
-			}
-		}
-	}
-
-	dap_chain_cs_block_ton_message_item_t *l_messages_items = NULL;
-	l_messages_items = l_round_id == l_session->old_round.id.uint64 ?
-						l_session->old_round.messages_items : l_session->cur_round.messages_items;
-
-	// check hash message dup
-	dap_chain_cs_block_ton_message_item_t *l_message_item_temp = NULL;
-	HASH_FIND(hh, l_messages_items, a_data_hash, sizeof(dap_chain_hash_fast_t), l_message_item_temp);
-	if (l_message_item_temp) {
-		if (PVT(l_session->ton)->debug)
+                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
+                            l_session->attempt_current_number, l_message->hdr.type);
+                goto handler_finish;
+            }
+        }
+    }
+
+    dap_chain_cs_block_ton_message_item_t *l_messages_items = l_session->cur_round.messages_items;
+
+    // check hash message dup
+    dap_chain_cs_block_ton_message_item_t *l_message_item_temp = NULL;
+    HASH_FIND(hh, l_messages_items, a_data_hash, sizeof(dap_chain_hash_fast_t), l_message_item_temp);
+    if (l_message_item_temp) {
+        if (PVT(l_session->ton)->debug)
             log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: message hash is exists in chain (duplicate?)",
-					l_session->chain->net_name, l_session->chain->name,
-						l_session->cur_round.id.uint64, l_session->attempt_current_number);
-		goto handler_finish;
-	}
-
-	// check validator index in queue for event Submit
-	if ( l_message->hdr.type == DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT ) {
-		dap_list_t *l_validators_list = dap_list_first(l_session->cur_round.validators_start);
-		int l_validator_number = 0;
-		int i = 0;
-		while(l_validators_list) {
-			if( ((dap_chain_node_addr_t *)l_validators_list->data)->uint64 == a_sender_node_addr->uint64) {
-				l_validator_number = i;
-				break;
-			}
-			i++;
-			l_validators_list = l_validators_list->next;
-		}
-		if ( l_validator_number ) { // pass if I first validator
-			int l_submit_count = 0;
-			dap_chain_cs_block_ton_message_item_t *l_chain_message=NULL, *l_chain_message_tmp=NULL;
-    		HASH_ITER(hh, l_messages_items, l_chain_message, l_chain_message_tmp) {
-    			if ( l_chain_message->message->hdr.type == DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT ) {
-    				l_submit_count++;
-    			}
-    		}
-    		if ( l_validator_number < l_submit_count ) {
-    			// Skip this SUBMIT. Validator must wait its queue.
-				if (PVT(l_session->ton)->debug)
+                    l_session->chain->net_name, l_session->chain->name,
+                        l_session->cur_round.id.uint64, l_session->attempt_current_number);
+        goto handler_finish;
+    }
+
+    // check validator index in queue for event Submit
+    if ( l_message->hdr.type == DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT ) {
+        dap_list_t *l_validators_list = dap_list_first(l_session->cur_round.validators_start);
+        int l_validator_number = 0;
+        int i = 0;
+        while(l_validators_list) {
+            if( ((dap_chain_node_addr_t *)l_validators_list->data)->uint64 == a_sender_node_addr->uint64) {
+                l_validator_number = i;
+                break;
+            }
+            i++;
+            l_validators_list = l_validators_list->next;
+        }
+        if ( l_validator_number ) { // pass if I first validator
+            int l_submit_count = 0;
+            dap_chain_cs_block_ton_message_item_t *l_chain_message=NULL, *l_chain_message_tmp=NULL;
+            HASH_ITER(hh, l_messages_items, l_chain_message, l_chain_message_tmp) {
+                if ( l_chain_message->message->hdr.type == DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT ) {
+                    l_submit_count++;
+                }
+            }
+            if ( l_validator_number < l_submit_count ) {
+                // Skip this SUBMIT. Validator must wait its queue.
+                if (PVT(l_session->ton)->debug)
                     log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: Validator must wait its queue for sent SUBMIT",
-							l_session->chain->net_name, l_session->chain->name,
-								l_session->cur_round.id.uint64, l_session->attempt_current_number);
-    			goto handler_finish;
-    		}
-		}
-	}
+                            l_session->chain->net_name, l_session->chain->name,
+                                l_session->cur_round.id.uint64, l_session->attempt_current_number);
+                goto handler_finish;
+            }
+        }
+    }
 
     uint32_t /* l_approve_count = 0, */ l_vote_count = 0, l_precommit_count = 0;
-	// check messages chain
+    // check messages chain
     dap_chain_cs_block_ton_message_item_t *l_chain_message=NULL, *l_chain_message_tmp=NULL;
     HASH_ITER(hh, l_messages_items, l_chain_message, l_chain_message_tmp) {
-    	if (l_chain_message->message->hdr.sender_node_addr.uint64 == a_sender_node_addr->uint64) {
-    		dap_chain_hash_fast_t *l_candidate_hash_cur = 
-    				&((dap_chain_cs_block_ton_message_getinfo_t *)
-    						(l_message->sign_n_message+l_message->hdr.sign_size))->candidate_hash;
-
-    		dap_chain_hash_fast_t *l_candidate_hash = 
-    			&((dap_chain_cs_block_ton_message_getinfo_t *)
-    				(l_chain_message->message->sign_n_message+l_chain_message->message->hdr.sign_size))->candidate_hash;
-
-    		bool l_candidate_hash_match = (memcmp(l_candidate_hash_cur, l_candidate_hash,
-															sizeof(dap_chain_hash_fast_t)) == 0);
-
-    		uint8_t l_chain_msg_type = l_chain_message->message->hdr.type;
-
-    		// search & check messages from this validator 
-    		switch (l_chain_msg_type) {
-    			// check dup messages APPROVE, REJECT for one candidate
-    			case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE:
-    			case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT: {
-    				switch (l_message->hdr.type) {
-    					case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE:
-    					case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT:
-	    					if (l_candidate_hash_match) {
-								if (PVT(l_session->ton)->debug)
+        if (l_chain_message->message->hdr.sender_node_addr.uint64 == a_sender_node_addr->uint64) {
+            dap_chain_hash_fast_t *l_candidate_hash_cur =
+                    &((dap_chain_cs_block_ton_message_getinfo_t *)
+                            (l_message->sign_n_message+l_message->hdr.sign_size))->candidate_hash;
+
+            dap_chain_hash_fast_t *l_candidate_hash =
+                &((dap_chain_cs_block_ton_message_getinfo_t *)
+                    (l_chain_message->message->sign_n_message+l_chain_message->message->hdr.sign_size))->candidate_hash;
+
+            bool l_candidate_hash_match = (memcmp(l_candidate_hash_cur, l_candidate_hash,
+                                                            sizeof(dap_chain_hash_fast_t)) == 0);
+
+            uint8_t l_chain_msg_type = l_chain_message->message->hdr.type;
+
+            // search & check messages from this validator
+            switch (l_chain_msg_type) {
+                // check dup messages APPROVE, REJECT for one candidate
+                case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE:
+                case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT: {
+                    switch (l_message->hdr.type) {
+                        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE:
+                        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT:
+                            if (l_candidate_hash_match) {
+                                if (PVT(l_session->ton)->debug)
                                     log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: duplicate messages APPROVE or REJECT for one candidate",
-											l_session->chain->net_name, l_session->chain->name, 
+                                            l_session->chain->net_name, l_session->chain->name,
                                                 l_session->cur_round.id.uint64, l_session->attempt_current_number);
-								goto handler_finish;
-							}
-    				}
-    			} break;
-    			//check dup messages VOTE for one candidate in this attempt
-    			case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE: {
-    				dap_chain_cs_block_ton_message_vote_t *l_vote = 
-    								(dap_chain_cs_block_ton_message_vote_t *)
-    									(l_message->sign_n_message+l_message->hdr.sign_size);
-    				dap_chain_cs_block_ton_message_vote_t *l_vote_item = 
-    								(dap_chain_cs_block_ton_message_vote_t *)
-    									(l_chain_message->message->sign_n_message+l_chain_message->message->hdr.sign_size);
-    				if ( l_chain_msg_type == l_message->hdr.type
-    						&& l_vote->attempt_number == l_vote_item->attempt_number ) {
-						if (PVT(l_session->ton)->debug)
+                                goto handler_finish;
+                            }
+                    }
+                } break;
+                //check dup messages VOTE for one candidate in this attempt
+                case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE: {
+                    dap_chain_cs_block_ton_message_vote_t *l_vote =
+                                    (dap_chain_cs_block_ton_message_vote_t *)
+                                        (l_message->sign_n_message+l_message->hdr.sign_size);
+                    dap_chain_cs_block_ton_message_vote_t *l_vote_item =
+                                    (dap_chain_cs_block_ton_message_vote_t *)
+                                        (l_chain_message->message->sign_n_message+l_chain_message->message->hdr.sign_size);
+                    if ( l_chain_msg_type == l_message->hdr.type
+                            && l_vote->attempt_number == l_vote_item->attempt_number ) {
+                        if (PVT(l_session->ton)->debug)
                             log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: duplicate messages VOTE for one candidate for one attempt",
-									l_session->chain->net_name, l_session->chain->name,
+                                    l_session->chain->net_name, l_session->chain->name,
                                         l_session->cur_round.id.uint64, l_session->attempt_current_number);
-    					goto handler_finish;
-    				}
-    			} break;
-    			// this messages should only appear once per round //attempt
-    			// case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE:
-    			case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT:
-    			case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN: 
-    			case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT:{
-    				if ( l_chain_msg_type == l_message->hdr.type ){
-						if (PVT(l_session->ton)->debug)
+                        goto handler_finish;
+                    }
+                } break;
+                // this messages should only appear once per round //attempt
+                // case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE:
+                case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT:
+                case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN:
+                case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT:{
+                    if ( l_chain_msg_type == l_message->hdr.type ){
+                        if (PVT(l_session->ton)->debug)
                             log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: duplicate messages VOTE or PRE_COMMIT for one candidate for one attempt",
-									l_session->chain->net_name, l_session->chain->name,
+                                    l_session->chain->net_name, l_session->chain->name,
                                         l_session->cur_round.id.uint64, l_session->attempt_current_number);
-    					goto handler_finish;
-    				}
-    			}
-    		}
-    		// count messages in chain for this candidate
-    		if (l_candidate_hash_match) {
-	    		switch (l_chain_msg_type) {
-	    			// case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE: {
-	    			// 	l_approve_count++;
-	    			// } break;
-	    			case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE: {
-	    				l_vote_count++;
-	    			} break;
-	    			case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT: {
-	    				l_precommit_count++;
-	    			} break;
-	    		}
-	    	}
-    	}
+                        goto handler_finish;
+                    }
+                }
+            }
+            // count messages in chain for this candidate
+            if (l_candidate_hash_match) {
+                switch (l_chain_msg_type) {
+                    // case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE: {
+                    // 	l_approve_count++;
+                    // } break;
+                    case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE: {
+                        l_vote_count++;
+                    } break;
+                    case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT: {
+                        l_precommit_count++;
+                    } break;
+                }
+            }
+        }
     }
 
-	// check message chain is correct
-	switch (l_message->hdr.type) {
-		// case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE: {
-		// 	if (!l_approve_count) { // if this validator not sent Approve for this candidate
-		// 		goto handler_finish;
-		// 	}
-		// } break;
-		case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT: {
-			if (!l_vote_count) { // if this validator not sent Vote for this candidate
-				if (PVT(l_session->ton)->debug)
+    // check message chain is correct
+    switch (l_message->hdr.type) {
+        // case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE: {
+        // 	if (!l_approve_count) { // if this validator not sent Approve for this candidate
+        // 		goto handler_finish;
+        // 	}
+        // } break;
+        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT: {
+            if (!l_vote_count) { // if this validator not sent Vote for this candidate
+                if (PVT(l_session->ton)->debug)
                     log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: this validator can't send a PRE_COMMIT because it didn't send a VOTE for this candidate",
-							l_session->chain->net_name, l_session->chain->name,
+                            l_session->chain->net_name, l_session->chain->name,
                                 l_session->cur_round.id.uint64, l_session->attempt_current_number);
-    			goto handler_finish;
-    		}
-		} break;
-		case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN: {
-			if (!l_precommit_count) { // if this validator not sent PreCommit for this candidate
-				if (PVT(l_session->ton)->debug)
+                goto handler_finish;
+            }
+        } break;
+        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN: {
+            if (!l_precommit_count) { // if this validator not sent PreCommit for this candidate
+                if (PVT(l_session->ton)->debug)
                     log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: this validator can't send a COMMIT_SIGN because it didn't send a PRE_COMMIT for this candidate",
-							l_session->chain->net_name, l_session->chain->name,
-								l_session->cur_round.id.uint64, l_session->attempt_current_number);
-    			goto handler_finish;
-    		}
-		} break;
-	}
-
-	bool l_finalize_consensus = false;
-	switch (l_message->hdr.type) {
-		case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT: {
+                            l_session->chain->net_name, l_session->chain->name,
+                                l_session->cur_round.id.uint64, l_session->attempt_current_number);
+                goto handler_finish;
+            }
+        } break;
+    }
+
+    switch (l_message->hdr.type) {
+        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT: {
             if( sizeof(dap_chain_cs_block_ton_message_submit_t) > l_message_data_size){
                 log_it(L_WARNING, "Wrong submit message size,have %zu bytes for data section when only a header requires %zu bytes",
                        l_message_data_size,sizeof(dap_chain_cs_block_ton_message_submit_t));
                 goto handler_finish;
             }
             dap_chain_cs_block_ton_message_submit_t *l_submit = (dap_chain_cs_block_ton_message_submit_t *)l_message_data;
-
-			size_t l_candidate_size = l_submit->candidate_size;
+            size_t l_candidate_size = l_submit->candidate_size;
             if( l_message_data_size < l_candidate_size + sizeof(*l_submit) ){
                 log_it(L_WARNING, "Wrong submit message size %zu when maximum is %zu for received message", l_candidate_size,
                        l_message_data_size - sizeof(*l_submit));
                 goto handler_finish;
             }
-			if (!l_candidate_size || s_hash_is_null(&l_submit->candidate_hash)) { // null candidate - save chain and exit
-				if (PVT(l_session->ton)->debug)
+            if (!l_candidate_size || dap_hash_fast_is_blank(&l_submit->candidate_hash)) { // null candidate - save chain and exit
+
+                if (PVT(l_session->ton)->debug)
                     log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive SUBMIT: candidate: NULL",
-							l_session->chain->net_name, l_session->chain->name,
-								l_session->cur_round.id.uint64, l_session->attempt_current_number);
-				goto handler_finish_save;
-			}
+                            l_session->chain->net_name, l_session->chain->name,
+                                l_session->cur_round.id.uint64, l_session->attempt_current_number);
+                goto handler_finish_save;
+            }
 
-			dap_chain_hash_fast_t l_candidate_hash;
+            dap_chain_hash_fast_t l_candidate_hash;
             dap_hash_fast(l_submit->candidate, l_candidate_size, &l_candidate_hash);
-			
-			// check candidate hash
-			if (memcmp(&l_submit->candidate_hash, &l_candidate_hash,
-											sizeof(dap_chain_hash_fast_t)) != 0) {
-				goto handler_finish;				
-			}
+
+            // check candidate hash
+            if (memcmp(&l_submit->candidate_hash, &l_candidate_hash,
+                                            sizeof(dap_chain_hash_fast_t)) != 0) {
+                goto handler_finish;
+            }
             dap_chain_block_t *l_candidate = (dap_chain_block_t *) DAP_DUP_SIZE(l_submit->candidate, l_candidate_size);
 
-			char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(&l_candidate_hash);
-			if (PVT(l_session->ton)->debug)
+            char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(&l_candidate_hash);
+            if (PVT(l_session->ton)->debug)
                 log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive SUBMIT: candidate:%s, size:%zu",
-						l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-							l_session->attempt_current_number, l_candidate_hash_str, l_candidate_size);
+                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
+                            l_session->attempt_current_number, l_candidate_hash_str, l_candidate_size);
 
-			// check block exist in store
+            // check block exist in store
             //s_check_block_exist_in_store(,)
             struct proc_msg_type_submit * l_args = DAP_NEW_Z(struct proc_msg_type_submit);
             l_args->session = l_session;
@@ -2117,59 +1864,54 @@ static void s_session_packet_in(void *a_arg, dap_chain_node_addr_t *a_sender_nod
                 DAP_DELETE(l_args);
                 goto handler_finish;
             }
-		} break;
-		case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT: {
+        } break;
+        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT: {
             if  ( sizeof(dap_chain_cs_block_ton_message_reject_t) >l_message_data_size  ){
                 log_it(L_WARNING, "Wrong reject message size,have %zu bytes for data section when requires %zu bytes",
                        l_message_data_size,sizeof(dap_chain_cs_block_ton_message_reject_t));
                 goto handler_finish;
             }
             dap_chain_cs_block_ton_message_reject_t *l_reject = (dap_chain_cs_block_ton_message_reject_t *) l_message_data;
-
-
-			dap_chain_hash_fast_t *l_candidate_hash = &l_reject->candidate_hash;
+            dap_chain_hash_fast_t *l_candidate_hash = &l_reject->candidate_hash;
 
             pthread_rwlock_rdlock(&l_session->rwlock);
 
-			if ( s_hash_is_null(l_candidate_hash) ) {
-				if (PVT(l_session->ton)->debug)
+            if (dap_hash_fast_is_blank(l_candidate_hash)) {
+                if (PVT(l_session->ton)->debug)
                     log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive REJECT: NULL",
-							l_session->chain->net_name, l_session->chain->name,
-								l_session->cur_round.id.uint64, l_session->attempt_current_number);
+                            l_session->chain->net_name, l_session->chain->name,
+                                l_session->cur_round.id.uint64, l_session->attempt_current_number);
                 pthread_rwlock_unlock(&l_session->rwlock);
                 goto handler_finish_save;
-			}
-			char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+            }
+            char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
 
-			if (PVT(l_session->ton)->debug)
+            if (PVT(l_session->ton)->debug)
                 log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive REJECT: candidate:%s",
-						l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-							l_session->attempt_current_number, l_candidate_hash_str);
+                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
+                            l_session->attempt_current_number, l_candidate_hash_str);
+
 
-			
             pthread_rwlock_wrlock(&l_session->rwlock);
 
-            uint16_t l_reject_count = s_session_message_count(
-						l_session, DAP_TON$ROUND_CUR, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT,
-									l_candidate_hash, NULL);
-			l_reject_count++;
+            uint16_t l_reject_count = s_session_message_count(l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT,
+                                                              l_candidate_hash, NULL);
+            l_reject_count++;
             if (l_reject_count * 3 >= l_session->cur_round.validators_count * 2) {
                 dap_global_db_del_sync(l_session->gdb_group_store, l_candidate_hash_str);
-				dap_chain_hash_fast_t l_my_candidate_hash;
-				dap_hash_fast(l_session->my_candidate, l_session->my_candidate_size, &l_my_candidate_hash);
-				if (memcmp(&l_my_candidate_hash, l_candidate_hash,
-									sizeof(dap_chain_hash_fast_t)) == 0) {
-					s_session_my_candidate_delete(l_session);
-				}
-				if (PVT(l_session->ton)->debug)
+                dap_chain_hash_fast_t l_my_candidate_hash;
+                dap_hash_fast(l_session->my_candidate, l_session->my_candidate_size, &l_my_candidate_hash);
+                if (dap_hash_fast_compare(&l_my_candidate_hash, l_candidate_hash))
+                    s_session_my_candidate_delete(l_session);
+                if (PVT(l_session->ton)->debug)
                     log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Candidate:%s collected rejected more than 2/3 of the validators, so to removed this candidate",
                             l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                            	l_session->attempt_current_number, l_candidate_hash_str);
-			}
-			pthread_rwlock_unlock(&l_session->rwlock);
-			DAP_DELETE(l_candidate_hash_str);
-		} break;
-		case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE: {
+                                l_session->attempt_current_number, l_candidate_hash_str);
+            }
+            pthread_rwlock_unlock(&l_session->rwlock);
+            DAP_DELETE(l_candidate_hash_str);
+        } break;
+        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE: {
             if  ( sizeof(dap_chain_cs_block_ton_message_approve_t) >l_message_data_size  ){
                 log_it(L_WARNING, "Wrong approve message size,have %zu bytes for data section when requires %zu bytes",
                        l_message_data_size,sizeof(dap_chain_cs_block_ton_message_approve_t));
@@ -2185,39 +1927,39 @@ static void s_session_packet_in(void *a_arg, dap_chain_node_addr_t *a_sender_nod
                 goto handler_finish;
             }
 
-			dap_chain_hash_fast_t *l_candidate_hash = &l_approve->candidate_hash;
-			
-			if ( s_hash_is_null(l_candidate_hash) ) {
-				if (PVT(l_session->ton)->debug)
+            dap_chain_hash_fast_t *l_candidate_hash = &l_approve->candidate_hash;
+
+            if (dap_hash_fast_is_blank(l_candidate_hash)) {
+                if (PVT(l_session->ton)->debug)
                     log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive APPROVE: candidate: NULL",
-							l_session->chain->net_name, l_session->chain->name,
-								l_session->cur_round.id.uint64, l_session->attempt_current_number);
-				goto handler_finish_save;
-			}
-			char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+                            l_session->chain->net_name, l_session->chain->name,
+                                l_session->cur_round.id.uint64, l_session->attempt_current_number);
+                goto handler_finish_save;
+            }
+            char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
 
             pthread_rwlock_rdlock(&l_session->rwlock);
             if (PVT(l_session->ton)->debug)
                 log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive APPROVE: candidate:%s",
-						l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-							l_session->attempt_current_number, l_candidate_hash_str);
-
-			int l_sign_verified=0;
-			// check candidate hash sign
-			if ( (l_sign_verified=dap_sign_verify( (dap_sign_t*)l_approve->candidate_hash_sign, 
-													l_candidate_hash, sizeof(dap_chain_hash_fast_t))) == 1 ) {
-				l_message->hdr.is_verified=true;
-
-				if ( l_session->attempt_current_number == 1 ) { // if this first attempt then send Vote event
-					uint16_t l_approve_count = s_session_message_count(
-							l_session, DAP_TON$ROUND_CUR, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE,
-										l_candidate_hash, NULL);
-					l_approve_count++;
+                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
+                            l_session->attempt_current_number, l_candidate_hash_str);
+
+            int l_sign_verified=0;
+            // check candidate hash sign
+            if ( (l_sign_verified=dap_sign_verify( (dap_sign_t*)l_approve->candidate_hash_sign,
+                                                    l_candidate_hash, sizeof(dap_chain_hash_fast_t))) == 1 ) {
+                l_message->hdr.is_verified=true;
+
+                if ( l_session->attempt_current_number == 1 ) { // if this first attempt then send Vote event
+                    uint16_t l_approve_count = s_session_message_count(
+                            l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE,
+                                        l_candidate_hash, NULL);
+                    l_approve_count++;
                     if (l_approve_count * 3 >= l_session->cur_round.validators_count * 2) {
-						if (PVT(l_session->ton)->debug)
+                        if (PVT(l_session->ton)->debug)
                             log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U" attempt:%hu Candidate:%s collected approve more than 2/3 of the validators",
-									l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-										l_session->attempt_current_number, l_candidate_hash_str);
+                                    l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
+                                        l_session->attempt_current_number, l_candidate_hash_str);
 
                         struct proc_msg_type_approve * l_args = DAP_NEW_Z(struct proc_msg_type_approve);
                         l_args->session = l_session;
@@ -2235,13 +1977,13 @@ static void s_session_packet_in(void *a_arg, dap_chain_node_addr_t *a_sender_nod
                 }else{
                     DAP_DELETE(l_candidate_hash_str);
                 }
-			} else {
-				log_it(L_WARNING, "Candidate hash sign is incorrect: code %d", l_sign_verified);
+            } else {
+                log_it(L_WARNING, "Candidate hash sign is incorrect: code %d", l_sign_verified);
                 DAP_DELETE(l_candidate_hash_str);
             }
             pthread_rwlock_unlock(&l_session->rwlock);
         } break;
-		case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE_FOR: {
+        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE_FOR: {
             if  ( sizeof(dap_chain_cs_block_ton_message_votefor_t) >l_message_data_size  ){
                 log_it(L_WARNING, "Wrong vote_for message size,have %zu bytes for data section when requires %zu bytes",
                        l_message_data_size,sizeof(dap_chain_cs_block_ton_message_votefor_t));
@@ -2249,45 +1991,45 @@ static void s_session_packet_in(void *a_arg, dap_chain_node_addr_t *a_sender_nod
             }
 
             dap_chain_cs_block_ton_message_votefor_t *l_votefor = (dap_chain_cs_block_ton_message_votefor_t *) l_message_data;
-			dap_chain_hash_fast_t *l_candidate_hash = &l_votefor->candidate_hash;
+            dap_chain_hash_fast_t *l_candidate_hash = &l_votefor->candidate_hash;
 
             pthread_rwlock_rdlock(&l_session->rwlock);
 
-			uint16_t l_attempt_current = l_session->attempt_current_number;
-			if ( l_votefor->attempt_number != l_attempt_current) {
+            uint16_t l_attempt_current = l_session->attempt_current_number;
+            if ( l_votefor->attempt_number != l_attempt_current) {
                 pthread_rwlock_unlock(&l_session->rwlock);
-				goto handler_finish; // wrong attempt number in message
-			}
+                goto handler_finish; // wrong attempt number in message
+            }
 
-			if (PVT(l_session->ton)->debug) {
-				char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+            if (PVT(l_session->ton)->debug) {
+                char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
                 log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive VOTE_FOR: candidate:%s",
                         l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
                             l_session->attempt_current_number, l_candidate_hash_str);
-				DAP_DELETE(l_candidate_hash_str);
-			}
+                DAP_DELETE(l_candidate_hash_str);
+            }
 
-			if ( a_sender_node_addr->uint64 != l_session->attempt_coordinator->uint64 ) {
+            if ( a_sender_node_addr->uint64 != l_session->attempt_coordinator->uint64 ) {
                 pthread_rwlock_unlock(&l_session->rwlock);
                 goto handler_finish; // wrong coordinator addr
-			}
+            }
 
-			uint16_t l_votefor_count = s_session_message_count(
-						l_session, DAP_TON$ROUND_CUR, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE_FOR,
-									NULL, &l_attempt_current);
-			if ( l_votefor_count != 0 ) {
-				if (PVT(l_session->ton)->debug)
+            uint16_t l_votefor_count = s_session_message_count(
+                        l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE_FOR,
+                                    NULL, &l_attempt_current);
+            if ( l_votefor_count != 0 ) {
+                if (PVT(l_session->ton)->debug)
                     log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Ignored because it's not the first VOTE_FOR in this attempt",
-							l_session->chain->net_name, l_session->chain->name, 
-								l_session->cur_round.id.uint64, l_session->attempt_current_number);
+                            l_session->chain->net_name, l_session->chain->name,
+                                l_session->cur_round.id.uint64, l_session->attempt_current_number);
                 pthread_rwlock_unlock(&l_session->rwlock);
-				goto handler_finish;
-			}
+                goto handler_finish;
+            }
 
             struct vote_for_load_store_args * l_args = DAP_NEW_Z(struct vote_for_load_store_args);
             l_args->session = l_session;
-            memcpy(&l_args->candidate_hash, l_candidate_hash, sizeof(l_args->candidate_hash));
-			// search candidate with 2/3 vote
+            l_args->candidate_hash = *l_candidate_hash;
+            // search candidate with 2/3 vote
             if(dap_global_db_get_all(l_session->gdb_group_store, 0,
                                   s_session_packet_in_callback_vote_for_load_store,
                                   l_session) != 0 ){
@@ -2296,39 +2038,39 @@ static void s_session_packet_in(void *a_arg, dap_chain_node_addr_t *a_sender_nod
             }
             pthread_rwlock_unlock(&l_session->rwlock);
         } break;
-		case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE: {
+        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE: {
             if  ( sizeof(dap_chain_cs_block_ton_message_vote_t) >l_message_data_size  ){
                 log_it(L_WARNING, "Wrong vote message size,have %zu bytes for data section when requires %zu bytes",
                        l_message_data_size,sizeof(dap_chain_cs_block_ton_message_vote_t));
                 goto handler_finish;
             }
             dap_chain_cs_block_ton_message_vote_t *l_vote =	(dap_chain_cs_block_ton_message_vote_t *) l_message_data;
-			dap_chain_hash_fast_t *l_candidate_hash = &l_vote->candidate_hash;
-
-			if ( l_vote->attempt_number != l_session->attempt_current_number) {
-				goto handler_finish;
-			}
-			
-			if ( s_hash_is_null(l_candidate_hash) ) {
-				if (PVT(l_session->ton)->debug)
+            dap_chain_hash_fast_t *l_candidate_hash = &l_vote->candidate_hash;
+
+            if ( l_vote->attempt_number != l_session->attempt_current_number) {
+                goto handler_finish;
+            }
+
+            if (dap_hash_fast_is_blank(l_candidate_hash)) {
+                if (PVT(l_session->ton)->debug)
                     log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive VOTE: candidate: NULL",
-							l_session->chain->net_name, l_session->chain->name, 
-								l_session->cur_round.id.uint64, l_session->attempt_current_number);
-				goto handler_finish_save;
-			}
+                            l_session->chain->net_name, l_session->chain->name,
+                                l_session->cur_round.id.uint64, l_session->attempt_current_number);
+                goto handler_finish_save;
+            }
 
-			char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
-			if (PVT(l_session->ton)->debug)
+            char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+            if (PVT(l_session->ton)->debug)
                 log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive VOTE: candidate:%s",
-						l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-							l_session->attempt_current_number, l_candidate_hash_str);
-	
-			pthread_rwlock_rdlock(&l_session->rwlock);
-			uint16_t l_attempt_number = l_session->attempt_current_number;
-			uint16_t l_vote_count = s_session_message_count(
-						l_session, DAP_TON$ROUND_CUR, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE,
-									l_candidate_hash, &l_attempt_number);
-			l_vote_count++;
+                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
+                            l_session->attempt_current_number, l_candidate_hash_str);
+
+            pthread_rwlock_rdlock(&l_session->rwlock);
+            uint16_t l_attempt_number = l_session->attempt_current_number;
+            uint16_t l_vote_count = s_session_message_count(
+                        l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE,
+                                    l_candidate_hash, &l_attempt_number);
+            l_vote_count++;
             if (l_vote_count * 3 >= l_session->cur_round.validators_count * 2){
                 struct proc_msg_type_vote * l_args = DAP_NEW_Z(struct proc_msg_type_vote);
                 l_args->session = l_session;
@@ -2339,10 +2081,10 @@ static void s_session_packet_in(void *a_arg, dap_chain_node_addr_t *a_sender_nod
                     DAP_DELETE(l_candidate_hash_str);
                     DAP_DELETE(l_args);
                 }
-			}
-			pthread_rwlock_unlock(&l_session->rwlock);
-		} break;
-		case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT: {
+            }
+            pthread_rwlock_unlock(&l_session->rwlock);
+        } break;
+        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT: {
             if  ( sizeof(dap_chain_cs_block_ton_message_precommit_t) >l_message_data_size  ){
                 log_it(L_WARNING, "Wrong pre_commit message size,have %zu bytes for data section when requires %zu bytes",
                        l_message_data_size,sizeof(dap_chain_cs_block_ton_message_precommit_t));
@@ -2350,34 +2092,33 @@ static void s_session_packet_in(void *a_arg, dap_chain_node_addr_t *a_sender_nod
             }
 
             dap_chain_cs_block_ton_message_precommit_t *l_precommit = (dap_chain_cs_block_ton_message_precommit_t *) l_message_data;
-			dap_chain_hash_fast_t *l_candidate_hash = &l_precommit->candidate_hash;
+            dap_chain_hash_fast_t *l_candidate_hash = &l_precommit->candidate_hash;
 
-            pthread_rwlock_rdlock(&l_session->rwlock);
+            pthread_rwlock_wrlock(&l_session->rwlock);
 
-			if ( l_precommit->attempt_number != l_session->attempt_current_number) {
+            if ( l_precommit->attempt_number != l_session->attempt_current_number) {
                 pthread_rwlock_unlock(&l_session->rwlock);
-				goto handler_finish;
-			}
-			if ( s_hash_is_null(l_candidate_hash) ) {
-				if (PVT(l_session->ton)->debug)
+                goto handler_finish;
+            }
+            if (dap_hash_fast_is_blank(l_candidate_hash)) {
+                if (PVT(l_session->ton)->debug)
                     log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive PRE_COMMIT: candidate: NULL",
-							l_session->chain->net_name, l_session->chain->name,
-								l_session->cur_round.id.uint64, l_session->attempt_current_number);
+                            l_session->chain->net_name, l_session->chain->name,
+                                l_session->cur_round.id.uint64, l_session->attempt_current_number);
                 pthread_rwlock_unlock(&l_session->rwlock);
-				goto handler_finish_save;
-			}
+                goto handler_finish_save;
+            }
 
-			char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
-			if (PVT(l_session->ton)->debug)
+            char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+            if (PVT(l_session->ton)->debug)
                 log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive PRE_COMMIT: candidate:%s",
-						l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-							l_session->attempt_current_number, l_candidate_hash_str);
-
-			uint16_t l_attempt_number = l_session->attempt_current_number;
-			uint16_t l_precommit_count = s_session_message_count(
-						l_session, DAP_TON$ROUND_CUR, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT,
-									l_candidate_hash, &l_attempt_number);
-			l_precommit_count++;
+                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
+                            l_session->attempt_current_number, l_candidate_hash_str);
+
+            uint16_t l_attempt_number = l_session->attempt_current_number;
+            uint16_t l_precommit_count = s_session_message_count(l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT,
+                                                                 l_candidate_hash, &l_attempt_number);
+            l_precommit_count++;
             if ( 3* l_precommit_count >= 2*l_session->cur_round.validators_count  ) {
                 struct proc_msg_type_pre_commit * l_args = DAP_NEW_Z(struct proc_msg_type_pre_commit);
                 l_args->session = l_session;
@@ -2388,11 +2129,10 @@ static void s_session_packet_in(void *a_arg, dap_chain_node_addr_t *a_sender_nod
                     DAP_DELETE(l_candidate_hash_str);
                     DAP_DELETE(l_args);
                 }
-			}
+            }
             pthread_rwlock_unlock(&l_session->rwlock);
-
         } break;
-		case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN: {
+        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN: {
             if  ( sizeof(dap_chain_cs_block_ton_message_commitsign_t) >l_message_data_size  ){
                 log_it(L_WARNING, "Wrong commit_sign message size,have %zu bytes for data section when requires %zu bytes",
                        l_message_data_size,sizeof(dap_chain_cs_block_ton_message_commitsign_t));
@@ -2412,26 +2152,22 @@ static void s_session_packet_in(void *a_arg, dap_chain_node_addr_t *a_sender_nod
             }
 
             pthread_rwlock_rdlock(&l_session->rwlock);
-
-			dap_chain_cs_block_ton_round_t *l_round =
-						l_commitsign->round_id.uint64 == l_session->old_round.id.uint64 ?
-								&l_session->old_round : &l_session->cur_round;
-
-			if ( s_hash_is_null(l_candidate_hash) ) {
-				if (PVT(l_session->ton)->debug)
+            dap_chain_cs_block_ton_round_t *l_round = &l_session->cur_round;
+            if (dap_hash_fast_is_blank(l_candidate_hash)) {
+                if (PVT(l_session->ton)->debug)
                     log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive COMMIT_SIGN: candidate: NULL",
-							l_session->chain->net_name, l_session->chain->name,
-								l_round->id.uint64, l_session->attempt_current_number);
+                            l_session->chain->net_name, l_session->chain->name,
+                                l_round->id.uint64, l_session->attempt_current_number);
                 pthread_rwlock_unlock(&l_session->rwlock);
 
-				goto handler_finish_save;
-			}
+                goto handler_finish_save;
+            }
 
-			char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
-			if (PVT(l_session->ton)->debug)
+            char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+            if (PVT(l_session->ton)->debug)
                 log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive COMMIT_SIGN: candidate:%s",
-						l_session->chain->net_name, l_session->chain->name, l_round->id.uint64,
-							l_session->attempt_current_number, l_candidate_hash_str);
+                        l_session->chain->net_name, l_session->chain->name, l_round->id.uint64,
+                            l_session->attempt_current_number, l_candidate_hash_str);
 
             struct proc_msg_type_commit_sign * l_args = DAP_NEW_Z(struct proc_msg_type_commit_sign);
             l_args->session = l_session;
@@ -2454,111 +2190,106 @@ static void s_session_packet_in(void *a_arg, dap_chain_node_addr_t *a_sender_nod
             }
             pthread_rwlock_unlock(&l_session->rwlock);
 
-		} break;
-		default:
-			break;
-	}
+        } break;
+        default:
+            break;
+    }
 
 handler_finish_save:
-    s_session_packet_in_handler_finish_save(l_session, a_sender_node_addr,l_message, a_data_size, l_finalize_consensus);
+    if (l_session->state != DAP_STREAM_CH_CHAIN_SESSION_STATE_IDLE)
+        s_message_chain_add(l_session, a_sender_node_addr, l_message, a_data_size, NULL);
     return;
 handler_finish:
     DAP_DELETE(l_message);
 }
 
 static uint8_t *s_message_data_sign(dap_chain_cs_block_ton_session_t *a_session,
-						dap_chain_cs_block_ton_message_t *a_message, size_t *a_sign_size) {
-	size_t l_size[5] = {sizeof(a_message->hdr.id), sizeof(a_message->hdr.ts_created),
-						sizeof(a_message->hdr.type), sizeof(a_message->hdr.chain_id),
-						sizeof(a_message->hdr.sender_node_addr)};
-	size_t l_data_size = 0;
-	for(int i=0;i<5;i++) l_data_size+=l_size[i];
-    uint8_t *l_data = DAP_NEW_SIZE(uint8_t, l_data_size);	
-	size_t l_offset = 0;
-	memcpy(l_data+l_offset, &a_message->hdr.id, l_size[0]);
-	l_offset+=l_size[0];
-	memcpy(l_data+l_offset, &a_message->hdr.ts_created, l_size[1]);
-	l_offset+=l_size[1];
-	memcpy(l_data+l_offset, &a_message->hdr.type, l_size[2]);
-	l_offset+=l_size[2];
-	memcpy(l_data+l_offset, &a_message->hdr.chain_id, l_size[3]);
-	l_offset+=l_size[3];
-	memcpy(l_data+l_offset, &a_message->hdr.sender_node_addr, l_size[4]);
-	*a_sign_size = l_data_size;
-	return l_data;
+                                    dap_chain_cs_block_ton_message_t *a_message, size_t *a_sign_size)
+{
+    struct ton_msg_signing_data {
+        dap_chain_cs_block_ton_msg_id_t id;
+        dap_time_t ts_created;
+        uint8_t type;
+        dap_chain_id_t chain_id;
+        dap_chain_node_addr_t sender_node_addr;
+    } DAP_ALIGN_PACKED;
+
+    struct ton_msg_signing_data *l_data = DAP_NEW(struct ton_msg_signing_data);
+    l_data->id                  = a_message->hdr.id;
+    l_data->ts_created          = a_message->hdr.ts_created;
+    l_data->type                = a_message->hdr.type;
+    l_data->chain_id            = a_message->hdr.chain_id;
+    l_data->sender_node_addr    = a_message->hdr.sender_node_addr;
+    if (a_sign_size)
+        *a_sign_size = sizeof(l_data);
+    return (uint8_t *)l_data;
 }
 
+
 static void s_message_send(dap_chain_cs_block_ton_session_t *a_session, uint8_t a_message_type,
-									uint8_t *a_data, size_t a_data_size, dap_list_t *a_validators) {
-	dap_chain_net_t *l_net = dap_chain_net_by_id(a_session->chain->net_id);
-	size_t l_message_size = sizeof(dap_chain_cs_block_ton_message_hdr_t)+a_data_size;
-	dap_chain_cs_block_ton_message_t *l_message =
-						DAP_NEW_SIZE(dap_chain_cs_block_ton_message_t, l_message_size);
-	l_message->hdr.id.uint64 = (uint64_t)a_session->cur_round.messages_count;
-	l_message->hdr.chain_id.uint64 = a_session->chain->id.uint64;
-	l_message->hdr.ts_created = dap_time_now();
-	l_message->hdr.type = a_message_type;
+                                    uint8_t *a_data, size_t a_data_size, dap_list_t *a_validators)
+{
+    dap_chain_net_t *l_net = dap_chain_net_by_id(a_session->chain->net_id);
+    size_t l_message_size = sizeof(dap_chain_cs_block_ton_message_hdr_t)+a_data_size;
+    dap_chain_cs_block_ton_message_t *l_message =
+                        DAP_NEW_SIZE(dap_chain_cs_block_ton_message_t, l_message_size);
+    l_message->hdr.id.uint64 = (uint64_t)a_session->cur_round.messages_count;
+    l_message->hdr.chain_id.uint64 = a_session->chain->id.uint64;
+    l_message->hdr.ts_created = dap_time_now();
+    l_message->hdr.type = a_message_type;
     l_message->hdr.sender_node_addr = *dap_chain_net_get_cur_addr(l_net);
 
-	size_t l_sign_size = 0;
-	if ( !PVT(a_session->ton)->validators_list_by_stake ) { 
-		size_t l_data_size = sizeof(l_message->hdr.sender_node_addr);
-		uint8_t *l_data = s_message_data_sign(a_session, l_message, &l_data_size);
-	    dap_sign_t *l_sign = dap_sign_create(PVT(a_session->ton)->blocks_sign_key, l_data, l_data_size, 0);
-	    l_sign_size = dap_sign_get_size(l_sign);
-	    l_message_size += l_sign_size;
-	    l_message = DAP_REALLOC(l_message, l_message_size);
-	    memcpy(l_message->sign_n_message, l_sign, l_sign_size);
-	    DAP_DELETE(l_sign);
-	    DAP_DELETE(l_data);
-	}
-	l_message->hdr.sign_size = l_sign_size;
-	memcpy(l_message->sign_n_message+l_sign_size, a_data, a_data_size);
-	l_message->hdr.message_size = a_data_size;
-
-	dap_chain_hash_fast_t l_message_hash;
-	dap_hash_fast(l_message, l_message_size, &l_message_hash);
-
-	dap_stream_ch_chain_voting_message_write(l_net, a_validators, //a_session->cur_round.validators_start,
-												&l_message_hash, l_message, l_message_size);
+    size_t l_sign_size = 0;
+    if ( !PVT(a_session->ton)->validators_list_by_stake ) {
+        size_t l_data_size = sizeof(l_message->hdr.sender_node_addr);
+        uint8_t *l_data = s_message_data_sign(a_session, l_message, &l_data_size);
+        dap_sign_t *l_sign = dap_sign_create(PVT(a_session->ton)->blocks_sign_key, l_data, l_data_size, 0);
+        l_sign_size = dap_sign_get_size(l_sign);
+        l_message_size += l_sign_size;
+        l_message = DAP_REALLOC(l_message, l_message_size);
+        memcpy(l_message->sign_n_message, l_sign, l_sign_size);
+        DAP_DELETE(l_sign);
+        DAP_DELETE(l_data);
+    }
+    l_message->hdr.sign_size = l_sign_size;
+    memcpy(l_message->sign_n_message+l_sign_size, a_data, a_data_size);
+    l_message->hdr.message_size = a_data_size;
+
+    dap_chain_hash_fast_t l_message_hash;
+    dap_hash_fast(l_message, l_message_size, &l_message_hash);
+
+    dap_stream_ch_chain_voting_message_write(l_net, a_validators, //a_session->cur_round.validators_start,
+                                                &l_message_hash, l_message, l_message_size);
     DAP_DELETE(l_message);
 }
 
 
 static void s_message_chain_add(dap_chain_cs_block_ton_session_t *a_session, dap_chain_node_addr_t *a_sender_node_addr,
-									dap_chain_cs_block_ton_message_t *a_message,
-									size_t a_message_size, dap_chain_hash_fast_t *a_message_hash) {
-	
-    pthread_rwlock_wrlock(&a_session->rwlock);
-	dap_chain_cs_block_ton_message_t *l_message = a_message;
-
-	dap_chain_cs_block_ton_message_getinfo_t *l_getinfo =
-					(dap_chain_cs_block_ton_message_getinfo_t *)
-							(l_message->sign_n_message+l_message->hdr.sign_size);
-	dap_chain_cs_block_ton_round_t *l_round =
-				l_getinfo->round_id.uint64 == a_session->old_round.id.uint64 ?
-						&a_session->old_round : &a_session->cur_round;
+                                    dap_chain_cs_block_ton_message_t *a_message,
+                                    size_t a_message_size, dap_chain_hash_fast_t *a_message_hash) {
 
-	l_message->hdr.is_genesis = !l_round->last_message_hash ? true : false;
-	if (!l_message->hdr.is_genesis) {
-        l_message->hdr.prev_message_hash = *l_round->last_message_hash;
-	}
+    pthread_rwlock_wrlock(&a_session->rwlock);
+    dap_chain_cs_block_ton_message_t *l_message = a_message;
+    dap_chain_cs_block_ton_round_t *l_round = &a_session->cur_round;
+    l_message->hdr.is_genesis = dap_hash_fast_is_blank(&l_round->last_message_hash);
+    if (!l_message->hdr.is_genesis) {
+        l_message->hdr.prev_message_hash = l_round->last_message_hash;
+    }
 
-	dap_chain_hash_fast_t l_message_hash;
-	dap_hash_fast(a_message, a_message_size, &l_message_hash);
+    dap_chain_hash_fast_t l_message_hash;
+    dap_hash_fast(a_message, a_message_size, &l_message_hash);
 
-	dap_chain_cs_block_ton_message_item_t *l_message_items = DAP_NEW_Z(dap_chain_cs_block_ton_message_item_t);
-	l_message_items->message = l_message;
+    dap_chain_cs_block_ton_message_item_t *l_message_items = DAP_NEW_Z(dap_chain_cs_block_ton_message_item_t);
+    l_message_items->message = l_message;
 
-	memcpy( &l_message_items->message_hash, &l_message_hash, sizeof(dap_chain_hash_fast_t));
-	l_round->last_message_hash = 
-			(dap_chain_hash_fast_t*)DAP_DUP_SIZE(&l_message_hash, sizeof(dap_chain_hash_fast_t));
-	HASH_ADD(hh, l_round->messages_items, message_hash, sizeof(l_message_items->message_hash), l_message_items);
+    l_round->last_message_hash = l_message_items->message_hash = l_message_hash;
+    HASH_ADD(hh, l_round->messages_items, message_hash, sizeof(l_message_items->message_hash), l_message_items);
 
-	l_round->messages_count++;
-	memcpy( a_message_hash, &l_message_hash, sizeof(dap_chain_hash_fast_t));
+    l_round->messages_count++;
+    if (a_message_hash)
+        *a_message_hash = l_message_hash;
 
-	pthread_rwlock_unlock(&a_session->rwlock);
+    pthread_rwlock_unlock(&a_session->rwlock);
 }
 
 static size_t s_callback_block_sign(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_t **a_block_ptr, size_t a_block_size)
@@ -2590,53 +2321,53 @@ static int s_callback_block_verify(dap_chain_cs_blocks_t *a_blocks, dap_chain_bl
         return  -7;
     }
 
-    if ( l_ton_pvt->flag_sign_verify && !l_ton_pvt->validators_list_by_stake ) { // PoA mode		
-		size_t l_offset = dap_chain_block_get_sign_offset(a_block, a_block_size);
-		size_t l_signs_count = 0;
-		dap_sign_t **l_signs = dap_sign_get_unique_signs(a_block->meta_n_datum_n_sign+l_offset,
-												a_block_size-sizeof(a_block->hdr)-l_offset, &l_signs_count);
-		if (!l_signs_count){
-	        log_it(L_ERROR, "No any signatures at all for block");
-	        DAP_DELETE(l_signs);
-	        return -2;
-	    }
-
-	    if ( ((float)l_signs_count/l_ton_pvt->poa_validators_count ) < ((float)2/3) ) {
+    if ( l_ton_pvt->flag_sign_verify && !l_ton_pvt->validators_list_by_stake ) { // PoA mode
+        size_t l_offset = dap_chain_block_get_sign_offset(a_block, a_block_size);
+        size_t l_signs_count = 0;
+        dap_sign_t **l_signs = dap_sign_get_unique_signs(a_block->meta_n_datum_n_sign+l_offset,
+                                                a_block_size-sizeof(a_block->hdr)-l_offset, &l_signs_count);
+        if (!l_signs_count){
+            log_it(L_ERROR, "No any signatures at all for block");
+            DAP_DELETE(l_signs);
+            return -2;
+        }
+
+        if (l_signs_count * 3  < l_ton_pvt->poa_validators_count * 2) {
             log_it(L_ERROR, "Corrupted block: not enough signs: %zu of %hu", l_signs_count, l_ton_pvt->poa_validators_count);
-	        DAP_DELETE(l_signs);
-	    	return -1;
-	    }
-
-	    // Parse the rest signs
-	    int l_ret = 0;
-	    uint16_t l_signs_verified_count = 0;
-	    size_t l_block_excl_sign_size = dap_chain_block_get_sign_offset(a_block, a_block_size)+sizeof(a_block->hdr);
-	    for (size_t i=0; i<l_signs_count; i++) {
-	    	dap_sign_t *l_sign = (dap_sign_t *)l_signs[i];
-	        if (!dap_sign_verify_size(l_sign, a_block_size)) {
-	            log_it(L_ERROR, "Corrupted block: sign size is bigger than block size");
-	            l_ret = -3;
-	            break;
-	        }
-
-	        // Compare signature with auth_certs
-	        for (uint16_t j = 0; j < l_ton_pvt->auth_certs_count; j++) {
-	            if (dap_cert_compare_with_sign( l_ton_pvt->auth_certs[j], l_sign) == 0
-	            		&& dap_sign_verify(l_sign, a_block, l_block_excl_sign_size) == 1 ){
-	                l_signs_verified_count++;
-	                break;
-	            }
-	        }
-	    }
-		DAP_DELETE(l_signs);
-	    if ( l_ret != 0 ) {
-	    	return l_ret;
-	    }
-	    if ( ((float)l_signs_verified_count/l_ton_pvt->poa_validators_count ) < ((float)2/3) ) {
-	        log_it(L_ERROR, "Corrupted block: not enough signs: %u of %u", l_signs_verified_count, l_ton_pvt->poa_validators_count);
-	    	return -1;
-	    }
-	}
+            DAP_DELETE(l_signs);
+            return -1;
+        }
+
+        // Parse the rest signs
+        int l_ret = 0;
+        uint16_t l_signs_verified_count = 0;
+        size_t l_block_excl_sign_size = dap_chain_block_get_sign_offset(a_block, a_block_size)+sizeof(a_block->hdr);
+        for (size_t i=0; i<l_signs_count; i++) {
+            dap_sign_t *l_sign = (dap_sign_t *)l_signs[i];
+            if (!dap_sign_verify_size(l_sign, a_block_size - l_block_excl_sign_size + sizeof(a_block->hdr))) {
+                log_it(L_ERROR, "Corrupted block: sign size is bigger than block size");
+                l_ret = -3;
+                break;
+            }
+
+            // Compare signature with auth_certs
+            for (uint16_t j = 0; j < l_ton_pvt->auth_certs_count; j++) {
+                if (dap_cert_compare_with_sign( l_ton_pvt->auth_certs[j], l_sign) == 0
+                        && dap_sign_verify(l_sign, a_block, l_block_excl_sign_size) == 1 ){
+                    l_signs_verified_count++;
+                    break;
+                }
+            }
+        }
+        DAP_DELETE(l_signs);
+        if ( l_ret != 0 ) {
+            return l_ret;
+        }
+        if (l_signs_verified_count * 3 < l_ton_pvt->poa_validators_count * 2) {
+            log_it(L_ERROR, "Corrupted block: not enough signs: %u of %u", l_signs_verified_count, l_ton_pvt->poa_validators_count);
+            return -1;
+        }
+    }
     return 0;
 }
 
diff --git a/modules/consensus/block-ton/include/dap_chain_cs_block_ton.h b/modules/consensus/block-ton/include/dap_chain_cs_block_ton.h
index c4a7f3a0d9856c9403f6061a870be6cbbba82ed7..686413fdad11a5b79c4d263a376b9993a77feeef 100644
--- a/modules/consensus/block-ton/include/dap_chain_cs_block_ton.h
+++ b/modules/consensus/block-ton/include/dap_chain_cs_block_ton.h
@@ -23,11 +23,6 @@
 #define DAP_CHAIN_BLOCKS_SESSION_ROUND_ID_SIZE		8
 #define DAP_CHAIN_BLOCKS_SESSION_MESSAGE_ID_SIZE	8
 
-enum    {
-    DAP_TON$ROUND_CUR  = 'c',
-    DAP_TON$ROUND_OLD  = 'o',
-};
-
 typedef struct dap_chain_cs_block_ton_message dap_chain_cs_block_ton_message_t;
 typedef struct dap_chain_cs_block_ton_message_item dap_chain_cs_block_ton_message_item_t;
 
@@ -43,76 +38,71 @@ typedef union dap_chain_cs_block_ton_round_id {
     uint64_t uint64;
 } DAP_ALIGN_PACKED dap_chain_cs_block_ton_round_id_t;
 
+typedef union dap_chain_cs_block_ton_msg_id {
+    uint8_t raw[DAP_CHAIN_BLOCKS_SESSION_MESSAGE_ID_SIZE];
+    uint64_t uint64;
+} DAP_ALIGN_PACKED dap_chain_cs_block_ton_msg_id_t;
+
 typedef struct dap_chain_cs_block_ton_round {
-	dap_chain_cs_block_ton_round_id_t id;
-	dap_list_t *validators_start; // dap_chain_node_addr_t
-	uint16_t validators_start_count;
-	dap_chain_hash_fast_t *last_message_hash;
-	dap_chain_cs_block_ton_message_item_t *messages_items;
-	bool submit;
-	uint16_t messages_count;
-	dap_chain_hash_fast_t *my_candidate_hash;
-	dap_list_t *validators_list; // dap_chain_node_addr_t 
-	uint16_t validators_count;
-	uint16_t candidates_count;
+    dap_chain_cs_block_ton_round_id_t id;
+    dap_list_t *validators_start; // dap_chain_node_addr_t
+    uint16_t validators_start_count;
+    dap_chain_hash_fast_t last_message_hash;
+    dap_chain_cs_block_ton_message_item_t *messages_items;
+    bool submit;
+    uint16_t messages_count;
+    dap_chain_hash_fast_t my_candidate_hash;
+    dap_list_t *validators_list; // dap_chain_node_addr_t
+    uint16_t validators_count;
+    uint16_t candidates_count;
 } dap_chain_cs_block_ton_round_t;
 
 typedef struct dap_chain_cs_block_ton_session {
-	dap_chain_t *chain;
-	dap_chain_cs_block_ton_t *ton;
+    dap_chain_t *chain;
+    dap_chain_cs_block_ton_t *ton;
 
-	dap_chain_node_addr_t *my_addr;
+    dap_chain_node_addr_t *my_addr;
 
     dap_chain_block_t *my_candidate;
     size_t my_candidate_size;
-   	uint16_t my_candidate_attempts_count;
+    uint16_t my_candidate_attempts_count;
+
+    uint8_t state; // session state
+    dap_chain_cs_block_ton_round_t cur_round;
 
-	uint8_t state; // session state
-	dap_chain_cs_block_ton_round_t cur_round;
-	dap_chain_cs_block_ton_round_t old_round; 
-	
-	dap_chain_node_addr_t *attempt_coordinator; // validator-coordinator in current attempt
-	uint16_t attempt_current_number;
+    dap_chain_node_addr_t *attempt_coordinator; // validator-coordinator in current attempt
+    uint16_t attempt_current_number;
 
-	dap_time_t ts_round_sync_start; // time start sync
-	dap_time_t ts_round_start; // time round-start
-	dap_time_t ts_round_state_commit;
-	dap_time_t ts_round_finish;
+    dap_time_t ts_round_sync_start; // time start sync
+    dap_time_t ts_round_start; // time round-start
+    dap_time_t ts_round_state_commit;
+    dap_time_t ts_round_finish;
 
-	char * gdb_group_setup;
-	char * gdb_group_store;
-	char * gdb_group_message;
+    char * gdb_group_setup;
+    char * gdb_group_store;
+    char * gdb_group_message;
 
-	dap_enc_key_t *blocks_sign_key;
+    dap_enc_key_t *blocks_sign_key;
 
     struct dap_chain_cs_block_ton_session *next;
     struct dap_chain_cs_block_ton_session *prev;
 
-	bool time_proc_lock; // flag - skip check if prev check is not finish
+    bool time_proc_lock; // flag - skip check if prev check is not finish
 
     dap_worker_t * worker; // Worker where it was processed last time
     pthread_rwlock_t rwlock;
 } dap_chain_cs_block_ton_session_t;
 
 typedef struct dap_chain_cs_block_ton_message_hdr {
-	uint8_t type;
-
-	union {
-		uint8_t raw[DAP_CHAIN_BLOCKS_SESSION_MESSAGE_ID_SIZE];
-    	uint64_t uint64;
-	} DAP_ALIGN_PACKED id;
-
-	size_t sign_size;
-	size_t message_size;
-
-	dap_time_t ts_created;
-	//dap_chain_cs_block_ton_round_id_t round_id;
-
-	dap_chain_node_addr_t sender_node_addr;
-
-	bool is_genesis;
-	bool is_verified;
-	dap_chain_hash_fast_t prev_message_hash; 
+    uint8_t type;
+    dap_chain_cs_block_ton_msg_id_t id;
+    uint64_t sign_size;
+    uint64_t message_size;
+    dap_time_t ts_created;
+    dap_chain_node_addr_t sender_node_addr;
+    uint16_t  is_genesis;
+    uint16_t  is_verified;
+    dap_chain_hash_fast_t prev_message_hash;
     dap_chain_id_t chain_id;
 } DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_hdr_t;
 
@@ -129,15 +119,15 @@ typedef struct dap_chain_cs_block_ton_message_item {
 
 // struct for get info from any messages
 typedef struct dap_chain_cs_block_ton_message_getinfo {
-	dap_chain_hash_fast_t candidate_hash;
-	dap_chain_cs_block_ton_round_id_t round_id;
-	uint16_t attempt_number;
+    dap_chain_hash_fast_t candidate_hash;
+    dap_chain_cs_block_ton_round_id_t round_id;
+    uint16_t attempt_number;
 } DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_getinfo_t;
 
 // technical messages
 typedef struct dap_chain_cs_block_ton_message_startsync {
-	dap_time_t ts;
-	dap_chain_cs_block_ton_round_id_t round_id;
+    dap_time_t ts;
+    dap_chain_cs_block_ton_round_id_t round_id;
 } DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_startsync_t;
 
 /*
@@ -153,61 +143,61 @@ in this round (even if the current process has another opinion)
 */
 
 typedef struct dap_chain_cs_block_ton_message_submit {
-	dap_chain_hash_fast_t candidate_hash;
-	dap_chain_cs_block_ton_round_id_t round_id;
-	size_t candidate_size;
-	uint8_t candidate[];
+    dap_chain_hash_fast_t candidate_hash;
+    dap_chain_cs_block_ton_round_id_t round_id;
+    size_t candidate_size;
+    uint8_t candidate[];
 } DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_submit_t;
 
 typedef struct dap_chain_cs_block_ton_message_approve {
-	dap_chain_hash_fast_t candidate_hash;
-	dap_chain_cs_block_ton_round_id_t round_id;
-	uint8_t candidate_hash_sign[];
+    dap_chain_hash_fast_t candidate_hash;
+    dap_chain_cs_block_ton_round_id_t round_id;
+    uint8_t candidate_hash_sign[];
 } DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_approve_t;
 
 typedef struct dap_chain_cs_block_ton_message_reject {
-	dap_chain_hash_fast_t candidate_hash;
-	dap_chain_cs_block_ton_round_id_t round_id;
+    dap_chain_hash_fast_t candidate_hash;
+    dap_chain_cs_block_ton_round_id_t round_id;
 } DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_reject_t;
 
 typedef struct dap_chain_cs_block_ton_message_votefor {
-	dap_chain_hash_fast_t candidate_hash;
-	dap_chain_cs_block_ton_round_id_t round_id;
-	uint16_t attempt_number;
+    dap_chain_hash_fast_t candidate_hash;
+    dap_chain_cs_block_ton_round_id_t round_id;
+    uint16_t attempt_number;
 } DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_votefor_t;
 
 typedef struct dap_chain_cs_block_ton_message_vote {
-	dap_chain_hash_fast_t candidate_hash;
-	dap_chain_cs_block_ton_round_id_t round_id;
-	uint16_t attempt_number;
+    dap_chain_hash_fast_t candidate_hash;
+    dap_chain_cs_block_ton_round_id_t round_id;
+    uint16_t attempt_number;
 } DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_vote_t;
 
 typedef struct dap_chain_cs_block_ton_message_precommit {
-	dap_chain_hash_fast_t candidate_hash;
-	dap_chain_cs_block_ton_round_id_t round_id;
-	uint16_t attempt_number;
+    dap_chain_hash_fast_t candidate_hash;
+    dap_chain_cs_block_ton_round_id_t round_id;
+    uint16_t attempt_number;
 } DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_precommit_t;
 
 typedef struct dap_chain_cs_block_ton_message_commitsign {
-	dap_chain_hash_fast_t candidate_hash;
-	dap_chain_cs_block_ton_round_id_t round_id;
-	uint8_t candidate_sign[];
+    dap_chain_hash_fast_t candidate_hash;
+    dap_chain_cs_block_ton_round_id_t round_id;
+    uint8_t candidate_sign[];
 } DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_commitsign_t;
 
 typedef struct dap_chain_cs_block_ton_store_hdr {
-	bool sign_collected; // cellect 2/3 min 
-	bool approve_collected;
-	// bool reject_done;
-	bool vote_collected;
-	bool precommit_collected;
-	size_t candidate_size;
-	dap_chain_cs_block_ton_round_id_t round_id;
-	dap_chain_hash_fast_t candidate_hash;
-	dap_time_t ts_candidate_submit;
+    bool sign_collected; // collect 2/3 min
+    bool approve_collected;
+    // bool reject_done;
+    bool vote_collected;
+    bool precommit_collected;
+    size_t candidate_size;
+    dap_chain_cs_block_ton_round_id_t round_id;
+    dap_chain_hash_fast_t candidate_hash;
+    dap_time_t ts_candidate_submit;
 } DAP_ALIGN_PACKED dap_chain_cs_block_ton_store_hdr_t;
 
 typedef struct dap_chain_cs_block_ton_store {
-	dap_chain_cs_block_ton_store_hdr_t hdr;
+    dap_chain_cs_block_ton_store_hdr_t hdr;
     uint8_t candidate_n_signs[];
 } DAP_ALIGN_PACKED dap_chain_cs_block_ton_store_t;
 
diff --git a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
index fd64efc4f3fdab214e06139939751a6833bb4a56..986cd1ee38545ecac54fa71db3031c35cbae89fc 100644
--- a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
+++ b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
@@ -55,7 +55,7 @@
 #define LOG_TAG "dap_chain_cs_dag_poa"
 
 typedef struct dap_chain_cs_dag_poa_presign_callback{
-    dap_chain_cs_dag_poa_callback_t callback; 
+    dap_chain_cs_dag_poa_callback_t callback;
     void *arg;
 } dap_chain_cs_dag_poa_presign_callback_t;
 
@@ -100,7 +100,7 @@ static void s_round_event_cs_done(dap_chain_cs_dag_t * a_dag, uint64_t a_round_i
 static int s_cli_dag_poa(int argc, char ** argv, char **str_reply);
 
 static bool s_seed_mode = false;
-static dap_timerfd_t *s_poa_round_timer = NULL; 
+static dap_interval_timer_t s_poa_round_timer = NULL;
 
 /**
  * @brief
@@ -130,7 +130,7 @@ void dap_chain_cs_dag_poa_deinit(void)
 
 /*
 // example
-static int s_callback_presign_test(dap_chain_t *a_chain, 
+static int s_callback_presign_test(dap_chain_t *a_chain,
                     dap_chain_cs_dag_event_t* a_event, size_t a_event_size, void *a_arg) {
     dap_chain_hash_fast_t l_event_hash;
     dap_chain_cs_dag_event_calc_hash(a_event, a_event_size, &l_event_hash);
@@ -372,9 +372,7 @@ static int s_callback_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
         dap_chain_node_role_t l_role = dap_chain_net_get_role(l_net);
         if (l_role.enums == NODE_ROLE_ROOT_MASTER || l_role.enums == NODE_ROLE_ROOT) {
             if (!s_poa_round_timer) {
-                s_poa_round_timer = dap_interval_timer_create(10 * 1000,
-                                                              s_poa_round_clean,
-                                                              a_chain);
+                s_poa_round_timer = dap_interval_timer_create(10 * 1000, s_poa_round_clean, a_chain);
                 log_it(L_MSG, "DAG-PoA: Round timer is started");
             }
         }
@@ -791,7 +789,7 @@ static int s_callback_event_round_sync(dap_chain_cs_dag_t * a_dag, const char a_
  */
 static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_event_t * a_event, size_t a_event_size)
 {
-    
+
     dap_chain_cs_dag_poa_pvt_t * l_poa_pvt = PVT ( DAP_CHAIN_CS_DAG_POA( a_dag ) );
     size_t l_offset_from_beginning = dap_chain_cs_dag_event_calc_size_excl_signs(a_event, a_event_size);
     if( l_offset_from_beginning >= a_event_size){
@@ -822,7 +820,7 @@ static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_
         uint16_t l_event_signs_count = a_event->header.signs_count;
         for (size_t i=0; i<l_signs_count; i++) {
             dap_sign_t *l_sign = (dap_sign_t *)l_signs[i];
-            if (!dap_sign_verify_size(l_sign, a_event_size)) {
+            if (!dap_sign_verify_size(l_sign, a_event_size - l_offset_from_beginning)) {
                 log_it(L_WARNING,"Incorrect size with event %p", a_event);
                 l_ret = -3;
                 break;
diff --git a/modules/consensus/dag-pos/dap_chain_cs_dag_pos.c b/modules/consensus/dag-pos/dap_chain_cs_dag_pos.c
index 22312893f841d051ce10e0dfc4fccb3bf8d7918f..256a3219b1b42d8a7af0c94dd959ffa64487f53d 100644
--- a/modules/consensus/dag-pos/dap_chain_cs_dag_pos.c
+++ b/modules/consensus/dag-pos/dap_chain_cs_dag_pos.c
@@ -184,14 +184,14 @@ static void s_callback_delete(dap_chain_cs_dag_t * a_dag)
 }
 
 /**
- * @brief 
+ * @brief
  * create event
- * @param a_dag 
- * @param a_datum 
- * @param a_hashes 
- * @param a_hashes_count 
- * @param a_dag_event_size 
- * @return dap_chain_cs_dag_event_t* 
+ * @param a_dag
+ * @param a_datum
+ * @param a_hashes
+ * @param a_hashes_count
+ * @param a_dag_event_size
+ * @return dap_chain_cs_dag_event_t*
  */
 static dap_chain_cs_dag_event_t * s_callback_event_create(dap_chain_cs_dag_t * a_dag, dap_chain_datum_t * a_datum,
                                                           dap_chain_hash_fast_t * a_hashes, size_t a_hashes_count,
@@ -213,12 +213,12 @@ static dap_chain_cs_dag_event_t * s_callback_event_create(dap_chain_cs_dag_t * a
 }
 
 /**
- * @brief 
+ * @brief
  * function makes event singing verification
  * @param a_dag dag object
  * @param a_dag_event dap_chain_cs_dag_event_t
  * @param a_dag_event_size size_t size of event object
- * @return int 
+ * @return int
  */
 static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_event_t * a_dag_event, size_t a_dag_event_size)
 {
@@ -233,6 +233,7 @@ static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_
         log_it(L_WARNING,"Incorrect size with event %p on chain %s", a_dag_event, a_dag->chain->name);
         return  -7;
     }
+    size_t l_offset_signs = dap_chain_cs_dag_event_calc_size_excl_signs(a_dag_event, a_dag_event_size);
     if ( a_dag_event->header.signs_count >= l_pos_pvt->confirmations_minimum ){
         uint16_t l_verified_num = 0;
 
@@ -243,7 +244,7 @@ static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_
                 return -4;
             }
 
-            bool l_sign_size_correct = dap_sign_verify_size(l_sign, a_dag_event_size);
+            bool l_sign_size_correct = dap_sign_verify_size(l_sign, a_dag_event_size - l_offset_signs);
             if (!l_sign_size_correct) {
                 log_it(L_WARNING, "Event's sign size is incorrect");
                 return -41;
diff --git a/modules/consensus/none/dap_chain_cs_none.c b/modules/consensus/none/dap_chain_cs_none.c
index 030c1fea0ba503e6d624db2f76a76afd9880e9f9..c7c5e58d1f3bcdf8ce91bd0928630de0186a4dcc 100644
--- a/modules/consensus/none/dap_chain_cs_none.c
+++ b/modules/consensus/none/dap_chain_cs_none.c
@@ -25,11 +25,10 @@
 #include <stdlib.h>
 #include <stdbool.h>
 #include <pthread.h>
-
-#include "dap_chain.h"
 #include "utlist.h"
 
 #include "dap_chain_net.h"
+#include "dap_chain.h"
 #include "dap_common.h"
 #include "dap_strfuncs.h"
 #include "dap_config.h"
@@ -95,16 +94,13 @@ static dap_chain_datum_t **s_chain_callback_atom_get_datum(dap_chain_atom_ptr_t
 
 static size_t s_chain_callback_datums_pool_proc(dap_chain_t * a_chain, dap_chain_datum_t ** a_datums,
         size_t a_datums_size);
-static size_t s_chain_callback_datums_pool_proc_with_group(dap_chain_t * a_chain, dap_chain_datum_t ** a_datums,
-        size_t a_datums_size, const char *a_group);
-
 
 /**
  * @brief stub for consensus
- * 
+ *
  * @param a_chain chain object
  * @param a_chain_cfg chain config object
- * @return int 
+ * @return int
  */
 static int s_cs_callback_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
 {
@@ -150,7 +146,7 @@ static void s_history_callback_notify(void * a_arg, const char a_op_code, const
 
 /**
  * @brief set PVT(DAP_CHAIN_GDB(a_chain))->is_load_mode = true
- * 
+ *
  * @param a_chain dap_chain_t object
  */
 static void s_dap_chain_gdb_callback_purge(dap_chain_t *a_chain)
@@ -162,8 +158,8 @@ static void s_dap_chain_gdb_callback_purge(dap_chain_t *a_chain)
  * @brief configure chain gdb
  * Set atom element callbacks
  * @param a_chain dap_chain_t chain object
- * @param a_chain_cfg dap_config_t config object 
- * @return int 
+ * @param a_chain_cfg dap_config_t config object
+ * @return int
  */
 int dap_chain_gdb_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
 {
@@ -211,7 +207,6 @@ int dap_chain_gdb_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
 
     a_chain->callback_atom_find_by_hash = s_chain_callback_atom_iter_find_by_hash;
     a_chain->callback_add_datums = s_chain_callback_datums_pool_proc;
-    a_chain->callback_add_datums_with_group = s_chain_callback_datums_pool_proc_with_group;
 
     // Linear pass through
     a_chain->callback_atom_iter_get_first = s_chain_callback_atom_iter_get_first; // Get the fisrt element from chain
@@ -226,7 +221,7 @@ int dap_chain_gdb_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
 
 /**
  * @brief clear dap_chain_gdb_t object
- * 
+ *
  * @param a_chain dap_chain_t chain object
  */
 void dap_chain_gdb_delete(dap_chain_t * a_chain)
@@ -242,7 +237,7 @@ void dap_chain_gdb_delete(dap_chain_t * a_chain)
 
 /**
  * @brief get group name for ledger
- * 
+ *
  * @param a_chain dap_chain_t * chain object
  * @return const char*
  */
@@ -310,7 +305,7 @@ static bool s_ledger_load_callback(dap_global_db_context_t * a_global_db_context
 
 /**
  * @brief Load ledger from mempool
- * 
+ *
  * @param a_gdb_group a_gdb_group char gdb group name
  * @param a_chain chain dap_chain_t object
  * @return int return 0 if OK otherwise  negative error code
@@ -331,11 +326,11 @@ int dap_chain_gdb_ledger_load(char *a_gdb_group, dap_chain_t *a_chain)
 
 /**
  * @brief call s_chain_callback_atom_add for every dap_chain_datum_t objects in a_datums array
- * 
+ *
  * @param a_chain dap_chain_t chain object (f.e. plasma)
  * @param a_datums dap_chain_datum array with dap_chain_datum objects
  * @param a_datums_count object counts in datums array
- * @return size_t 
+ * @return size_t
  */
 static size_t s_chain_callback_datums_pool_proc(dap_chain_t * a_chain, dap_chain_datum_t ** a_datums,
         size_t a_datums_count)
@@ -347,37 +342,20 @@ static size_t s_chain_callback_datums_pool_proc(dap_chain_t * a_chain, dap_chain
     return a_datums_count;
 }
 
-/**
- * @brief call s_chain_callback_atom_add for every dap_chain_datum_t objects in a_datums array only if chain contains specific group (chain-gdb.home21-network.chain-F)
- * 
- * @param a_chain dap_chain_t chain object (f.e. plasma)
- * @param a_datums dap_chain_datum array with dap_chain_datum objects
- * @param a_datums_count object counts in datums array
- * @param a_group group name
- * @return size_t 
- */
-static size_t s_chain_callback_datums_pool_proc_with_group(dap_chain_t * a_chain, dap_chain_datum_t ** a_datums,
-        size_t a_datums_count, const char *a_group)
-{
-    if(dap_strcmp(dap_chain_gdb_get_group(a_chain), a_group))
-        return 0;
-    return s_chain_callback_datums_pool_proc(a_chain, a_datums, a_datums_count);
-}
-
 /**
  * @brief add atom to DB
- * 
+ *
  * @param a_chain chaon object
  * @param a_atom pointer to atom
  * @param a_atom_size atom size
- * @return dap_chain_atom_verify_res_t 
+ * @return dap_chain_atom_verify_res_t
  */
 static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size)
 {
     dap_chain_gdb_t * l_gdb = DAP_CHAIN_GDB(a_chain);
     dap_chain_gdb_private_t *l_gdb_priv = PVT(l_gdb);
     dap_chain_datum_t *l_datum = (dap_chain_datum_t*) a_atom;
-    if(dap_chain_datum_add(a_chain, l_datum, a_atom_size))
+    if(dap_chain_datum_add(a_chain, l_datum, a_atom_size, NULL))
         return ATOM_REJECT;
 
     dap_chain_gdb_datum_hash_item_t * l_hash_item = DAP_NEW_Z(dap_chain_gdb_datum_hash_item_t);
@@ -388,19 +366,24 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
         dap_global_db_set(l_gdb_priv->group_datums, l_hash_item->key, l_datum, l_datum_size, false, NULL, NULL);
     } else
         log_it(L_DEBUG,"Load mode, doesn't save item %s:%s", l_hash_item->key, l_gdb_priv->group_datums);
-
     DL_APPEND(l_gdb_priv->hash_items, l_hash_item);
+    if (!l_gdb_priv->is_load_mode && a_chain->atom_notifiers) {
+        for(dap_list_t *l_iter = a_chain->atom_notifiers; l_iter; l_iter = dap_list_next(l_iter)) {
+            dap_chain_atom_notifier_t *i = (dap_chain_atom_notifier_t *)l_iter->data;
+            i->callback(i->arg, a_chain, (dap_chain_cell_id_t){}, (void *)l_datum, l_datum_size);
+        }
+    }
     return ATOM_ACCEPT;
 }
 
 
 /**
  * @brief Verify atomic element (currently simply return ATOM_ACCEPT)
- * 
+ *
  * @param a_chain chain object
  * @param a_atom pointer to atom
  * @param a_atom_size size of atom
- * @return dap_chain_atom_verify_res_t 
+ * @return dap_chain_atom_verify_res_t
  */
 static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size)
 {
@@ -413,8 +396,8 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_
 
 /**
  * @brief return size of dap_chain_datum_t l_datum_null->header
- * 
- * @return size_t 
+ *
+ * @return size_t
  */
 static size_t s_chain_callback_atom_get_static_hdr_size()
 {
@@ -425,9 +408,9 @@ static size_t s_chain_callback_atom_get_static_hdr_size()
 
 /**
  * @brief Create atomic element iterator
- * 
+ *
  * @param a_chain dap_chain_t a_chain
- * @return dap_chain_atom_iter_t* 
+ * @return dap_chain_atom_iter_t*
  */
 static dap_chain_atom_iter_t* s_chain_callback_atom_iter_create(dap_chain_t * a_chain, dap_chain_cell_id_t a_cell_id, bool a_with_treshold)
 {
@@ -569,11 +552,11 @@ static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_next(dap_chain_atom_i
 
 /**
  * @brief return null in current implementation
- * 
- * @param a_atom_iter 
- * @param a_links_size_ptr 
- * @param a_links_sizes_ptr 
- * @return dap_chain_atom_ptr_t* 
+ *
+ * @param a_atom_iter
+ * @param a_links_size_ptr
+ * @param a_links_sizes_ptr
+ * @return dap_chain_atom_ptr_t*
  */
 static dap_chain_atom_ptr_t* s_chain_callback_atom_iter_get_links(dap_chain_atom_iter_t * a_atom_iter,
         size_t * a_links_size_ptr, size_t **a_links_sizes_ptr)
@@ -586,11 +569,11 @@ static dap_chain_atom_ptr_t* s_chain_callback_atom_iter_get_links(dap_chain_atom
 
 /**
  * @brief return null in current implementation
- * 
- * @param a_atom_iter 
- * @param a_lasts_size_ptr 
- * @param a_links_sizes_ptr 
- * @return dap_chain_atom_ptr_t* 
+ *
+ * @param a_atom_iter
+ * @param a_lasts_size_ptr
+ * @param a_links_sizes_ptr
+ * @return dap_chain_atom_ptr_t*
  */
 static dap_chain_atom_ptr_t* s_chain_callback_atom_iter_get_lasts(dap_chain_atom_iter_t * a_atom_iter,
         size_t * a_lasts_size_ptr,  size_t **a_links_sizes_ptr)
@@ -603,11 +586,11 @@ static dap_chain_atom_ptr_t* s_chain_callback_atom_iter_get_lasts(dap_chain_atom
 
 /**
  * @brief get new datum object from atom
- * 
+ *
  * @param a_atom atom object
  * @param a_atom_size atom size
  * @param a_datums_count count of datums
- * @return dap_chain_datum_t** 
+ * @return dap_chain_datum_t**
  */
 static dap_chain_datum_t **s_chain_callback_atom_get_datum(dap_chain_atom_ptr_t a_atom, size_t a_atom_size, size_t *a_datums_count)
 {
diff --git a/modules/global-db/CMakeLists.txt b/modules/global-db/CMakeLists.txt
index f83f426e737cecd870ba2874312d999147d6399c..72c9868c179e09de233703989c4ae2ea855d6e84 100644
--- a/modules/global-db/CMakeLists.txt
+++ b/modules/global-db/CMakeLists.txt
@@ -21,7 +21,12 @@ file(GLOB DAP_CHAIN_GLOBAL_DB_HDR
     include/dap_chain_global_db_driver_sqlite.h
 )
 
-set(DAP_CHAIN_GLOBAL_DB_LIBS dap_core dap_crypto dap_chain sqlite3 dap_cuttdb json-c)
+add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/cuttdb ${CMAKE_CURRENT_BINARY_DIR}/../../3rdparty/cuttdb)
+if (BUILD_WITH_GDB_DRIVER_MDBX)
+add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/libmdbx ${CMAKE_CURRENT_BINARY_DIR}/../../3rdparty/libmdbx)
+endif()
+
+set(DAP_CHAIN_GLOBAL_DB_LIBS dap_core dap_io dap_crypto dap_chain dap_chain_net sqlite3 dap_cuttdb json-c)
 
 if(BUILD_WITH_GDB_DRIVER_MDBX)
     file(GLOB DAP_CHAIN_GLOBAL_DB_SRC ${DAP_CHAIN_GLOBAL_DB_SRC} dap_chain_global_db_driver_mdbx.c)
@@ -38,7 +43,7 @@ endif()
 
 add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_GLOBAL_DB_SRC} ${DAP_CHAIN_GLOBAL_DB_HDR})
 
-target_link_libraries(${PROJECT_NAME}  ${DAP_CHAIN_GLOBAL_DB_LIBS})
+target_link_libraries(${PROJECT_NAME} ${DAP_CHAIN_GLOBAL_DB_LIBS})
 
 target_include_directories(${PROJECT_NAME} INTERFACE .)
 target_include_directories(${PROJECT_NAME} PUBLIC include)
diff --git a/modules/global-db/dap_chain_global_db_driver_mdbx.c b/modules/global-db/dap_chain_global_db_driver_mdbx.c
index 8da7cc0b255febdb487393a2dc6f8f43610a5e0a..e307141db085afc17ce151622881b99f9954e1ed 100644
--- a/modules/global-db/dap_chain_global_db_driver_mdbx.c
+++ b/modules/global-db/dap_chain_global_db_driver_mdbx.c
@@ -821,12 +821,13 @@ size_t  l_cnt = 0, l_count_out = 0;
 
             l_obj_arr = l_obj;
             l_obj = l_obj_arr + (l_cnt - 1);                                /* Point <l_obj> to last array's element */
+            memset(l_obj, 0, sizeof(dap_store_obj_t));
 
             if ( !(l_obj->key = DAP_CALLOC(1, l_key.iov_len + 1)) )
                 l_rc = MDBX_PROBLEM, log_it (L_ERROR, "Cannot allocate a memory for store object key, errno=%d", errno);
 
             else if ( (l_obj->value = DAP_CALLOC(1, (l_data.iov_len + 1)  - sizeof(struct __record_suffix__))) )
-                {
+            {
                 /* Fill the <store obj> by data from the retreived record */
                 l_obj->key_len = l_key.iov_len;
                 memcpy((char *) l_obj->key, l_key.iov_base, l_obj->key_len);
@@ -834,14 +835,13 @@ size_t  l_cnt = 0, l_count_out = 0;
                 l_obj->value_len = l_data.iov_len - sizeof(struct __record_suffix__);
                 memcpy(l_obj->value, l_data.iov_base, l_obj->value_len);
 
-
                 l_obj->id = l_suff->id;
                 l_obj->timestamp = l_suff->ts;
                 l_obj->flags = l_suff->flags;
 
                 dap_assert ( (l_obj->group = dap_strdup(a_group)) );
                 l_obj->group_len = strlen(l_obj->group);
-                }
+            }
             else l_rc = MDBX_PROBLEM, log_it (L_ERROR, "Cannot allocate a memory for store object value, errno=%d", errno);
         }
 
@@ -1005,8 +1005,7 @@ struct  __record_suffix__   *l_suff;
 
 
 
-    if ( !(l_db_ctx = s_get_db_ctx_for_group(a_store_obj->group)) ) {        /* Get a DB context for the group */
-        log_it(L_WARNING, "No DB context for the group '%s', create it ...", a_store_obj->group);
+    if ( !(l_db_ctx = s_get_db_ctx_for_group(a_store_obj->group)) ) {       /* Get a DB context for the group */
                                                                             /* Group is not found ? Try to create table for new group */
         if ( !(l_db_ctx = s_cre_db_ctx_for_group(a_store_obj->group, MDBX_CREATE)) )
             return  log_it(L_WARNING, "Cannot create DB context for the group '%s'", a_store_obj->group), -EIO;
diff --git a/modules/global-db/dap_chain_global_db_driver_sqlite.c b/modules/global-db/dap_chain_global_db_driver_sqlite.c
index 8f00e4283fb1af8171c47279c9203e84c26e5c1d..ed2772d08484b30627339b248d6660307a61bd94 100644
--- a/modules/global-db/dap_chain_global_db_driver_sqlite.c
+++ b/modules/global-db/dap_chain_global_db_driver_sqlite.c
@@ -611,7 +611,7 @@ int dap_db_driver_sqlite_apply_store_obj(dap_store_obj_t *a_store_obj)
             return -1;
         char *l_blob_value = s_dap_db_driver_get_string_from_blob(a_store_obj->value, (int)a_store_obj->value_len);
         //add one record
-        l_query = sqlite3_mprintf("REPLACE INTO '%s' values(NULL, '%s', x'', '%lld', x'%s')",
+        l_query = sqlite3_mprintf("INSERT INTO '%s' values(NULL, '%s', x'', '%lld', x'%s')",
                                            l_table_name, a_store_obj->key, a_store_obj->timestamp, l_blob_value);
         s_dap_db_driver_sqlite_free(l_blob_value);
     }
@@ -650,17 +650,14 @@ int dap_db_driver_sqlite_apply_store_obj(dap_store_obj_t *a_store_obj)
     if(l_ret == SQLITE_CONSTRAINT) {
         s_dap_db_driver_sqlite_free(l_error_message);
         l_error_message = NULL;
-        //delete exist record
-        char *l_query_del = sqlite3_mprintf("DELETE FROM '%s' WHERE key = '%s'", l_table_name, a_store_obj->key);
-        l_ret = s_dap_db_driver_sqlite_exec(l_conn->conn, l_query_del, &l_error_message);
-        s_dap_db_driver_sqlite_free(l_query_del);
-        if(l_ret != SQLITE_OK) {
-            log_it(L_INFO, "Entry with the same key is already present and can't delete, %s", l_error_message);
-            s_dap_db_driver_sqlite_free(l_error_message);
-            l_error_message = NULL;
-        }
-        // repeat request
-        l_ret = s_dap_db_driver_sqlite_exec(l_conn->conn, l_query, &l_error_message);
+        //replace one record
+        char *l_blob_value = s_dap_db_driver_get_string_from_blob(a_store_obj->value, (int)a_store_obj->value_len);
+        char *l_query_replace = sqlite3_mprintf("REPLACE INTO '%s' values(NULL, '%s', x'', '%lld', x'%s')",
+                                   l_table_name, a_store_obj->key, a_store_obj->timestamp, l_blob_value);
+        s_dap_db_driver_sqlite_free(l_blob_value);
+        l_ret = s_dap_db_driver_sqlite_exec(l_conn->conn, l_query_replace, &l_error_message);
+        s_dap_db_driver_sqlite_free(l_query_replace);
+
     }
     // missing database
     if(l_ret != SQLITE_OK) {
diff --git a/modules/global-db/dap_chain_global_db_remote.c b/modules/global-db/dap_chain_global_db_remote.c
index 7351eacc48eb32fa195fcf2ed94f9bd349a04f68..fae3fe9e0376659ed2406fe3e729f7ab276fd486 100644
--- a/modules/global-db/dap_chain_global_db_remote.c
+++ b/modules/global-db/dap_chain_global_db_remote.c
@@ -591,7 +591,7 @@ unsigned char *pdata;
     *( (uint64_t *) pdata) = a_store_obj->value_len;            pdata += sizeof(uint64_t);
     memcpy(pdata, a_store_obj->value, a_store_obj->value_len);  pdata += a_store_obj->value_len;
 
-    assert( (pdata - l_pkt->data) == l_data_size_out);
+    assert( (uint32_t)(pdata - l_pkt->data) == l_data_size_out);
     return l_pkt;
 }
 
diff --git a/modules/global-db/dap_global_db.c b/modules/global-db/dap_global_db.c
index 7d25fe500b502f86547e801d810a6c6bd2527c15..61f5a5baa6453c8890aa85fe53150e57768b2f76 100644
--- a/modules/global-db/dap_global_db.c
+++ b/modules/global-db/dap_global_db.c
@@ -208,7 +208,7 @@ int dap_global_db_init(const char * a_storage_path, const char * a_driver_name)
         s_driver_name = dap_strdup(a_driver_name);
 
     // Debug config
-    g_dap_global_db_debug_more = dap_config_get_item_bool(g_config, "global_db", "debug_more");
+    g_dap_global_db_debug_more = dap_config_get_item_bool_default(g_config, "resources", "debug_more", false);
 
 
     // Driver initalization
diff --git a/modules/global-db/include/dap_global_db.h b/modules/global-db/include/dap_global_db.h
index d7d2e7afdbcc257ca4c393ad1d5537239ddb4e5c..e83c3d28ab5d5a5ae046ac4f426611f225ba6940 100644
--- a/modules/global-db/include/dap_global_db.h
+++ b/modules/global-db/include/dap_global_db.h
@@ -28,7 +28,7 @@
 #include "dap_context.h"
 #include "dap_proc_queue.h"
 
-#define DAP_GLOBAL_DB_VERSION                 1
+#define DAP_GLOBAL_DB_VERSION               2
 #define DAP_GLOBAL_DB_LOCAL_GENERAL         "local.general"
 
 // GlobalDB own context custom extension
diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c
index af666267f5ede774dbc1e13459b8d7b037b610dc..844d1d0e788654718b5d02bea7269024714783b2 100644
--- a/modules/mempool/dap_chain_mempool.c
+++ b/modules/mempool/dap_chain_mempool.c
@@ -59,6 +59,7 @@
 #include "dap_list.h"
 #include "dap_chain.h"
 #include "dap_chain_net.h"
+#include "dap_chain_net_tx.h"
 #include "dap_sign.h"
 #include "dap_chain_datum_tx.h"
 #include "dap_chain_datum_tx_items.h"
@@ -117,19 +118,29 @@ dap_hash_fast_t* dap_chain_mempool_tx_create(dap_chain_t * a_chain, dap_enc_key_
             !dap_chain_addr_check_sum(a_addr_from) || (a_addr_to && !dap_chain_addr_check_sum(a_addr_to)) || IS_ZERO_256(a_value))
         return NULL;
 
+    const char *l_native_ticker = dap_chain_net_by_id(a_chain->net_id)->pub.native_ticker;
+    bool l_single_channel = !dap_strcmp(a_token_ticker, l_native_ticker);
     // find the transactions from which to take away coins
     uint256_t l_value_transfer = {}; // how many coins to transfer
-    uint256_t l_value_need;
-    // Full fee
-    uint256_t l_value_fee_full = {};
-    // Add fee stake
-    SUM_256_256(a_value_fee, MAX_FEE_STAKE, &l_value_fee_full);
-    // Add full fee
-    SUM_256_256(a_value, l_value_fee_full, &l_value_need);
+    uint256_t l_value_need = a_value, l_net_fee = {}, l_total_fee = {}, l_fee_transfer = {};
+    dap_chain_addr_t l_addr_fee = {};
+    dap_list_t *l_list_fee_out = NULL;
+    bool l_net_fee_used = dap_chain_net_tx_get_fee(a_chain->net_id, &l_net_fee, &l_addr_fee);
+    SUM_256_256(l_net_fee, a_value_fee, &l_total_fee);
+    if (l_single_channel)
+        SUM_256_256(l_value_need, l_total_fee, &l_value_need);
+    else {
+        l_list_fee_out = dap_chain_ledger_get_list_tx_outs_with_val(a_chain->ledger, l_native_ticker,
+                                                                    a_addr_from, l_total_fee, &l_fee_transfer);
+        if (!l_list_fee_out) {
+            log_it(L_WARNING, "Not enough funds to pay fee");
+            return NULL;
+        }
+    }
     dap_list_t *l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(a_chain->ledger, a_token_ticker,
                                                                              a_addr_from, l_value_need, &l_value_transfer);
     if (!l_list_used_out) {
-        log_it(L_WARNING,"Not enough funds to transfer");
+        log_it(L_WARNING, "Not enough funds to transfer");
         return NULL;
     }
     // create empty transaction
@@ -139,21 +150,38 @@ dap_hash_fast_t* dap_chain_mempool_tx_create(dap_chain_t * a_chain, dap_enc_key_
         uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
         assert(EQUAL_256(l_value_to_items, l_value_transfer));
         dap_list_free_full(l_list_used_out, NULL);
+        if (l_list_fee_out) {
+            uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+            assert(EQUAL_256(l_value_fee_items, l_fee_transfer));
+            dap_list_free_full(l_list_fee_out, NULL);
+        }
+
     }
-    // add 'out' items
-    {
+
+    if (l_single_channel) { // add 'out' items
         uint256_t l_value_pack = {}; // how much datoshi add to 'out' items
-        if(dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to, a_value) == 1) {
+        if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to, a_value) == 1) {
             SUM_256_256(l_value_pack, a_value, &l_value_pack);
-            // transaction fee
-            if (!IS_ZERO_256(a_value_fee)) {
-                if(dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1)
-                    SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
+        } else {
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+        // Network fee
+        if (l_net_fee_used) {
+            if (dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_fee, l_net_fee) == 1)
+                SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
+            else {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
             }
-            // Staker fee
-            if(!IS_ZERO_256(MAX_FEE_STAKE)) {
-                if(dap_chain_datum_tx_add_fee_stake_item(&l_tx, MAX_FEE_STAKE) == 1)
-                    SUM_256_256(l_value_pack, MAX_FEE_STAKE, &l_value_pack);
+        }
+        // Validator's fee
+        if (!IS_ZERO_256(a_value_fee)) {
+            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1)
+                SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
+            else {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
             }
         }
         // coin back
@@ -165,6 +193,42 @@ dap_hash_fast_t* dap_chain_mempool_tx_create(dap_chain_t * a_chain, dap_enc_key_
                 return NULL;
             }
         }
+    } else { // add 'out_ext' items
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to, a_value, a_token_ticker) != 1) {
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+        // coin back
+        uint256_t l_value_back;
+        SUBTRACT_256_256(l_value_transfer, a_value, &l_value_back);
+        if(!IS_ZERO_256(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 NULL;
+            }
+        }
+        // Network fee
+        if (l_net_fee_used) {
+            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_fee, l_net_fee, l_native_ticker) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
+        }
+        // Validator's fee
+        if (!IS_ZERO_256(a_value_fee)) {
+            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
+        }
+        // fee coin back
+        SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_value_back);
+        if(!IS_ZERO_256(l_value_back)) {
+            if(dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_from, l_value_back, l_native_ticker) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
+        }
     }
 
     // add 'sign' items
@@ -209,18 +273,20 @@ int dap_chain_mempool_tx_create_massive( dap_chain_t * a_chain, dap_enc_key_t *a
         return -1;
 
     }
-    dap_global_db_obj_t * l_objs = DAP_NEW_Z_SIZE(dap_global_db_obj_t, (a_tx_num + 1) * sizeof (dap_global_db_obj_t));
-
-
+    const char *l_native_ticker = dap_chain_net_by_id(a_chain->net_id)->pub.native_ticker;
+    if (dap_strcmp(a_token_ticker, l_native_ticker)) {
+        log_it(L_WARNING, "dap_chain_mempool_tx_create_massive() should only be used with native token");
+        return -2;
+    }
 
+    dap_global_db_obj_t * l_objs = DAP_NEW_Z_SIZE(dap_global_db_obj_t, (a_tx_num + 1) * sizeof (dap_global_db_obj_t));
+    uint256_t l_net_fee = {}, l_total_fee = {};
+    dap_chain_addr_t l_addr_fee = {};
+    bool l_net_fee_used = dap_chain_net_tx_get_fee(a_chain->net_id, &l_net_fee, &l_addr_fee);
+    SUM_256_256(l_net_fee, a_value_fee, &l_total_fee);
     // Search unused out:
     uint256_t l_single_val = {};
-    // Full fee
-    uint256_t l_value_fee_full = {};
-    // Add fee stake
-    SUM_256_256(a_value_fee, MAX_FEE_STAKE, &l_value_fee_full);
-    // Add full fee
-    SUM_256_256(a_value, l_value_fee_full, &l_single_val);
+    SUM_256_256(a_value, l_total_fee, &l_single_val);
     uint256_t l_value_need = {};
     MULT_256_256(dap_chain_uint256_from(a_tx_num), l_single_val, &l_value_need);
     uint256_t l_value_transfer = {}; // how many coins to transfer
@@ -254,7 +320,7 @@ int dap_chain_mempool_tx_create_massive( dap_chain_t * a_chain, dap_enc_key_t *a
             dap_chain_hash_fast_to_str(&l_item->tx_hash_fast,l_in_hash_str,sizeof (l_in_hash_str) );
 
             char *l_balance = dap_chain_balance_print(l_item->value);
-            if(dap_chain_datum_tx_add_in_item(&l_tx_new, &l_item->tx_hash_fast, (uint32_t)l_item->num_idx_out) == 1) {
+            if (dap_chain_datum_tx_add_in_item(&l_tx_new, &l_item->tx_hash_fast, l_item->num_idx_out)) {
                 SUM_256_256(l_value_to_items, l_item->value, &l_value_to_items);
                 log_it(L_DEBUG, "Added input %s with %s datoshi", l_in_hash_str, l_balance);
             }else{
@@ -280,23 +346,36 @@ int dap_chain_mempool_tx_create_massive( dap_chain_t * a_chain, dap_enc_key_t *a
 
         // add 'out' items
         uint256_t l_value_pack = {}; // how much coin add to 'out' items
-        if(dap_chain_datum_tx_add_out_item(&l_tx_new, a_addr_to, a_value) == 1) {
+        if (dap_chain_datum_tx_add_out_item(&l_tx_new, a_addr_to, a_value) == 1)
             SUM_256_256(l_value_pack, a_value, &l_value_pack);
-            // Transaction fee
-            if (!IS_ZERO_256(a_value_fee)) {
-                if (dap_chain_datum_tx_add_fee_item(&l_tx_new, a_value_fee) == 1)
-                    SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
+        else {
+            dap_chain_datum_tx_delete(l_tx_new);
+            DAP_DELETE(l_objs);
+            return -3;
+        }
+        // Network fee
+        if (l_net_fee_used) {
+            if (dap_chain_datum_tx_add_out_item(&l_tx_new, &l_addr_fee, l_net_fee) == 1)
+                SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
+            else {
+                dap_chain_datum_tx_delete(l_tx_new);
+                DAP_DELETE(l_objs);
+                return -3;
             }
-            // Staker fee
-            if(!IS_ZERO_256(MAX_FEE_STAKE)) {
-                if(dap_chain_datum_tx_add_fee_stake_item(&l_tx_new, MAX_FEE_STAKE) == 1)
-                    SUM_256_256(l_value_pack, MAX_FEE_STAKE, &l_value_pack);
+        }
+        // Validator's fee
+        if (!IS_ZERO_256(a_value_fee)) {
+            if (dap_chain_datum_tx_add_fee_item(&l_tx_new, a_value_fee) == 1)
+                SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
+            else {
+                dap_chain_datum_tx_delete(l_tx_new);
+                DAP_DELETE(l_objs);
+                return -3;
             }
         }
         // coin back
         SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
         if (!IS_ZERO_256(l_value_back)) {
-            //log_it(L_DEBUG,"Change back %"DAP_UINT64_FORMAT_U"", l_value_back);
             if(dap_chain_datum_tx_add_out_item(&l_tx_new, a_addr_from, l_value_back) != 1) {
                 dap_chain_datum_tx_delete(l_tx_new);
                 DAP_DELETE(l_objs);
@@ -308,7 +387,7 @@ int dap_chain_mempool_tx_create_massive( dap_chain_t * a_chain, dap_enc_key_t *a
         if(dap_chain_datum_tx_add_sign_item(&l_tx_new, a_key_from) != 1) {
             dap_chain_datum_tx_delete(l_tx_new);
             DAP_DELETE(l_objs);
-            return -1;
+            return -4;
         }
         // now tx is formed - calc size and hash
         size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx_new);
@@ -358,15 +437,13 @@ int dap_chain_mempool_tx_create_massive( dap_chain_t * a_chain, dap_enc_key_t *a
         //continue;
         l_objs[i].value = (uint8_t *)l_datum;
         l_objs[i].value_len = l_tx_size + sizeof(l_datum->header);
-        log_it(L_DEBUG, "Prepared obj with key %s (value_len = %zd)",
+        log_it(L_DEBUG, "Prepared obj with key %s (value_len = %"DAP_UINT64_FORMAT_U")",
                l_objs[i].key? l_objs[i].key :"NULL" , l_objs[i].value_len );
 
     }
-    dap_list_free_full(l_list_used_out, NULL);
+    dap_list_free_full(l_list_used_out, free);
 
     char * l_gdb_group = dap_chain_net_get_gdb_group_mempool_new(a_chain);
-
-    //return 0;
     dap_global_db_set_multiple_zc(l_gdb_group, l_objs,a_tx_num, s_tx_create_massive_gdb_save_callback , NULL );
     DAP_DELETE(l_gdb_group);
     return 0;
@@ -408,87 +485,83 @@ dap_chain_datum_t *dap_chain_tx_create_cond_input(dap_chain_net_t * a_net, dap_c
         log_it(L_ERROR, "Wrong address_to checksum");
         return NULL;
     }
-
-    // create empty transaction
-    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
-
-    uint16_t pos = 0;
-    dap_chain_datum_tx_add_item(&l_tx, (byte_t*)a_receipt);
-    pos++;
-    uint256_t l_value_send = a_receipt->receipt_info.value_datoshi;
-
-    // add 'in_cond' items
-    dap_chain_hash_fast_t *l_tx_prev_hash = a_tx_prev_hash;
-    dap_chain_datum_tx_t *l_tx_cond = dap_chain_ledger_tx_find_by_hash(l_ledger, l_tx_prev_hash);
-    int l_prev_cond_idx = 0;
-    dap_chain_tx_out_cond_t *l_out_cond = dap_chain_datum_tx_out_cond_get(l_tx_cond, &l_prev_cond_idx);
+    dap_chain_hash_fast_t *l_tx_final_hash = dap_chain_ledger_get_final_chain_tx_hash(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY, a_tx_prev_hash);
+    if (!l_tx_final_hash) {
+        log_it(L_WARNING, "Requested conditional transaction is already used out");
+        return NULL;
+    }
+    if (dap_strcmp(a_net->pub.native_ticker, dap_chain_ledger_tx_get_token_ticker_by_hash(l_ledger, l_tx_final_hash))) {
+        log_it(L_WARNING, "Pay for service should be only in native token ticker");
+        return NULL;
+    }
+    dap_chain_datum_tx_t *l_tx_cond = dap_chain_ledger_tx_find_by_hash(l_ledger, l_tx_final_hash);
+    int l_out_cond_idx;
+    dap_chain_tx_out_cond_t *l_out_cond = dap_chain_datum_tx_out_cond_get(l_tx_cond, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY, &l_out_cond_idx);
     if (!l_out_cond) {
         log_it(L_WARNING, "Requested conditioned transaction have no conditioned output");
         return NULL;
     }
-    if (dap_chain_ledger_tx_hash_is_used_out_item(l_ledger, l_tx_prev_hash, l_prev_cond_idx)) { // TX already spent
-        dap_chain_datum_tx_t *l_tx_tmp = NULL;
-        dap_chain_hash_fast_t l_tx_cur_hash = { 0 }; // start hash
-        dap_chain_tx_out_cond_t *l_tmp_cond;
-        uint256_t l_value_cond = {};
-        int l_tmp_cond_idx;
-        // Find all transactions
-        while (compare256(l_value_cond, l_value_send) == -1) {
-            l_tx_tmp = dap_chain_ledger_tx_cache_find_out_cond(l_ledger, &l_tx_cur_hash, &l_tmp_cond, &l_tmp_cond_idx, NULL);
-            if (!l_tx_tmp) {
-                break;
-            }
-            if (dap_chain_ledger_tx_hash_is_used_out_item(l_ledger, &l_tx_cur_hash, l_tmp_cond_idx))
-                continue;
-            if (l_tmp_cond->header.subtype != l_out_cond->header.subtype)
-                continue;
-            if (!dap_chain_net_srv_uid_compare(l_tmp_cond->header.srv_uid, l_out_cond->header.srv_uid))
-                continue;
-            if (l_tmp_cond->subtype.srv_pay.unit.uint32 != l_out_cond->subtype.srv_pay.unit.uint32)
-                continue;
-            if (!EQUAL_256(l_tmp_cond->subtype.srv_pay.unit_price_max_datoshi, l_out_cond->subtype.srv_pay.unit_price_max_datoshi))
-                continue;
-            if (memcmp(&l_tmp_cond->subtype.srv_pay.pkey_hash, &l_out_cond->subtype.srv_pay.pkey_hash, sizeof(dap_chain_hash_fast_t)))
-                continue;
-            l_value_cond = l_tmp_cond->header.value;
-        }
-        if (compare256(l_value_cond, l_value_send) == -1) {
-            log_it(L_WARNING, "Requested conditional transaction is already used out");
-            return NULL;
-        }
-        l_prev_cond_idx = l_tmp_cond_idx;
-        l_out_cond = l_tmp_cond;
-        l_tx_prev_hash = dap_chain_node_datum_tx_calc_hash(l_tx_tmp);
+
+    dap_chain_tx_out_cond_t *l_out_fee = dap_chain_datum_tx_out_cond_get(l_tx_cond, DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE, NULL);
+    uint256_t l_fee = l_out_fee ? l_out_fee->header.value : uint256_0;
+    uint256_t l_value_send = a_receipt->receipt_info.value_datoshi;
+    uint256_t l_net_fee = {};
+    dap_chain_addr_t l_addr_fee = {};
+    bool l_net_fee_used = dap_chain_net_tx_get_fee(a_net->pub.id, &l_net_fee, &l_addr_fee);
+    SUM_256_256(l_value_send, l_net_fee, &l_value_send);
+    SUM_256_256(l_value_send, l_fee, &l_value_send);
+    if (compare256(l_out_cond->header.value, l_value_send) < 0) {
+        log_it(L_WARNING, "Requested conditioned transaction have no enough funds");
+        return NULL;
     }
-    if (dap_chain_datum_tx_add_in_cond_item(&l_tx, l_tx_prev_hash, l_prev_cond_idx, pos - 1)) {
+
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    dap_chain_datum_tx_add_item(&l_tx, (byte_t*)a_receipt);
+    // add 'in_cond' items
+    if (dap_chain_datum_tx_add_in_cond_item(&l_tx, l_tx_final_hash, l_out_cond_idx, 0)) {
         dap_chain_datum_tx_delete(l_tx);
         log_it( L_ERROR, "Cant add tx cond input");
         return NULL;
     }
-
     // add 'out' item
-    if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to, l_value_send) != 1) {
+    if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to, a_receipt->receipt_info.value_datoshi) != 1) {
         dap_chain_datum_tx_delete(l_tx);
         log_it( L_ERROR, "Cant add tx output");
         return NULL;
     }
-
-    uint256_t l_old_val = l_out_cond->header.value;
-    SUBTRACT_256_256(l_out_cond->header.value, l_value_send, &l_out_cond->header.value);
-    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_out_cond);
-    l_out_cond->header.value = l_old_val;
-
-    // add 'sign' items
-    if (a_key_tx_sign) {
-        if(dap_chain_datum_tx_add_sign_item(&l_tx, a_key_tx_sign) != 1) {
+    // add network fee
+    if (l_net_fee_used) {
+        if (dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_fee, l_net_fee) != 1) {
+            dap_chain_datum_tx_delete(l_tx);
+            log_it( L_ERROR, "Cant add tx output");
+            return NULL;
+        }
+    }
+    // add validator's fee
+    if (!IS_ZERO_256(l_fee)) {
+        if (dap_chain_datum_tx_add_fee_item(&l_tx, l_fee) != 1) {
             dap_chain_datum_tx_delete(l_tx);
-            log_it( L_ERROR, "Can't add sign output");
+            log_it( L_ERROR, "Cant add tx output");
             return NULL;
         }
     }
+    //add 'out_cond' item
+    uint256_t l_new_val = {};
+    uint256_t l_value_cond = l_out_cond->header.value;
+    SUBTRACT_256_256(l_out_cond->header.value, l_value_send, &l_new_val);
+    l_out_cond->header.value = l_new_val;       // Use old conditinal output to form the new one
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_out_cond);
+    l_out_cond->header.value = l_value_cond;    // Restore original value
+    // add 'sign' item
+    if(dap_chain_datum_tx_add_sign_item(&l_tx, a_key_tx_sign) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        log_it( L_ERROR, "Can't add sign output");
+        return NULL;
+    }
     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_DELETE(l_tx);
+    dap_chain_datum_tx_delete(l_tx);
     return l_datum;
 }
 
@@ -502,11 +575,7 @@ dap_chain_hash_fast_t* dap_chain_mempool_tx_create_cond_input(dap_chain_net_t *
 
     char * l_key_str = dap_chain_hash_fast_to_str_new( l_key_hash );
 
-    char * l_gdb_group;
-    if(a_net->pub.default_chain)
-        l_gdb_group = dap_chain_net_get_gdb_group_mempool_new(a_net->pub.default_chain);
-    else
-        l_gdb_group = dap_chain_net_get_gdb_group_mempool_by_chain_type( a_net ,CHAIN_TYPE_TX);
+    char * l_gdb_group = dap_chain_net_get_gdb_group_mempool_by_chain_type(a_net, CHAIN_TYPE_TX);
 
     if( dap_global_db_set(l_gdb_group, l_key_str, l_datum, dap_chain_datum_size(l_datum), true, NULL, NULL )  == 0 ) {
         log_it(L_NOTICE, "Transaction %s placed in mempool", l_key_str);
@@ -537,6 +606,14 @@ static dap_chain_datum_t* dap_chain_tx_create_cond(dap_chain_net_t *a_net,
             !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value))
         return NULL;
 
+    if (dap_strcmp(a_net->pub.native_ticker, a_token_ticker)) {
+        log_it(L_WARNING, "Pay for service should be only in native token ticker");
+        return NULL;
+    }
+
+    uint256_t l_net_fee = {};
+    dap_chain_addr_t l_addr_fee = {};
+    bool l_net_fee_used = dap_chain_net_tx_get_fee(a_net->pub.id, &l_net_fee, &l_addr_fee);
     // find the transactions from which to take away coins
     uint256_t l_value_transfer = {}; // how many coins to transfer
     uint256_t l_value_need = {};
@@ -558,7 +635,7 @@ static dap_chain_datum_t* dap_chain_tx_create_cond(dap_chain_net_t *a_net,
     {
         uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
         assert(EQUAL_256(l_value_to_items, l_value_transfer));
-        dap_list_free_full(l_list_used_out, NULL);
+        dap_list_free_full(l_list_used_out, free);
     }
     // add 'out_cond' and 'out' items
     {
@@ -566,9 +643,27 @@ static dap_chain_datum_t* dap_chain_tx_create_cond(dap_chain_net_t *a_net,
         if(dap_chain_datum_tx_add_out_cond_item(&l_tx, a_key_cond, a_srv_uid, a_value, a_value_per_unit_max, a_unit, a_cond,
                 a_cond_size) == 1) {
             SUM_256_256(l_value_pack, a_value, &l_value_pack);
-            // transaction fee
-            if (!IS_ZERO_256(a_value_fee)) {
-                // TODO add condition with fee for mempool-as-service
+        } else {
+            dap_chain_datum_tx_delete(l_tx);
+            log_it( L_ERROR, "Cant add conditional output");
+            return NULL;
+        }
+        // Network fee
+        if (l_net_fee_used) {
+            if (dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_fee, l_net_fee) == 1)
+                SUM_256_256(l_value_pack, l_net_fee, &l_value_pack);
+            else {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
+            }
+        }
+        // Validator's fee
+        if (!IS_ZERO_256(a_value_fee)) {
+            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1)
+                SUM_256_256(l_value_pack, a_value_fee, &l_value_pack);
+            else {
+                dap_chain_datum_tx_delete(l_tx);
+                return NULL;
             }
         }
         // coin back
@@ -596,6 +691,7 @@ static dap_chain_datum_t* dap_chain_tx_create_cond(dap_chain_net_t *a_net,
     return l_datum;
 }
 
+
 /**
  * Make transfer transaction & insert to cache
  *
@@ -713,7 +809,7 @@ dap_chain_datum_token_emission_t *dap_chain_mempool_emission_get(dap_chain_t *a_
 
 dap_chain_datum_token_emission_t *dap_chain_mempool_datum_emission_extract(dap_chain_t *a_chain, byte_t *a_data, size_t a_size)
 {
-    if (!a_chain || !a_data || !a_size)
+    if (!a_chain || !a_data || a_size < sizeof(dap_chain_datum_t))
         return NULL;
     dap_chain_datum_t *l_datum = (dap_chain_datum_t *)a_data;
     if ((l_datum->header.version_id != DAP_CHAIN_DATUM_VERSION) || (l_datum->header.type_id != DAP_CHAIN_DATUM_TOKEN_EMISSION) ||
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index b3d28dc5ffbc84c68f6ff44fb260ae9ed754bdc9..eb378f0249924c0927f3156cde645779003eedf5 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -26,10 +26,6 @@
 
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
-#include "dap_chain.h"
-#include "dap_chain_datum_tx_out_cond.h"
-#include "dap_list.h"
-#include "dap_time.h"
 #endif
 #ifndef  _XOPEN_SOURCE
 #define _XOPEN_SOURCE       /* See feature_test_macros(7) */
@@ -65,7 +61,9 @@
 
 #include "uthash.h"
 #include "utlist.h"
-
+#include "dap_chain.h"
+#include "dap_list.h"
+#include "dap_time.h"
 #include "dap_common.h"
 #include "dap_string.h"
 #include "dap_strfuncs.h"
@@ -75,17 +73,22 @@
 #include "dap_hash.h"
 #include "dap_cert.h"
 #include "dap_cert_file.h"
-
+#include "dap_chain_datum_tx.h"
+#include "dap_chain_datum_tx_in_cond.h"
+#include "dap_chain_datum_tx_items.h"
+#include "dap_chain_datum_tx_out.h"
+#include "dap_chain_datum_tx_out_cond.h"
 #include "dap_timerfd.h"
 #include "dap_stream_worker.h"
 #include "dap_worker.h"
 #include "dap_proc_queue.h"
 #include "dap_proc_thread.h"
-
 #include "dap_enc_http.h"
 #include "dap_chain_common.h"
 #include "dap_chain_datum_decree.h"
+#include "dap_chain_tx.h"
 #include "dap_chain_net.h"
+#include "dap_chain_net_tx.h"
 #include "dap_chain_net_srv.h"
 #include "dap_chain_pvt.h"
 #include "dap_chain_node_client.h"
@@ -135,11 +138,13 @@ struct link_dns_request {
 struct net_link {
     dap_chain_node_info_t *link_info;
     dap_chain_node_client_t *link;
+    dap_events_socket_uuid_t client_uuid;
 };
 
 struct downlink {
     dap_stream_worker_t *worker;
     dap_stream_ch_uuid_t ch_uuid;
+    dap_events_socket_uuid_t esocket_uuid;
     UT_hash_handle hh;
 };
 
@@ -200,7 +205,7 @@ typedef struct dap_chain_net_pvt{
     uint16_t acl_idx;
 
     // Main loop timer
-    dap_timerfd_t * main_timer;
+    dap_interval_timer_t main_timer;
 
     // General rwlock for structure
     pthread_rwlock_t rwlock;
@@ -283,8 +288,7 @@ static int s_cli_net(int argc, char ** argv, char **str_reply);
 
 static bool s_seed_mode = false;
 
-static uint8_t *dap_chain_net_set_acl(dap_chain_hash_fast_t *a_pkey_hash);
-
+static uint8_t *s_net_set_acl(dap_chain_hash_fast_t *a_pkey_hash);
 static bool s_start_dns_request(dap_chain_net_t *a_net, dap_chain_node_info_t *a_link_node_info);
 
 /**
@@ -329,9 +333,7 @@ int dap_chain_net_init()
     s_required_links_count = dap_config_get_item_int32_default(g_config, "general", "require_links", s_required_links_count);
     s_debug_more = dap_config_get_item_bool_default(g_config,"chain_net","debug_more",false);
 
-    dap_chain_net_load_all();
-
-    dap_enc_http_set_acl_callback(dap_chain_net_set_acl);
+    dap_enc_http_set_acl_callback(s_net_set_acl);
     log_it(L_NOTICE,"Chain networks initialized");
     return 0;
 }
@@ -406,7 +408,7 @@ void dap_chain_net_add_gdb_notify_callback(dap_chain_net_t *a_net, dap_global_db
     PVT(a_net)->gdb_notifiers = dap_list_append(PVT(a_net)->gdb_notifiers, l_notifier);
 }
 
-int dap_chain_net_add_downlink(dap_chain_net_t *a_net, dap_stream_worker_t *a_worker, dap_stream_ch_uuid_t a_ch_uuid)
+int dap_chain_net_add_downlink(dap_chain_net_t *a_net, dap_stream_worker_t *a_worker, dap_stream_ch_uuid_t a_ch_uuid, dap_events_socket_uuid_t a_esocket_uuid)
 {
     if (!a_net || !a_worker)
         return -1;
@@ -423,12 +425,12 @@ int dap_chain_net_add_downlink(dap_chain_net_t *a_net, dap_stream_worker_t *a_wo
     l_downlink = DAP_NEW_Z(struct downlink);
     l_downlink->worker = a_worker;
     l_downlink->ch_uuid = a_ch_uuid;
+    l_downlink->esocket_uuid = a_esocket_uuid;
     HASH_ADD_BYHASHVALUE(hh, l_net_pvt->downlinks, ch_uuid, sizeof(a_ch_uuid), a_hash_value, l_downlink);
     pthread_rwlock_unlock(&l_net_pvt->rwlock);
     return 0;
 }
 
-
 struct send_records_args{
     dap_chain_net_t * net;
     dap_proc_thread_t * proc_thread;
@@ -518,7 +520,7 @@ static bool s_net_send_records_callback_get_raw (dap_global_db_context_t * a_glo
 static bool s_net_send_records(dap_proc_thread_t *a_thread, void *a_arg)
 {
     UNUSED(a_thread);
-    dap_store_obj_t *l_obj, *l_arg_obj = (dap_store_obj_t *)a_arg;
+    dap_store_obj_t *l_arg_obj = (dap_store_obj_t *)a_arg;
     dap_chain_net_t *l_net = (dap_chain_net_t *)l_arg_obj->callback_proc_thread_arg;
 
     struct send_records_args * l_args = DAP_NEW_Z(struct send_records_args);
@@ -594,7 +596,7 @@ static bool s_net_send_atoms(dap_proc_thread_t *a_thread, void *a_arg)
     UNUSED(a_thread);
     dap_store_obj_t *l_arg = (dap_store_obj_t *)a_arg;
     dap_chain_net_t *l_net = (dap_chain_net_t *)l_arg->callback_proc_thread_arg;
-    pthread_rwlock_rdlock(&PVT(l_net)->rwlock);
+    pthread_rwlock_wrlock(&PVT(l_net)->rwlock);
     if (PVT(l_net)->state != NET_STATE_SYNC_CHAINS) {
         dap_list_t *it = NULL;
         do {
@@ -822,99 +824,6 @@ static void s_fill_links_from_root_aliases(dap_chain_net_t * a_net)
      }
 }
 
-/**
- * @brief s_net_state_link_replace_error
- * @param a_worker
- * @param a_node_info
- * @param a_arg
- * @param a_errno
- */
-/*static void s_net_state_link_replace_error(dap_worker_t *a_worker, dap_chain_node_info_t *a_node_info, void *a_arg, int a_errno)
-{
-    UNUSED(a_worker);
-    struct link_dns_request *l_dns_request = (struct link_dns_request *)a_arg;
-    dap_chain_net_t *l_net = l_dns_request->net;
-    char l_node_addr_str[INET_ADDRSTRLEN] = {};
-    inet_ntop(AF_INET, &a_node_info->hdr.ext_addr_v4, l_node_addr_str, sizeof (a_node_info->hdr.ext_addr_v4));
-    log_it(L_WARNING,"Link " NODE_ADDR_FP_STR " (%s) replace error with code %d", NODE_ADDR_FP_ARGS_S(a_node_info->hdr.address),
-                                                                                 l_node_addr_str,a_errno );
-    struct json_object *l_json = net_states_json_collect(l_net);
-    char l_err_str[128] = { };
-    dap_snprintf(l_err_str, sizeof(l_err_str)
-                 , "Link " NODE_ADDR_FP_STR " [%s] replace errno %d"
-                 , NODE_ADDR_FP_ARGS_S(a_node_info->hdr.address), l_node_addr_str, a_errno);
-    json_object_object_add(l_json, "errorMessage", json_object_new_string(l_err_str));
-    dap_notify_server_send_mt(json_object_get_string(l_json));
-    json_object_put(l_json);
-    DAP_DELETE(a_node_info);
-    dap_chain_node_info_t *l_link_node_info = NULL;
-    for (int i = 0; i < 1000; i++) {
-        l_link_node_info = s_get_dns_link_from_cfg(l_net);
-        if (l_link_node_info)
-            break;
-    }
-    if (!l_link_node_info || PVT(l_net)->state == NET_STATE_OFFLINE) { // We have lost this link forever
-        DAP_DELETE(l_dns_request);
-        return;
-    }
-    if (dap_chain_node_info_dns_request(l_link_node_info->hdr.ext_addr_v4,
-                                        l_link_node_info->hdr.ext_port,
-                                        l_net->pub.name,
-                                        l_link_node_info,  // use it twice
-                                        s_net_state_link_replace_success,
-                                        s_net_state_link_replace_error,
-                                        l_dns_request)) {
-        log_it(L_ERROR, "Can't process node info dns request");
-        DAP_DELETE(l_link_node_info);
-        DAP_DELETE(l_dns_request);
-    }
-}*/
-
-/**
- * @brief s_net_state_link_repace_success
- * @param a_worker
- * @param a_node_info
- * @param a_arg
- */
-
-/*static void s_net_state_link_replace_success(dap_worker_t *a_worker, dap_chain_node_info_t *a_node_info, void *a_arg)
-{
-    if (s_debug_more) {
-        char l_node_addr_str[INET_ADDRSTRLEN] = {};
-        inet_ntop(AF_INET, &a_node_info->hdr.ext_addr_v4, l_node_addr_str, INET_ADDRSTRLEN);
-        log_it(L_DEBUG,"Link " NODE_ADDR_FP_STR " (%s) replace success", NODE_ADDR_FP_ARGS_S(a_node_info->hdr.address),
-                                                                                     l_node_addr_str);
-    }
-
-    struct link_dns_request *l_dns_request = (struct link_dns_request *)a_arg;
-    dap_chain_net_t *l_net = l_dns_request->net;
-    dap_chain_net_pvt_t *l_net_pvt = PVT(l_net);
-    if (l_net_pvt->state == NET_STATE_OFFLINE) {
-        DAP_DELETE(l_dns_request);
-        return;
-    }
-    uint64_t l_own_addr = dap_chain_net_get_cur_addr_int(l_net);
-    if (a_node_info->hdr.address.uint64 == l_own_addr) {
-        s_net_state_link_replace_error(a_worker, a_node_info, a_arg, EWOULDBLOCK);
-        return;
-    }
-    struct net_link *l_new_link = DAP_NEW_Z(struct net_link);
-    l_new_link->link_info = a_node_info;
-    l_new_link->link = dap_chain_net_client_create_n_connect(l_net, a_node_info);
-    pthread_rwlock_wrlock(&l_net_pvt->rwlock);
-    l_net_pvt->net_links = dap_list_append(l_net_pvt->net_links, l_new_link);
-    pthread_rwlock_unlock(&l_net_pvt->rwlock);
-    struct json_object *l_json = net_states_json_collect(l_net);
-    char l_err_str[128] = { };
-    dap_snprintf(l_err_str, sizeof(l_err_str)
-                 , "Link " NODE_ADDR_FP_STR " replace success"
-                 , NODE_ADDR_FP_ARGS_S(a_node_info->hdr.address));
-    json_object_object_add(l_json, "errorMessage", json_object_new_string(l_err_str));
-    dap_notify_server_send_mt(json_object_get_string(l_json));
-    json_object_put(l_json);
-    DAP_DELETE(l_dns_request);
-}*/
-
 /**
  * @brief s_node_link_callback_connected
  * @param a_node_client
@@ -994,11 +903,13 @@ static void s_node_link_callback_disconnected(dap_chain_node_client_t *a_node_cl
             log_it(L_ERROR, "Links count is zero in disconnected callback, looks smbd decreased it twice or forget to increase on connect/reconnect");
     }
     if (l_net_pvt->state_target != NET_STATE_OFFLINE) {
-        a_node_client->keep_connection = true;
         for (dap_list_t *it = l_net_pvt->net_links; it; it = it->next) {
             if (((struct net_link *)it->data)->link == NULL) {  // We have a free prepared link
-                s_node_link_remove(l_net_pvt, a_node_client, true);
-                a_node_client->keep_connection = false;
+                s_node_link_remove(l_net_pvt, a_node_client, l_net_pvt->only_static_links);
+                dap_chain_node_client_t *l_client_new = dap_chain_net_client_create_n_connect(l_net,
+                                                                                             ((struct net_link *)it->data)->link_info);
+                ((struct net_link *)it->data)->link = l_client_new;
+                ((struct net_link *)it->data)->client_uuid = l_client_new->uuid;
                 ((struct net_link *)it->data)->link = dap_chain_net_client_create_n_connect(l_net,
                                                         ((struct net_link *)it->data)->link_info);
                 pthread_rwlock_unlock(&l_net_pvt->rwlock);
@@ -1006,6 +917,7 @@ static void s_node_link_callback_disconnected(dap_chain_node_client_t *a_node_cl
             }
         }
         if (l_net_pvt->only_static_links) {
+            a_node_client->keep_connection = true;
             pthread_rwlock_unlock(&l_net_pvt->rwlock);
             return;
         }
@@ -1022,16 +934,6 @@ static void s_node_link_callback_disconnected(dap_chain_node_client_t *a_node_cl
 
         if (l_link_node_info) {
             if(!s_start_dns_request(l_net, l_link_node_info)) {
-            /*struct link_dns_request *l_dns_request = DAP_NEW_Z(struct link_dns_request);
-            l_dns_request->net = l_net;
-            if (dap_chain_node_info_dns_request(l_link_node_info->hdr.ext_addr_v4,
-                                                l_link_node_info->hdr.ext_port,
-                                                l_net->pub.name,
-                                                l_link_node_info,  // use it twice
-                                                s_net_state_link_prepare_success,//s_net_state_link_replace_success,
-                                                s_net_state_link_prepare_error,//s_net_state_link_replace_error,
-                                                l_dns_request)) {
-                                                */
                 log_it(L_ERROR, "Can't process node info dns request");
                 DAP_DELETE(l_link_node_info);
             } else {
@@ -1113,7 +1015,9 @@ static void s_node_link_callback_delete(dap_chain_node_client_t * a_node_client,
     for ( dap_list_t * it = l_net_pvt->net_links; it; it=it->next ){
         if (((struct net_link *)it->data)->link == a_node_client) {
             log_it(L_DEBUG,"Replace node client with new one");
-            ((struct net_link *)it->data)->link = dap_chain_net_client_create_n_connect(l_net, a_node_client->info);
+            dap_chain_node_client_t *l_client = dap_chain_net_client_create_n_connect(l_net, a_node_client->info);
+            ((struct net_link *)it->data)->link = l_client;
+            ((struct net_link *)it->data)->client_uuid = l_client->uuid;
         }
     }
     pthread_rwlock_unlock(&l_net_pvt->rwlock);
@@ -1332,15 +1236,16 @@ static bool s_net_states_proc(dap_proc_thread_t *a_thread, void *a_arg) {
             // delete all links
             dap_list_t *l_tmp = l_net_pvt->net_links;
             while (l_tmp) {
-                dap_list_t *l_next =l_tmp->next;
-                dap_chain_node_client_t *l_link = ((struct net_link *)l_tmp->data)->link;
-                if (l_link) {
-                    l_link->keep_connection = false;
-                    dap_chain_node_client_close(l_link);
-                }
+                dap_list_t *l_next = l_tmp->next;
+                dap_chain_node_client_close(((struct net_link *)l_tmp->data)->client_uuid);
                 DAP_DEL_Z(((struct net_link *)l_tmp->data)->link_info);
                 l_tmp = l_next;
             }
+            struct downlink *l_downlink, *l_dltmp;
+            HASH_ITER(hh, l_net_pvt->downlinks, l_downlink, l_dltmp) {
+                HASH_DEL(l_net_pvt->downlinks, l_downlink);
+                dap_events_socket_delete_mt(l_downlink->worker->worker, l_downlink->esocket_uuid);
+            }
             dap_list_free_full(l_net_pvt->net_links, NULL);
             l_net_pvt->net_links = NULL;
             if ( l_net_pvt->state_target != NET_STATE_OFFLINE ){
@@ -1453,6 +1358,7 @@ static bool s_net_states_proc(dap_proc_thread_t *a_thread, void *a_arg) {
                 dap_chain_node_info_t *l_link_info = ((struct net_link *)l_tmp->data)->link_info;
                 dap_chain_node_client_t *l_client = dap_chain_net_client_create_n_connect(l_net, l_link_info);
                 ((struct net_link *)l_tmp->data)->link = l_client;
+                ((struct net_link *)l_tmp->data)->client_uuid = l_client->uuid;
                 if (++l_used_links == s_required_links_count)
                     break;
             }
@@ -1774,7 +1680,7 @@ const char* dap_chain_net_get_type(dap_chain_t *l_chain)
  * @return true
  * @return false
  */
-void s_chain_net_ledger_cache_reload(dap_chain_net_t *l_net)
+static void s_chain_net_ledger_cache_reload(dap_chain_net_t *l_net)
 {
     dap_chain_ledger_purge(l_net->pub.ledger, false);
     dap_chain_t *l_chain = NULL;
@@ -1792,18 +1698,6 @@ void s_chain_net_ledger_cache_reload(dap_chain_net_t *l_net)
                 debug_if(s_debug_more, L_DEBUG, "Added atom from treshold");
         }
     }
-    /*bool l_processed;
-    do {
-        l_processed = false;
-        DL_FOREACH(l_net->pub.chains, l_chain) {
-           if (l_chain->callback_atom_add_from_treshold) {
-                while (l_chain->callback_atom_add_from_treshold(l_chain, NULL)) {
-                    log_it(L_DEBUG, "Added atom from treshold");
-                    l_processed = true;
-                }
-            }
-        }
-    } while (l_processed); */ //TODO: Commented out in branch master and flagged as obscure code.
 }
 
 /**
@@ -1814,7 +1708,7 @@ void s_chain_net_ledger_cache_reload(dap_chain_net_t *l_net)
  * @return true
  * @return false
  */
-bool s_chain_net_reload_ledger_cache_once(dap_chain_net_t *l_net)
+static bool s_chain_net_reload_ledger_cache_once(dap_chain_net_t *l_net)
 {
     if (!l_net)
         return false;
@@ -1826,7 +1720,7 @@ bool s_chain_net_reload_ledger_cache_once(dap_chain_net_t *l_net)
         return false;
     }
     // create file, if it not presented. If file exists, ledger cache operation is stopped
-    char *l_cache_file = dap_strdup_printf( "%s/%s.cache", l_cache_dir, "5B0FEEF6-B0D5-48A9-BFA2-32E8B294366D");
+    char *l_cache_file = dap_strdup_printf( "%s/%s.cache", l_cache_dir, "e0fee993-54b7-4cbb-be94-f633cc17853f");
     DAP_DELETE(l_cache_dir);
     if (dap_file_simple_test(l_cache_file)) {
         log_it(L_WARNING, "Cache file '%s' already exists", l_cache_file);
@@ -1834,7 +1728,6 @@ bool s_chain_net_reload_ledger_cache_once(dap_chain_net_t *l_net)
         return false;
     }
 
-    log_it(L_WARNING,"Start one time ledger cache reloading");
     static FILE *s_cache_file = NULL;
     s_cache_file = fopen(l_cache_file, "a");
     if(!s_cache_file) {
@@ -1846,9 +1739,6 @@ bool s_chain_net_reload_ledger_cache_once(dap_chain_net_t *l_net)
             return -1;
         }
     }
-    // reload ledger cache (same as net -net <network_name>> ledger reload command)
-    if (dap_file_simple_test(l_cache_file))
-        s_chain_net_ledger_cache_reload(l_net);
     fclose(s_cache_file);
     DAP_DELETE(l_cache_file);
     return true;
@@ -1861,21 +1751,21 @@ bool s_chain_net_reload_ledger_cache_once(dap_chain_net_t *l_net)
  * @return uint16_t
  */
 static const char *s_chain_type_convert_to_string(dap_chain_type_t a_type) {
-	switch (a_type) {
-		case CHAIN_TYPE_TOKEN:
-			return ("token");
-		case CHAIN_TYPE_EMISSION:
-			return ("emission");
-		case CHAIN_TYPE_TX:
-			return ("transaction");
-		case CHAIN_TYPE_CA:
-			return ("ca");
-		case CHAIN_TYPE_SIGNER:
-			return ("signer");
-
-		default:
-			return ("custom");
-	}
+    switch (a_type) {
+        case CHAIN_TYPE_TOKEN:
+            return ("token");
+        case CHAIN_TYPE_EMISSION:
+            return ("emission");
+        case CHAIN_TYPE_TX:
+            return ("transaction");
+        case CHAIN_TYPE_CA:
+            return ("ca");
+        case CHAIN_TYPE_SIGNER:
+            return ("signer");
+
+        default:
+            return ("custom");
+    }
 }
 
 /**
@@ -1933,13 +1823,13 @@ static int s_cli_net(int argc, char **argv, char **a_str_reply)
                     dap_chain_t * l_chain = l_net->pub.chains;
                     while (l_chain) {
                         dap_string_append_printf(l_string_ret, "\t\t%s:\n", l_chain->name );
-						if (l_chain->default_datum_types_count)
-						{
-							dap_string_append_printf(l_string_ret, "\t\t");
-							for (uint16_t i = 0; i < l_chain->default_datum_types_count; i++)
-								dap_string_append_printf(l_string_ret, "| %s ", s_chain_type_convert_to_string(l_chain->default_datum_types[i]) );
-							dap_string_append_printf(l_string_ret, "|\n");
-						}
+                        if (l_chain->default_datum_types_count)
+                        {
+                            dap_string_append_printf(l_string_ret, "\t\t");
+                            for (uint16_t i = 0; i < l_chain->default_datum_types_count; i++)
+                                dap_string_append_printf(l_string_ret, "| %s ", s_chain_type_convert_to_string(l_chain->default_datum_types[i]) );
+                            dap_string_append_printf(l_string_ret, "|\n");
+                        }
                         l_chain = l_chain->next;
                     }
                 }
@@ -2269,12 +2159,13 @@ static int s_cli_net(int argc, char **argv, char **a_str_reply)
                                                   "Subcommand 'ca' requires one of parameter: add, list, del\n");
                 l_ret = -5;
             }
-        } else if (l_ledger_str && !strcmp(l_ledger_str, "reload"))
-        {
-           s_chain_net_ledger_cache_reload(l_net);
-        }
-        else
-        {
+        } else if (l_ledger_str && !strcmp(l_ledger_str, "reload")) {
+            int l_return_state = dap_chain_net_stop(l_net);
+            sleep(1);   // wait to net going offline
+            s_chain_net_ledger_cache_reload(l_net);
+            if (l_return_state)
+                dap_chain_net_start(l_net);
+        } else {
             dap_cli_server_cmd_set_reply_text(a_str_reply,
                                               "Command 'net' requires one of subcomands: sync, link, go, get, stats, ca, ledger");
             l_ret = -1;
@@ -2294,21 +2185,21 @@ static int s_cli_net(int argc, char **argv, char **a_str_reply)
 
 static void remove_duplicates_in_chain_by_priority(dap_chain_t *l_chain_1, dap_chain_t *l_chain_2)
 {
-	dap_chain_t *l_chain_high_priority = (l_chain_1->load_priority > l_chain_2->load_priority) ? l_chain_2 : l_chain_1; //such distribution is made for correct operation with the same priority
-	dap_chain_t *l_chain_low_priority = (l_chain_1->load_priority > l_chain_2->load_priority) ? l_chain_1 : l_chain_2; //...^...^...^...
+    dap_chain_t *l_chain_high_priority = (l_chain_1->load_priority > l_chain_2->load_priority) ? l_chain_2 : l_chain_1; //such distribution is made for correct operation with the same priority
+    dap_chain_t *l_chain_low_priority = (l_chain_1->load_priority > l_chain_2->load_priority) ? l_chain_1 : l_chain_2; //...^...^...^...
 
-	for (int i = 0; i < l_chain_high_priority->default_datum_types_count; i++)
-	{
-		for (int j = 0; j < l_chain_low_priority->default_datum_types_count; j++)
-		{
-			if (l_chain_high_priority->default_datum_types[i] == l_chain_low_priority->default_datum_types[j])
-			{
-				l_chain_low_priority->default_datum_types[j] = l_chain_low_priority->default_datum_types[l_chain_low_priority->default_datum_types_count - 1];
-				--l_chain_low_priority->default_datum_types_count;
-				--j;
-			}
-		}
-	}
+    for (int i = 0; i < l_chain_high_priority->default_datum_types_count; i++)
+    {
+        for (int j = 0; j < l_chain_low_priority->default_datum_types_count; j++)
+        {
+            if (l_chain_high_priority->default_datum_types[i] == l_chain_low_priority->default_datum_types[j])
+            {
+                l_chain_low_priority->default_datum_types[j] = l_chain_low_priority->default_datum_types[l_chain_low_priority->default_datum_types_count - 1];
+                --l_chain_low_priority->default_datum_types_count;
+                --j;
+            }
+        }
+    }
 }
 
 // for sequential loading chains
@@ -2329,6 +2220,16 @@ static int callback_compare_prioritity_list(const void * a_item1, const void * a
     return -1;
 }
 
+void s_main_timer_callback(void *a_arg)
+{
+    dap_chain_net_t *l_net = (dap_chain_net_t *)a_arg;
+    dap_chain_net_pvt_t *l_net_pvt = PVT(l_net);
+    if (l_net_pvt->state_target == NET_STATE_ONLINE &&
+            l_net_pvt->state >= NET_STATE_LINKS_ESTABLISHED &&
+            !l_net_pvt->links_connected_count) // restart network
+        dap_chain_net_start(l_net);
+}
+
 /**
  * @brief load network config settings from cellframe-node.cfg file
  *
@@ -2548,87 +2449,69 @@ int s_net_load(const char * a_net_name, uint16_t a_acl_idx)
                                 ( l_seed_nodes_ipv4_len  && i < l_seed_nodes_ipv4_len  ) ||
                                 ( l_seed_nodes_ipv6_len  && i < l_seed_nodes_ipv6_len  ) ||
                                 ( l_seed_nodes_hostnames_len  && i < l_seed_nodes_hostnames_len  )
-                              )
-                                                                    ; i++ ){
-            dap_chain_node_addr_t *l_seed_node_addr;
-            dap_chain_node_info_t *l_node_info = NULL;
-            l_seed_node_addr = dap_chain_node_alias_find(l_net, l_net_pvt->seed_aliases[i]);
-            if (l_seed_node_addr) {
-                l_node_info = dap_chain_node_info_read(l_net, l_seed_node_addr);
-                DAP_DELETE(l_seed_node_addr);
+                            ); i++) {
+            dap_chain_node_addr_t l_seed_node_addr  = { 0 }, *l_seed_node_addr_gdb  = NULL;
+            dap_chain_node_info_t l_node_info       = { 0 }, *l_node_info_gdb       = NULL;
+
+            log_it(L_NOTICE, "Check alias %s in db", l_net_pvt->seed_aliases[i]);
+            dap_snprintf(l_node_info.hdr.alias,sizeof (l_node_info.hdr.alias),"%s", PVT(l_net)->seed_aliases[i]);
+            if (dap_sscanf(l_seed_nodes_addrs[i], NODE_ADDR_FP_STR, NODE_ADDR_FPS_ARGS_S(l_seed_node_addr)) != 4) {
+              log_it(L_ERROR,"Wrong address format, must be 0123::4567::890AB::CDEF");
+              continue;
             }
-            if (!l_seed_node_addr || !l_node_info) {
-                log_it(L_NOTICE, "Update alias %s in database, prefill it",l_net_pvt->seed_aliases[i]);
-                l_node_info = DAP_NEW_Z(dap_chain_node_info_t);
-                l_seed_node_addr = DAP_NEW_Z(dap_chain_node_addr_t);
-                dap_snprintf( l_node_info->hdr.alias,sizeof ( l_node_info->hdr.alias),"%s",PVT(l_net)->seed_aliases[i]);
-                if (dap_sscanf(l_seed_nodes_addrs[i],NODE_ADDR_FP_STR, NODE_ADDR_FPS_ARGS(l_seed_node_addr) ) != 4 ){
-                    log_it(L_ERROR,"Wrong address format,  should be like 0123::4567::890AB::CDEF");
-                    DAP_DELETE(l_seed_node_addr);
-                    DAP_DELETE(l_node_info);
-                    l_seed_node_addr = NULL;
-                    continue;
+            if (l_seed_nodes_ipv4_len)
+                inet_pton(AF_INET, l_seed_nodes_ipv4[i], &l_node_info.hdr.ext_addr_v4);
+            if (l_seed_nodes_ipv6_len)
+                inet_pton(AF_INET6, l_seed_nodes_ipv6[i], &l_node_info.hdr.ext_addr_v6);
+            l_node_info.hdr.ext_port = l_seed_nodes_port_len && l_seed_nodes_port_len >= i ?
+                strtoul(l_seed_nodes_port[i], NULL, 10) : 8079;
+
+            if (l_seed_nodes_hostnames_len) {
+                struct sockaddr l_sa = {};
+                log_it(L_DEBUG, "Resolve %s addr", l_seed_nodes_hostnames[i]);
+                int l_ret_code = dap_net_resolve_host(l_seed_nodes_hostnames[i], AF_INET, &l_sa);
+                if (l_ret_code == 0) {
+                    struct in_addr *l_res = (struct in_addr *)&l_sa;
+                    log_it(L_NOTICE, "Resolved %s to %s (ipv4)", l_seed_nodes_hostnames[i], inet_ntoa(*l_res));
+                    l_node_info.hdr.ext_addr_v4.s_addr = l_res->s_addr;
+                } else {
+                    log_it(L_ERROR, "%s", gai_strerror(l_ret_code));
                 }
-                if( l_seed_node_addr ){
-                    if ( l_seed_nodes_ipv4_len )
-                        inet_pton( AF_INET, l_seed_nodes_ipv4[i],&l_node_info->hdr.ext_addr_v4);
-                    if ( l_seed_nodes_ipv6_len )
-                        inet_pton( AF_INET6, l_seed_nodes_ipv6[i],&l_node_info->hdr.ext_addr_v6);
-                    if(l_seed_nodes_port_len && l_seed_nodes_port_len >= i)
-                        l_node_info->hdr.ext_port = strtoul(l_seed_nodes_port[i], NULL, 10);
-                    else
-                        l_node_info->hdr.ext_port = 8079;
-
-                    if ( l_seed_nodes_hostnames_len ){
-                        struct addrinfo l_hints={0};
-
-                        l_hints.ai_family = AF_UNSPEC ;    /* Allow IPv4 or IPv6 */
-                        //l_hints.ai_flags = AI_PASSIVE;    /* For wildcard IP address */
-
-                        log_it( L_DEBUG, "Resolve %s addr", l_seed_nodes_hostnames[i]);
-                        struct hostent *l_he;
-
-                        if ( (l_he = gethostbyname (l_seed_nodes_hostnames[i]) ) != NULL  ){
-                            struct in_addr **l_addr_list = (struct in_addr **) l_he->h_addr_list;
-                            for(int i = 0; l_addr_list[i] != NULL; i++ ) {
-                                log_it( L_NOTICE, "Resolved %s to %s (ipv4)", l_seed_nodes_hostnames[i] ,
-                                        inet_ntoa( *l_addr_list[i]  ) );
-                                l_node_info->hdr.ext_addr_v4.s_addr = l_addr_list[i]->s_addr;
-                            }
-                        } else {
-                            herror("gethostname");
-                        }
-                    }
+            }
 
-                    l_node_info->hdr.address.uint64 = l_seed_node_addr->uint64;
-                    if ( l_node_info->hdr.ext_addr_v4.s_addr ||
-                    #ifdef DAP_OS_BSD
-                    l_node_info->hdr.ext_addr_v6.__u6_addr.__u6_addr32[0]
-                    #else
-                        l_node_info->hdr.ext_addr_v6.s6_addr32[0]
-                    #endif
-                            ){
-                        int l_ret;
-                        if ( (l_ret = dap_chain_node_info_save(l_net, l_node_info)) ==0 ){
-                            if (dap_chain_node_alias_register(l_net,l_net_pvt->seed_aliases[i],l_seed_node_addr))
-                                log_it(L_NOTICE,"Seed node "NODE_ADDR_FP_STR" added to the curent list",NODE_ADDR_FP_ARGS(l_seed_node_addr) );
-                            else {
-                                log_it(L_WARNING,"Cant register alias %s for address "NODE_ADDR_FP_STR, l_net_pvt->seed_aliases[i], NODE_ADDR_FP_ARGS(l_seed_node_addr));
-                            }
-                        }else{
-                            log_it(L_WARNING,"Cant save node info for address "NODE_ADDR_FP_STR" return code %d",
-                                   NODE_ADDR_FP_ARGS(l_seed_node_addr), l_ret);
-                        }
+            l_seed_node_addr_gdb    = dap_chain_node_alias_find(l_net, l_net_pvt->seed_aliases[i]);
+            l_node_info_gdb         = l_seed_node_addr_gdb ? dap_chain_node_info_read(l_net, l_seed_node_addr_gdb) : NULL;
+
+            l_node_info.hdr.address = l_seed_node_addr;
+            if (l_node_info.hdr.ext_addr_v4.s_addr ||
+#ifdef DAP_OS_BSD
+                l_node_info.hdr.ext_addr_v6.__u6_addr.__u6_addr32[0]
+#else
+                l_node_info.hdr.ext_addr_v6.s6_addr32[0]
+#endif
+            ) {
+                /* Let's check if config was altered */
+                int l_ret = l_node_info_gdb ? memcmp(&l_node_info, l_node_info_gdb, sizeof(dap_chain_node_info_t)) : 1;
+                if (!l_ret) {
+                    log_it(L_NOTICE,"Seed node "NODE_ADDR_FP_STR" already in list", NODE_ADDR_FP_ARGS_S(l_seed_node_addr));
+                } else {
+                    /* Either not yet added or must be altered */
+                    l_ret = dap_chain_node_info_save(l_net, &l_node_info);
+                    if (!l_ret) {
+                        if (dap_chain_node_alias_register(l_net,l_net_pvt->seed_aliases[i], &l_seed_node_addr))
+                            log_it(L_NOTICE,"Seed node "NODE_ADDR_FP_STR" added to the curent list", NODE_ADDR_FP_ARGS_S(l_seed_node_addr));
+                        else
+                            log_it(L_WARNING,"Cant register alias %s for address "NODE_ADDR_FP_STR, l_net_pvt->seed_aliases[i], NODE_ADDR_FP_ARGS_S(l_seed_node_addr));
+                    } else {
+                        log_it(L_WARNING,"Cant save node info for address "NODE_ADDR_FP_STR" return code %d", NODE_ADDR_FP_ARGS_S(l_seed_node_addr), l_ret);
                     }
-                    DAP_DELETE(l_seed_node_addr);
-                }else
-                    log_it(L_WARNING,"No address for seed node, can't populate global_db with it");
-                DAP_DELETE( l_node_info);
-            } else {
-                log_it(L_DEBUG,"Seed alias %s is present", PVT(l_net)->seed_aliases[i]);
-                DAP_DELETE(l_node_info);
-            }
+                }
+            } else
+                log_it(L_WARNING,"No address for seed node, can't populate global_db with it");
+            DAP_DEL_Z(l_seed_node_addr_gdb);
+            DAP_DEL_Z(l_node_info_gdb);
         }
+
         PVT(l_net)->bootstrap_nodes_count = 0;
         PVT(l_net)->bootstrap_nodes_addrs = DAP_NEW_SIZE(struct in_addr, l_bootstrap_nodes_len * sizeof(struct in_addr));
         PVT(l_net)->bootstrap_nodes_ports = DAP_NEW_SIZE(uint16_t, l_bootstrap_nodes_len * sizeof(uint16_t));
@@ -2755,6 +2638,12 @@ int s_net_load(const char * a_net_name, uint16_t a_acl_idx)
             }
             closedir(l_chains_dir);
 
+            // reload ledger cache at once
+            if (s_chain_net_reload_ledger_cache_once(l_net)) {
+                log_it(L_WARNING,"Start one time ledger cache reloading");
+                dap_chain_ledger_purge(l_net->pub.ledger, false);
+            }
+
             // sort list with chains names by priority
             l_prior_list = dap_list_sort(l_prior_list, callback_compare_prioritity_list);
             // load chains by priority
@@ -2766,7 +2655,7 @@ int s_net_load(const char * a_net_name, uint16_t a_acl_idx)
                 l_chain = dap_chain_load_from_cfg(l_net->pub.ledger, l_net->pub.name,
                                                   l_net->pub.id, l_chain_prior->chains_path);
                 if(l_chain) {//add minimum commission from to which the master node agrees. if present (default = 1.0)
-					l_chain->minimum_commission = dap_chain_coins_to_balance(dap_config_get_item_str_default(l_cfg , "general" ,"minimum_commission","1.0"));
+                    l_chain->minimum_commission = dap_chain_coins_to_balance(dap_config_get_item_str_default(l_cfg , "general" ,"minimum_commission","1.0"));
                     DL_APPEND(l_net->pub.chains, l_chain);
                     if(l_chain->callback_created)
                         l_chain->callback_created(l_chain, l_cfg);
@@ -2797,7 +2686,7 @@ int s_net_load(const char * a_net_name, uint16_t a_acl_idx)
                             log_it(L_ERROR, "Please, fix your configs and restart node");
                             return -2;
                         }
-						remove_duplicates_in_chain_by_priority(l_chain, l_chain02);
+                        remove_duplicates_in_chain_by_priority(l_chain, l_chain02);
                     }
                 }
             }
@@ -2814,13 +2703,7 @@ int s_net_load(const char * a_net_name, uint16_t a_acl_idx)
                     }
                 }
             } while (l_processed);
-
-            const char* l_default_chain_name = dap_config_get_item_str(l_cfg , "general" , "default_chain");
-            if(l_default_chain_name)
-                l_net->pub.default_chain = dap_chain_net_get_chain_by_name(l_net, l_default_chain_name);
-            else
-                l_net->pub.default_chain = NULL;
-
+            l_net->pub.native_ticker = dap_strdup(dap_config_get_item_str(l_cfg , "general" , "native_ticker"));
         } else {
             log_it(L_ERROR, "Can't find any chains for network %s", l_net->pub.name);
             l_net_pvt->load_mode = false;
@@ -2854,7 +2737,8 @@ int s_net_load(const char * a_net_name, uint16_t a_acl_idx)
                 char ** l_proc_chains = dap_config_get_array_str(l_cfg,"role-master" , "proc_chains", &l_proc_chains_count );
                 for ( size_t i = 0; i< l_proc_chains_count ; i++){
                     dap_chain_id_t l_chain_id = {{0}};
-                    if(dap_sscanf( l_proc_chains[i], "0x%16"DAP_UINT64_FORMAT_X,  &l_chain_id.uint64) ==1 || dap_scanf("0x%16"DAP_UINT64_FORMAT_x,  &l_chain_id.uint64) == 1){
+                    if (dap_sscanf( l_proc_chains[i], "0x%16"DAP_UINT64_FORMAT_X,  &l_chain_id.uint64) ==1 ||
+                            dap_scanf("0x%16"DAP_UINT64_FORMAT_x,  &l_chain_id.uint64) == 1) {
                         dap_chain_t * l_chain = dap_chain_find_by_id(l_net->pub.id, l_chain_id );
                         if ( l_chain ){
                             l_chain->is_datum_pool_proc = true;
@@ -2884,14 +2768,12 @@ int s_net_load(const char * a_net_name, uint16_t a_acl_idx)
         l_net_pvt->load_mode = false;
         dap_chain_ledger_load_end(l_net->pub.ledger);
 
-        // reload ledger cache at once
-        s_chain_net_reload_ledger_cache_once(l_net);
-
         dap_chain_net_add_gdb_notify_callback(l_net, dap_chain_net_sync_gdb_broadcast, l_net);
         if (l_target_state != l_net_pvt->state_target)
             dap_chain_net_state_go_to(l_net, l_target_state);
 
-        // Start the proc thread
+        uint32_t l_timeout = dap_config_get_item_uint32_default(g_config, "node_client", "timer_update_states", 600);
+        PVT(l_net)->main_timer = dap_interval_timer_create(l_timeout * 1000, s_main_timer_callback, l_net);
         log_it(L_INFO, "Chain network \"%s\" initialized",l_net_item->name);
 
         DAP_DELETE(l_node_addr_str);
@@ -2905,6 +2787,20 @@ int s_net_load(const char * a_net_name, uint16_t a_acl_idx)
  */
 void dap_chain_net_deinit()
 {
+    pthread_rwlock_rdlock(&g_net_items_rwlock);
+    dap_chain_net_item_t *l_current_item, *l_tmp;
+    HASH_ITER(hh, s_net_items, l_current_item, l_tmp) {
+        dap_chain_net_t *l_net = l_current_item->chain_net;
+        dap_chain_net_pvt_t *l_net_pvt = PVT(l_net);
+        dap_interval_timer_delete(l_net_pvt->main_timer);
+        DAP_DEL_Z(l_net_pvt);
+        DAP_DEL_Z(l_net);
+        HASH_DEL(s_net_items, l_current_item);
+        DAP_DEL_Z(l_current_item);
+    }
+    pthread_rwlock_unlock(&g_net_items_rwlock);
+    pthread_rwlock_destroy(&g_net_items_rwlock);
+
 }
 
 dap_chain_net_t **dap_chain_net_list(uint16_t *a_size)
@@ -2974,10 +2870,9 @@ dap_chain_net_t * dap_chain_net_by_id( dap_chain_net_id_t a_id)
  * @param a_id
  * @return
  */
-uint16_t dap_chain_net_acl_idx_by_id(dap_chain_net_id_t a_id)
+uint16_t dap_chain_net_get_acl_idx(dap_chain_net_t *a_net)
 {
-    dap_chain_net_t *l_net = dap_chain_net_by_id(a_id);
-    return l_net ? PVT(l_net)->acl_idx : (uint16_t)-1;
+    return a_net ? PVT(a_net)->acl_idx : (uint16_t)-1;
 }
 
 /**
@@ -3015,15 +2910,16 @@ dap_chain_t * dap_chain_net_get_chain_by_name( dap_chain_net_t * l_net, const ch
  * @param a_datum_type
  * @return
  */
-dap_chain_t * dap_chain_net_get_chain_by_chain_type(dap_chain_net_t * l_net, dap_chain_type_t a_datum_type)
+dap_chain_t *dap_chain_net_get_chain_by_chain_type(dap_chain_net_t *a_net, dap_chain_type_t a_datum_type)
 {
-    dap_chain_t * l_chain;
-
-    if(!l_net)
+    if (!a_net)
         return NULL;
 
-    DL_FOREACH(l_net->pub.chains, l_chain)
-    {
+    dap_chain_t *l_chain = dap_chain_net_get_default_chain_by_chain_type(a_net, a_datum_type);
+    if (l_chain)
+        return l_chain;
+
+    DL_FOREACH(a_net->pub.chains, l_chain) {
         for(int i = 0; i < l_chain->datum_types_count; i++) {
             if(l_chain->datum_types[i] == a_datum_type)
                 return l_chain;
@@ -3037,21 +2933,21 @@ dap_chain_t * dap_chain_net_get_chain_by_chain_type(dap_chain_net_t * l_net, dap
  * @param a_datum_type
  * @return
  */
-dap_chain_t * dap_chain_net_get_default_chain_by_chain_type(dap_chain_net_t * l_net, dap_chain_type_t a_datum_type)
+dap_chain_t * dap_chain_net_get_default_chain_by_chain_type(dap_chain_net_t *a_net, dap_chain_type_t a_datum_type)
 {
-	dap_chain_t * l_chain;
+    dap_chain_t * l_chain;
 
-	if(!l_net)
-		return NULL;
+    if (!a_net)
+        return NULL;
 
-	DL_FOREACH(l_net->pub.chains, l_chain)
-	{
-		for(int i = 0; i < l_chain->default_datum_types_count; i++) {
-			if(l_chain->default_datum_types[i] == a_datum_type)
-				return l_chain;
-		}
-	}
-	return NULL;
+    DL_FOREACH(a_net->pub.chains, l_chain)
+    {
+        for(int i = 0; i < l_chain->default_datum_types_count; i++) {
+            if(l_chain->default_datum_types[i] == a_datum_type)
+                return l_chain;
+        }
+    }
+    return NULL;
 }
 
 /**
@@ -3059,12 +2955,12 @@ dap_chain_t * dap_chain_net_get_default_chain_by_chain_type(dap_chain_net_t * l_
  * @param a_datum_type
  * @return
  */
-char * dap_chain_net_get_gdb_group_mempool_by_chain_type(dap_chain_net_t * l_net, dap_chain_type_t a_datum_type)
+char * dap_chain_net_get_gdb_group_mempool_by_chain_type(dap_chain_net_t *a_net, dap_chain_type_t a_datum_type)
 {
-    dap_chain_t * l_chain;
-    if(!l_net)
+    dap_chain_t *l_chain;
+    if (!a_net)
         return NULL;
-    DL_FOREACH(l_net->pub.chains, l_chain)
+    DL_FOREACH(a_net->pub.chains, l_chain)
     {
         for(int i = 0; i < l_chain->datum_types_count; i++) {
             if(l_chain->datum_types[i] == a_datum_type)
@@ -3309,334 +3205,6 @@ void dap_chain_net_proc_mempool (dap_chain_net_t * a_net)
     }
 }
 
-/**
- * @brief For now it returns all COND_IN transactions
- * @param a_net
- * @param a_srv_uid
- * @param a_search_type
- * @return Hash lists of dap_chain_datum_tx_item_t with conditional transaction and it spending if present
- */
-dap_chain_datum_tx_spends_items_t * dap_chain_net_get_tx_cond_all_with_spends_by_srv_uid(dap_chain_net_t * a_net, const dap_chain_net_srv_uid_t a_srv_uid,
-                                                      const dap_time_t a_time_from, const dap_time_t a_time_to,
-                                                     const dap_chain_net_tx_search_type_t a_search_type)
-{
-    dap_ledger_t * l_ledger = a_net->pub.ledger;
-    dap_chain_datum_tx_spends_items_t * l_ret = DAP_NEW_Z(dap_chain_datum_tx_spends_items_t);
-
-    switch (a_search_type) {
-        case TX_SEARCH_TYPE_NET:
-        case TX_SEARCH_TYPE_CELL:
-        case TX_SEARCH_TYPE_LOCAL:
-        case TX_SEARCH_TYPE_CELL_SPENT:
-        case TX_SEARCH_TYPE_NET_UNSPENT:
-        case TX_SEARCH_TYPE_CELL_UNSPENT:
-        case TX_SEARCH_TYPE_NET_SPENT: {
-            // pass all chains
-            for ( dap_chain_t * l_chain = a_net->pub.chains; l_chain; l_chain = l_chain->next){
-                dap_chain_cell_t * l_cell, *l_cell_tmp;
-                // Go through all cells
-                HASH_ITER(hh,l_chain->cells,l_cell, l_cell_tmp){
-                    dap_chain_atom_iter_t * l_atom_iter = l_chain->callback_atom_iter_create(l_chain,l_cell->id, false  );
-                    // try to find transaction in chain ( inside shard )
-                    size_t l_atom_size = 0;
-                    dap_chain_atom_ptr_t l_atom = l_chain->callback_atom_iter_get_first(l_atom_iter, &l_atom_size);
-
-                    // Check atoms in chain
-                    while(l_atom && l_atom_size) {
-                        size_t l_datums_count = 0;
-                        dap_chain_datum_t **l_datums = l_chain->callback_atom_get_datums(l_atom, l_atom_size, &l_datums_count);
-                        // transaction
-                        dap_chain_datum_tx_t *l_tx = NULL;
-
-                        for (size_t i = 0; i < l_datums_count; i++) {
-                            // Check if its transaction
-                            if (l_datums && (l_datums[i]->header.type_id == DAP_CHAIN_DATUM_TX)) {
-                                l_tx = (dap_chain_datum_tx_t *)l_datums[i]->data;
-                            }
-
-                            // If found TX
-                            if (l_tx){
-                                // Check for time from
-                                if(a_time_from && l_tx->header.ts_created < a_time_from)
-                                        continue;
-
-                                // Check for time to
-                                if(a_time_to && l_tx->header.ts_created > a_time_to)
-                                        continue;
-
-                                if(a_search_type == TX_SEARCH_TYPE_CELL_SPENT || a_search_type == TX_SEARCH_TYPE_NET_SPENT ){
-                                    dap_hash_fast_t * l_tx_hash = dap_chain_node_datum_tx_calc_hash(l_tx);
-                                    bool l_is_spent = dap_chain_ledger_tx_spent_find_by_hash(l_ledger,l_tx_hash);
-                                    DAP_DELETE(l_tx_hash);
-                                    if(!l_is_spent)
-                                        continue;
-                                }
-
-                                // Go through all items
-                                uint32_t l_tx_items_pos = 0, l_tx_items_size = l_tx->header.tx_items_size;
-                                int l_item_idx = 0;
-                                while (l_tx_items_pos < l_tx_items_size) {
-                                    uint8_t *l_item = l_tx->tx_items + l_tx_items_pos;
-                                    int l_item_size = dap_chain_datum_item_tx_get_size(l_item);
-                                    if(!l_item_size)
-                                        break;
-                                    // check type
-                                    dap_chain_tx_item_type_t l_item_type = dap_chain_datum_tx_item_get_type(l_item);
-                                    switch (l_item_type){
-                                        case TX_ITEM_TYPE_IN_COND:{
-                                            dap_chain_tx_in_cond_t * l_tx_in_cond = (dap_chain_tx_in_cond_t *) l_item;
-                                            dap_chain_datum_tx_spends_item_t  *l_tx_prev_out_item = NULL;
-                                            HASH_FIND(hh, l_ret->tx_outs, &l_tx_in_cond->header.tx_prev_hash,sizeof(l_tx_in_cond->header.tx_prev_hash), l_tx_prev_out_item);
-
-                                            if (l_tx_prev_out_item){ // we found previous out_cond with target srv_uid
-                                                dap_chain_datum_tx_spends_item_t *l_item_in = DAP_NEW_Z(dap_chain_datum_tx_spends_item_t);
-                                                size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx);
-                                                dap_chain_datum_tx_t * l_tx_dup = DAP_DUP_SIZE(l_tx,l_tx_size);
-                                                dap_hash_fast(l_tx_dup,l_tx_size, &l_item_in->tx_hash);
-
-                                                l_item_in->tx = l_tx_dup;
-                                                // Calc same offset from tx duplicate
-                                                l_item_in->in_cond = (dap_chain_tx_in_cond_t*) (l_tx_dup->tx_items + l_tx_items_pos);
-                                                HASH_ADD_KEYPTR(hh,l_ret->tx_ins, &l_item_in->tx_hash, sizeof(l_item_in->tx_hash), l_item_in);
-
-                                                // Link previous out with current in
-                                                l_tx_prev_out_item->tx_next = l_tx_dup;
-                                            }
-                                        }break;
-                                        case TX_ITEM_TYPE_OUT_COND:{
-                                            dap_chain_tx_out_cond_t * l_tx_out_cond = (dap_chain_tx_out_cond_t *)l_item;
-                                            if(l_tx_out_cond->header.srv_uid.uint64 == a_srv_uid.uint64){
-                                                dap_chain_datum_tx_spends_item_t * l_item = DAP_NEW_Z(dap_chain_datum_tx_spends_item_t);
-                                                size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx);
-                                                dap_chain_datum_tx_t * l_tx_dup = DAP_DUP_SIZE(l_tx,l_tx_size);
-                                                dap_hash_fast(l_tx,l_tx_size, &l_item->tx_hash);
-                                                l_item->tx = l_tx_dup;
-                                                // Calc same offset from tx duplicate
-                                                l_item->out_cond = (dap_chain_tx_out_cond_t*) (l_tx_dup->tx_items + l_tx_items_pos);
-
-                                                HASH_ADD_KEYPTR(hh,l_ret->tx_outs, &l_item->tx_hash, sizeof(l_item->tx_hash), l_item);
-                                                break; // We're seaching only for one specified OUT_COND output per transaction
-                                            }
-                                        } break;
-                                        default:;
-                                    }
-
-                                    l_tx_items_pos += l_item_size;
-                                    l_item_idx++;
-                                }
-                            }
-                        }
-                        DAP_DEL_Z(l_datums);
-                        // go to next atom
-                        l_atom = l_chain->callback_atom_iter_get_next(l_atom_iter, &l_atom_size);
-
-                    }
-                }
-            }
-        } break;
-
-    }
-    return l_ret;
-
-}
-
-/**
- * @brief dap_chain_datum_tx_spends_items_free
- * @param a_items
- */
-void dap_chain_datum_tx_spends_items_free(dap_chain_datum_tx_spends_items_t * a_items)
-{
-    assert(a_items);
-    dap_chain_datum_tx_spends_item_free(a_items->tx_ins);
-    dap_chain_datum_tx_spends_item_free(a_items->tx_outs);
-    DAP_DELETE(a_items);
-}
-
-/**
- * @brief dap_chain_datum_tx_spends_item_free
- * @param a_items
- */
-void dap_chain_datum_tx_spends_item_free(dap_chain_datum_tx_spends_item_t * a_items)
-{
-    dap_chain_datum_tx_spends_item_t * l_item, *l_tmp;
-    HASH_ITER(hh,a_items,l_item,l_tmp){
-        DAP_DELETE(l_item->tx);
-        HASH_DELETE(hh,a_items, l_item);
-        DAP_DELETE(l_item);
-    }
-}
-
-/**
- * @brief dap_chain_net_get_tx_cond_all_by_srv_uid
- * @param a_net
- * @param a_srv_uid
- * @param a_search_type
- * @return
- */
-dap_list_t * dap_chain_net_get_tx_cond_all_by_srv_uid(dap_chain_net_t * a_net, const dap_chain_net_srv_uid_t a_srv_uid,
-                                                      const dap_time_t a_time_from, const dap_time_t a_time_to,
-                                                     const dap_chain_net_tx_search_type_t a_search_type)
-{
-    dap_ledger_t * l_ledger = a_net->pub.ledger;
-    dap_list_t * l_ret = NULL;
-
-    switch (a_search_type) {
-        case TX_SEARCH_TYPE_NET:
-        case TX_SEARCH_TYPE_CELL:
-        case TX_SEARCH_TYPE_LOCAL:
-        case TX_SEARCH_TYPE_CELL_SPENT:
-        case TX_SEARCH_TYPE_NET_SPENT: {
-            // pass all chains
-            for ( dap_chain_t * l_chain = a_net->pub.chains; l_chain; l_chain = l_chain->next){
-                dap_chain_cell_t * l_cell, *l_cell_tmp;
-                // Go through all cells
-                HASH_ITER(hh,l_chain->cells,l_cell, l_cell_tmp){
-                    dap_chain_atom_iter_t * l_atom_iter = l_chain->callback_atom_iter_create(l_chain,l_cell->id, false  );
-                    // try to find transaction in chain ( inside shard )
-                    size_t l_atom_size = 0;
-                    dap_chain_atom_ptr_t l_atom = l_chain->callback_atom_iter_get_first(l_atom_iter, &l_atom_size);
-
-                    // Check atoms in chain
-                    while(l_atom && l_atom_size) {
-                        dap_chain_datum_t *l_datum = (dap_chain_datum_t*) l_atom;
-                        // transaction
-                        dap_chain_datum_tx_t *l_tx = NULL;
-
-                        // Check if its transaction
-                        if ( l_datum && (l_datum->header.type_id == DAP_CHAIN_DATUM_TX)) {
-                            l_tx = (dap_chain_datum_tx_t*) l_datum->data;
-                        }
-
-                        // If found TX
-                        if (l_tx){
-                            // Check for time from
-                            if(a_time_from && l_tx->header.ts_created < a_time_from)
-                                    continue;
-
-                            // Check for time to
-                            if(a_time_to && l_tx->header.ts_created > a_time_to)
-                                    continue;
-
-                            if(a_search_type == TX_SEARCH_TYPE_CELL_SPENT || a_search_type == TX_SEARCH_TYPE_NET_SPENT ){
-                                dap_hash_fast_t * l_tx_hash = dap_chain_node_datum_tx_calc_hash(l_tx);
-                                bool l_is_spent = dap_chain_ledger_tx_spent_find_by_hash(l_ledger,l_tx_hash);
-                                DAP_DELETE(l_tx_hash);
-                                if(!l_is_spent)
-                                    continue;
-                            }
-                            // Check for OUT_COND items
-                            dap_list_t *l_list_out_cond_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT_COND , NULL);
-                            if(l_list_out_cond_items){
-                                dap_list_t *l_list_cur = l_list_out_cond_items;
-                                while(l_list_cur){ // Go through all cond items
-                                    l_list_cur = dap_list_next(l_list_cur);
-                                    dap_chain_tx_out_cond_t * l_tx_out_cond = (dap_chain_tx_out_cond_t *)l_list_cur->data;
-                                    if(l_tx_out_cond) // If we found cond out with target srv_uid
-                                        if(l_tx_out_cond->header.srv_uid.uint64 == a_srv_uid.uint64)
-                                            l_ret = dap_list_append(l_ret,l_tx);
-                                }
-                                dap_list_free(l_list_out_cond_items);
-                            }
-                        }
-
-                        // go to next atom
-                        l_atom = l_chain->callback_atom_iter_get_next(l_atom_iter, &l_atom_size);
-
-                    }
-                }
-            }
-        } break;
-
-        case TX_SEARCH_TYPE_NET_UNSPENT:
-        case TX_SEARCH_TYPE_CELL_UNSPENT:
-            l_ret = dap_chain_ledger_tx_cache_find_out_cond_all(l_ledger, a_srv_uid);
-            break;
-    }
-    return l_ret;
-
-}
-
-/**
- * @brief Summarize all tx inputs
- * @param a_net
- * @param a_tx
- * @return
- */
-uint256_t dap_chain_net_get_tx_total_value(dap_chain_net_t * a_net, dap_chain_datum_tx_t * a_tx)
-{
-    uint256_t l_ret = {0};
-    int l_item_idx = 0;
-    dap_chain_tx_in_t *l_in_item = NULL;
-    do {
-        l_in_item = (dap_chain_tx_in_t*) dap_chain_datum_tx_item_get(a_tx, &l_item_idx, TX_ITEM_TYPE_IN , NULL);
-        l_item_idx++;
-        if(l_in_item ) {
-            //const char *token = l_out_cond_item->subtype.srv_xchange.token;
-            dap_chain_datum_tx_t * l_tx_prev = dap_chain_net_get_tx_by_hash(a_net,&l_in_item->header.tx_prev_hash, TX_SEARCH_TYPE_NET_SPENT);
-            if(l_tx_prev){
-                int l_tx_prev_out_index = l_in_item->header.tx_out_prev_idx;
-                dap_chain_tx_out_t *  l_tx_prev_out =(dap_chain_tx_out_t *)
-                        dap_chain_datum_tx_item_get(l_tx_prev,&l_tx_prev_out_index, TX_ITEM_TYPE_OUT,NULL);
-                if( l_tx_prev_out_index == (int) l_in_item->header.tx_out_prev_idx && l_tx_prev_out){
-                    uint256_t l_in_value = l_tx_prev_out->header.value;
-                    if(SUM_256_256(l_in_value,l_ret, &l_ret )!= 0)
-                        log_it(L_ERROR, "Overflow on inputs values calculation (summing)");
-                }else{
-                    log_it(L_WARNING, "Can't find item with index %d in prev tx hash", l_tx_prev_out_index);
-                }
-            }else
-                log_it(L_WARNING, "Can't find prev tx hash");
-        }
-    } while(l_in_item);
-    return l_ret;
-}
-
-/**
- * @brief dap_chain_net_tx_get_by_hash
- * @param a_net
- * @param a_tx_hash
- * @param a_search_type
- * @return
- */
-dap_chain_datum_tx_t * dap_chain_net_get_tx_by_hash(dap_chain_net_t * a_net, dap_chain_hash_fast_t * a_tx_hash,
-                                                     dap_chain_net_tx_search_type_t a_search_type)
-{
-    dap_ledger_t * l_ledger = a_net->pub.ledger;
-    dap_chain_datum_tx_t * l_tx = NULL;
-
-    switch (a_search_type) {
-        case TX_SEARCH_TYPE_NET:
-        case TX_SEARCH_TYPE_CELL:
-        case TX_SEARCH_TYPE_LOCAL:
-        case TX_SEARCH_TYPE_CELL_SPENT:
-        case TX_SEARCH_TYPE_NET_SPENT: {
-
-            if ( ! l_tx ){
-                // pass all chains
-                for ( dap_chain_t * l_chain = a_net->pub.chains; l_chain; l_chain = l_chain->next){
-                    if ( l_chain->callback_tx_find_by_hash ){
-                        // try to find transaction in chain ( inside shard )
-                        l_tx = l_chain->callback_tx_find_by_hash(l_chain, a_tx_hash);
-                        if (l_tx) {
-                            if ((a_search_type == TX_SEARCH_TYPE_CELL_SPENT ||
-                                    a_search_type == TX_SEARCH_TYPE_NET_SPENT) &&
-                                    (!dap_chain_ledger_tx_spent_find_by_hash(l_ledger, a_tx_hash)))
-                                return NULL;
-                            break;
-                        }
-                    }
-                }
-            }
-        } break;
-
-        case TX_SEARCH_TYPE_NET_UNSPENT:
-        case TX_SEARCH_TYPE_CELL_UNSPENT:
-            l_tx = dap_chain_ledger_tx_find_by_hash(l_ledger, a_tx_hash);
-            break;
-    }
-    return l_tx;
-}
-
 /**
  * @brief dap_chain_net_get_extra_gdb_group
  * @param a_net
@@ -3747,6 +3315,7 @@ static bool s_net_check_acl(dap_chain_net_t *a_net, dap_chain_hash_fast_t *a_pke
             }
         }
     }
+    dap_config_close(l_cfg);
     return l_authorized;
 }
 
@@ -3756,7 +3325,7 @@ static bool s_net_check_acl(dap_chain_net_t *a_net, dap_chain_hash_fast_t *a_pke
  * @param a_pkey_hash dap_chain_hash_fast_t hash object
  * @return uint8_t*
  */
-static uint8_t *dap_chain_net_set_acl(dap_chain_hash_fast_t *a_pkey_hash)
+static uint8_t *s_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);
@@ -3779,9 +3348,9 @@ static uint8_t *dap_chain_net_set_acl(dap_chain_hash_fast_t *a_pkey_hash)
  * @param a_filter_func
  * @param a_filter_func_param
  */
-dap_list_t* dap_chain_datum_list(dap_chain_net_t *a_net, dap_chain_t *a_chain, datum_filter_func_t *a_filter_func, void *a_filter_func_param)
+dap_list_t* dap_chain_datum_list(dap_chain_net_t *a_net, dap_chain_t *a_chain, dap_chain_datum_filter_func_t *a_filter_func, void *a_filter_func_param)
 {
-    dap_list_t *l_list = NULL;  
+    dap_list_t *l_list = NULL;
     if(!a_net)
 //        return l_list;
 //    void *l_chain_tmp = (void*) 0x1;
@@ -3855,21 +3424,20 @@ dap_list_t* dap_chain_datum_list(dap_chain_net_t *a_net, dap_chain_t *a_chain, d
  * @param a_datum_size
  * @return
  */
-int dap_chain_datum_add(dap_chain_t * a_chain, dap_chain_datum_t *a_datum, size_t a_datum_size  )
+int dap_chain_datum_add(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, size_t a_datum_size, dap_hash_fast_t *a_tx_hash)
 {
     size_t l_datum_data_size = a_datum->header.data_size;
     if ( a_datum_size < l_datum_data_size+ sizeof (a_datum->header) ){
         log_it(L_INFO,"Corrupted datum rejected: wrong size %zd not equel or less datum size %zd",a_datum->header.data_size+ sizeof (a_datum->header),
                a_datum_size );
-        return -1;
+        return -101;
     }
     switch (a_datum->header.type_id) {
         case DAP_CHAIN_DATUM_DECREE:{
             dap_chain_datum_decree_t * l_decree = (dap_chain_datum_decree_t *) a_datum->data;
             if( sizeof(l_decree->header)> l_datum_data_size  ){
-                log_it(L_WARNING, "Corrupted decree, size %zd is smaller than ever decree header's size %zd", l_datum_data_size,
-                       sizeof(l_decree->header));
-                break;
+                log_it(L_WARNING, "Corrupted decree, size %zd is smaller than ever decree header's size %zd", l_datum_data_size, sizeof(l_decree->header));
+                return -102;
             }
 
 
@@ -3883,42 +3451,34 @@ int dap_chain_datum_add(dap_chain_t * a_chain, dap_chain_datum_t *a_datum, size_
                          }
                     }else{
                         log_it(L_WARNING,"Decree for unknown srv uid 0x%016"DAP_UINT64_FORMAT_X , l_decree->header.srv_id.uint64);
+                        return -103;
                     }
-                }break;
+                }
                 default:;
             }
-        }break;
+        } break;
+
+        case DAP_CHAIN_DATUM_TOKEN_DECL:
+            return dap_chain_ledger_token_load(a_chain->ledger, (dap_chain_datum_token_t *)a_datum->data, a_datum->header.data_size);
+
+        case DAP_CHAIN_DATUM_TOKEN_EMISSION:
+            return dap_chain_ledger_token_emission_load(a_chain->ledger, a_datum->data, a_datum->header.data_size);
 
-        case DAP_CHAIN_DATUM_TOKEN_DECL:{
-            if (dap_chain_ledger_token_load(a_chain->ledger, (dap_chain_datum_token_t *)a_datum->data, a_datum->header.data_size))
-                return -2;
-        }break;
-        case DAP_CHAIN_DATUM_TOKEN_EMISSION: {
-            if (dap_chain_ledger_token_emission_load(a_chain->ledger, a_datum->data, a_datum->header.data_size))
-                return -3;
-        }break;
         case DAP_CHAIN_DATUM_TX:{
             dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t*) a_datum->data;
             // Check tx correcntess
-            size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx);
-            if (l_tx_size > l_datum_data_size  ){
-                log_it(L_WARNING, "Corrupted transaction in datum, size %zd is greater than datum's size %zd", l_tx_size, l_datum_data_size);
-                return -1;
-            }
+            int res = dap_chain_ledger_tx_load(a_chain->ledger, l_tx, a_tx_hash);
+            return res == 1 ? 0 : res;
+        }
+
+        case DAP_CHAIN_DATUM_CA:
+            return dap_cert_chain_file_save(a_datum, a_chain->net_name);
 
-            // TODO process with different codes from ledger to work with ledger thresholds
-            if (dap_chain_ledger_tx_load(a_chain->ledger, l_tx, NULL) != 1)
-                return -4;
-        }break;
-        case DAP_CHAIN_DATUM_CA:{
 
-            if (dap_cert_chain_file_save(a_datum, a_chain->net_name) < 0)
-                return -5;
-        }break;
         case DAP_CHAIN_DATUM_SIGNER:
-        break;
+            break;
         case DAP_CHAIN_DATUM_CUSTOM:
-        break;
+            break;
         default:
             return -666;
     }
diff --git a/modules/net/dap_chain_net_tx.c b/modules/net/dap_chain_net_tx.c
new file mode 100644
index 0000000000000000000000000000000000000000..95e0c9c44f8c46ffe6b4d724f17381dc09f71d24
--- /dev/null
+++ b/modules/net/dap_chain_net_tx.c
@@ -0,0 +1,635 @@
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * Cellframe Network https://cellframe.net
+ * Copyright  (c) 2022
+ * All rights reserved.
+
+ This file is part of DAP (Deus Applications Prototypes) the open source project
+
+    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    DAP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string.h>
+#include "dap_chain_net_tx.h"
+#include "dap_chain_cell.h"
+#include "dap_chain_common.h"
+#include "dap_chain_datum_tx_in_cond.h"
+#include "dap_chain_tx.h"
+#include "dap_list.h"
+
+#define LOG_TAG "dap_chain_net_tx"
+
+/**
+ * @brief For now it returns all COND_IN transactions
+ * @param a_net
+ * @param a_srv_uid
+ * @param a_search_type
+ * @return Hash lists of dap_chain_datum_tx_item_t with conditional transaction and it spending if present
+ */
+dap_chain_datum_tx_spends_items_t * dap_chain_net_get_tx_cond_all_with_spends_by_srv_uid(dap_chain_net_t * a_net, const dap_chain_net_srv_uid_t a_srv_uid,
+                                                      const dap_time_t a_time_from, const dap_time_t a_time_to,
+                                                     const dap_chain_net_tx_search_type_t a_search_type)
+{
+    dap_ledger_t * l_ledger = a_net->pub.ledger;
+    dap_chain_datum_tx_spends_items_t * l_ret = DAP_NEW_Z(dap_chain_datum_tx_spends_items_t);
+
+    switch (a_search_type) {
+        case TX_SEARCH_TYPE_NET:
+        case TX_SEARCH_TYPE_CELL:
+        case TX_SEARCH_TYPE_LOCAL:
+        case TX_SEARCH_TYPE_CELL_SPENT:
+        case TX_SEARCH_TYPE_NET_UNSPENT:
+        case TX_SEARCH_TYPE_CELL_UNSPENT:
+        case TX_SEARCH_TYPE_NET_SPENT: {
+            // pass all chains
+            for ( dap_chain_t * l_chain = a_net->pub.chains; l_chain; l_chain = l_chain->next){
+                dap_chain_cell_t * l_cell, *l_cell_tmp;
+                // Go through all cells
+                HASH_ITER(hh,l_chain->cells,l_cell, l_cell_tmp){
+                    dap_chain_atom_iter_t * l_atom_iter = l_chain->callback_atom_iter_create(l_chain,l_cell->id, false  );
+                    // try to find transaction in chain ( inside shard )
+                    size_t l_atom_size = 0;
+                    dap_chain_atom_ptr_t l_atom = l_chain->callback_atom_iter_get_first(l_atom_iter, &l_atom_size);
+
+                    // Check atoms in chain
+                    while(l_atom && l_atom_size) {
+                        size_t l_datums_count = 0;
+                        dap_chain_datum_t **l_datums = l_chain->callback_atom_get_datums(l_atom, l_atom_size, &l_datums_count);
+                        // transaction
+                        dap_chain_datum_tx_t *l_tx = NULL;
+
+                        for (size_t i = 0; i < l_datums_count; i++) {
+                            // Check if its transaction
+                            if (l_datums && (l_datums[i]->header.type_id == DAP_CHAIN_DATUM_TX)) {
+                                l_tx = (dap_chain_datum_tx_t *)l_datums[i]->data;
+                            }
+
+                            // If found TX
+                            if (l_tx){
+                                // Check for time from
+                                if(a_time_from && l_tx->header.ts_created < a_time_from)
+                                        continue;
+
+                                // Check for time to
+                                if(a_time_to && l_tx->header.ts_created > a_time_to)
+                                        continue;
+
+                                if(a_search_type == TX_SEARCH_TYPE_CELL_SPENT || a_search_type == TX_SEARCH_TYPE_NET_SPENT ){
+                                    dap_hash_fast_t * l_tx_hash = dap_chain_node_datum_tx_calc_hash(l_tx);
+                                    bool l_is_spent = dap_chain_ledger_tx_spent_find_by_hash(l_ledger,l_tx_hash);
+                                    DAP_DELETE(l_tx_hash);
+                                    if(!l_is_spent)
+                                        continue;
+                                }
+
+                                // Go through all items
+                                uint32_t l_tx_items_pos = 0, l_tx_items_size = l_tx->header.tx_items_size;
+                                int l_item_idx = 0;
+                                while (l_tx_items_pos < l_tx_items_size) {
+                                    uint8_t *l_item = l_tx->tx_items + l_tx_items_pos;
+                                    int l_item_size = dap_chain_datum_item_tx_get_size(l_item);
+                                    if(!l_item_size)
+                                        break;
+                                    // check type
+                                    dap_chain_tx_item_type_t l_item_type = dap_chain_datum_tx_item_get_type(l_item);
+                                    switch (l_item_type){
+                                        case TX_ITEM_TYPE_IN_COND:{
+                                            dap_chain_tx_in_cond_t * l_tx_in_cond = (dap_chain_tx_in_cond_t *) l_item;
+                                            dap_chain_datum_tx_spends_item_t  *l_tx_prev_out_item = NULL;
+                                            HASH_FIND(hh, l_ret->tx_outs, &l_tx_in_cond->header.tx_prev_hash,sizeof(l_tx_in_cond->header.tx_prev_hash), l_tx_prev_out_item);
+
+                                            if (l_tx_prev_out_item){ // we found previous out_cond with target srv_uid
+                                                dap_chain_datum_tx_spends_item_t *l_item_in = DAP_NEW_Z(dap_chain_datum_tx_spends_item_t);
+                                                size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx);
+                                                dap_chain_datum_tx_t * l_tx_dup = DAP_DUP_SIZE(l_tx,l_tx_size);
+                                                dap_hash_fast(l_tx_dup,l_tx_size, &l_item_in->tx_hash);
+
+                                                l_item_in->tx = l_tx_dup;
+                                                // Calc same offset from tx duplicate
+                                                l_item_in->in_cond = (dap_chain_tx_in_cond_t*) (l_tx_dup->tx_items + l_tx_items_pos);
+                                                HASH_ADD(hh,l_ret->tx_ins, tx_hash, sizeof(dap_chain_hash_fast_t), l_item_in);
+
+                                                // Link previous out with current in
+                                                l_tx_prev_out_item->tx_next = l_tx_dup;
+                                            }
+                                        }break;
+                                        case TX_ITEM_TYPE_OUT_COND:{
+                                            dap_chain_tx_out_cond_t * l_tx_out_cond = (dap_chain_tx_out_cond_t *)l_item;
+                                            if(l_tx_out_cond->header.srv_uid.uint64 == a_srv_uid.uint64){
+                                                dap_chain_datum_tx_spends_item_t * l_item = DAP_NEW_Z(dap_chain_datum_tx_spends_item_t);
+                                                size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx);
+                                                dap_chain_datum_tx_t * l_tx_dup = DAP_DUP_SIZE(l_tx,l_tx_size);
+                                                dap_hash_fast(l_tx,l_tx_size, &l_item->tx_hash);
+                                                l_item->tx = l_tx_dup;
+                                                // Calc same offset from tx duplicate
+                                                l_item->out_cond = (dap_chain_tx_out_cond_t*) (l_tx_dup->tx_items + l_tx_items_pos);
+
+                                                HASH_ADD(hh,l_ret->tx_outs, tx_hash, sizeof(dap_chain_hash_fast_t), l_item);
+                                                break; // We're seaching only for one specified OUT_COND output per transaction
+                                            }
+                                        } break;
+                                        default:;
+                                    }
+
+                                    l_tx_items_pos += l_item_size;
+                                    l_item_idx++;
+                                }
+                            }
+                        }
+                        DAP_DEL_Z(l_datums);
+                        // go to next atom
+                        l_atom = l_chain->callback_atom_iter_get_next(l_atom_iter, &l_atom_size);
+
+                    }
+                }
+            }
+        } break;
+
+    }
+    return l_ret;
+
+}
+
+/**
+ * @brief dap_chain_datum_tx_spends_items_free
+ * @param a_items
+ */
+void dap_chain_datum_tx_spends_items_free(dap_chain_datum_tx_spends_items_t * a_items)
+{
+    assert(a_items);
+    dap_chain_datum_tx_spends_item_free(a_items->tx_ins);
+    dap_chain_datum_tx_spends_item_free(a_items->tx_outs);
+    DAP_DELETE(a_items);
+}
+
+/**
+ * @brief dap_chain_datum_tx_spends_item_free
+ * @param a_items
+ */
+void dap_chain_datum_tx_spends_item_free(dap_chain_datum_tx_spends_item_t * a_items)
+{
+    dap_chain_datum_tx_spends_item_t * l_item, *l_tmp;
+    HASH_ITER(hh,a_items,l_item,l_tmp){
+        DAP_DELETE(l_item->tx);
+        HASH_DELETE(hh,a_items, l_item);
+        DAP_DELETE(l_item);
+    }
+}
+
+/**
+ * @brief dap_chain_net_get_tx_all
+ * @param a_net
+ * @param a_search_type
+ * @param a_tx_callback
+ * @param a_arg
+ */
+void dap_chain_net_get_tx_all(dap_chain_net_t * a_net, dap_chain_net_tx_search_type_t a_search_type ,dap_chain_net_tx_hash_callback_t a_tx_callback, void * a_arg)
+{
+    assert(a_tx_callback);
+    switch (a_search_type) {
+        case TX_SEARCH_TYPE_NET_UNSPENT:
+        case TX_SEARCH_TYPE_CELL_UNSPENT:
+        case TX_SEARCH_TYPE_NET:
+        case TX_SEARCH_TYPE_CELL:
+        case TX_SEARCH_TYPE_LOCAL:
+        case TX_SEARCH_TYPE_CELL_SPENT:
+        case TX_SEARCH_TYPE_NET_SPENT: {
+            // pass all chains
+            for ( dap_chain_t * l_chain = a_net->pub.chains; l_chain; l_chain = l_chain->next){
+                dap_chain_cell_t * l_cell, *l_cell_tmp;
+                // Go through all cells
+                HASH_ITER(hh,l_chain->cells,l_cell, l_cell_tmp){
+                    dap_chain_atom_iter_t * l_atom_iter = l_chain->callback_atom_iter_create(l_chain,l_cell->id, false  );
+                    // try to find transaction in chain ( inside shard )
+                    size_t l_atom_size = 0;
+                    dap_chain_atom_ptr_t l_atom = l_chain->callback_atom_iter_get_first(l_atom_iter, &l_atom_size);
+
+                    // Check atoms in chain
+                    while(l_atom && l_atom_size) {
+                        size_t l_datums_count = 0;
+                        dap_chain_datum_t **l_datums = l_chain->callback_atom_get_datums(l_atom, l_atom_size, &l_datums_count);
+                        // transaction
+                        dap_chain_datum_tx_t *l_tx = NULL;
+
+                        for (size_t i = 0; i < l_datums_count; i++) {
+                            // Check if its transaction
+                            if (l_datums && (l_datums[i]->header.type_id == DAP_CHAIN_DATUM_TX)) {
+                                l_tx = (dap_chain_datum_tx_t *) l_datums[i]->data;
+                            }
+
+                            // If found TX
+                            if ( l_tx ) {
+                                a_tx_callback(a_net, l_tx, a_arg);
+                            }
+                        }
+                        DAP_DEL_Z(l_datums);
+                        // go to next atom
+                        l_atom = l_chain->callback_atom_iter_get_next(l_atom_iter, &l_atom_size);
+                    }
+                }
+            }
+        } break;
+
+    }
+}
+
+/**
+ * @brief The get_tx_cond_all_from_tx struct
+ */
+struct get_tx_cond_all_from_tx
+{
+    dap_list_t * ret;
+    dap_hash_fast_t * tx_begin_hash;
+    dap_chain_datum_tx_t * tx_last;
+    dap_hash_fast_t tx_last_hash;
+    int tx_last_cond_idx;
+    dap_chain_net_srv_uid_t srv_uid;
+};
+
+/**
+ * @brief s_get_tx_cond_all_from_tx_callback
+ * @param a_net
+ * @param a_tx
+ * @param a_arg
+ */
+static void s_get_tx_cond_chain_callback(dap_chain_net_t* a_net, dap_chain_datum_tx_t *a_tx, void *a_arg)
+{
+    struct get_tx_cond_all_from_tx * l_args = (struct get_tx_cond_all_from_tx* ) a_arg;
+    dap_hash_fast_t * l_tx_hash = dap_chain_node_datum_tx_calc_hash(a_tx);
+    if( l_args->ret ){
+        int l_item_idx = 0;
+        byte_t *l_tx_item;
+
+        // Get items from transaction
+        while ((l_tx_item = dap_chain_datum_tx_item_get(a_tx, &l_item_idx, TX_ITEM_TYPE_IN_COND , NULL)) != NULL){
+            dap_chain_tx_in_cond_t * l_in_cond = (dap_chain_tx_in_cond_t *) l_tx_item;
+            if(dap_hash_fast_compare(&l_in_cond->header.tx_prev_hash, &l_args->tx_last_hash) &&
+                    (uint32_t)l_args->tx_last_cond_idx == l_in_cond->header.tx_out_prev_idx ){ // Found output
+                // We're the next tx in tx cond chain
+                l_args->ret = dap_list_append(l_args->ret, a_tx);
+            }
+            l_item_idx++;
+        }
+    }else if(dap_hash_fast_compare(l_tx_hash,l_args->tx_begin_hash)){
+        // Found condition
+        int l_item_idx = 0;
+        byte_t *l_tx_item;
+
+        // Get items from transaction
+        while ((l_tx_item = dap_chain_datum_tx_item_get(a_tx, &l_item_idx, TX_ITEM_TYPE_OUT_COND , NULL)) != NULL){
+            dap_chain_tx_out_cond_t * l_out_cond = (dap_chain_tx_out_cond_t *) l_tx_item;
+            if ( l_out_cond->header.srv_uid.uint64 == l_args->srv_uid.uint64 ){ // We found output with target service uuid
+                l_args->tx_last = a_tx; // Record current transaction as the last in tx chain
+                memcpy(&l_args->tx_last_hash, l_tx_hash, sizeof(*l_tx_hash)); // Record current hash
+                l_args->tx_last_cond_idx = l_item_idx;
+                l_args->ret = dap_list_append(NULL, a_tx);
+                break;
+            }
+        }
+    }
+    DAP_DELETE(l_tx_hash);
+}
+
+/**
+ * @brief Return spends chain for conditioned transaction since beginning one
+ * @param a_net Network where to search for
+ * @param l_tx_hash TX hash of the Tx chain beginning
+ * @param a_srv_uid Service UID from witch cond output the chain begin
+ * @return List of conditioned transactions followin each other one by one as they do as spends
+ */
+dap_list_t * dap_chain_net_get_tx_cond_chain(dap_chain_net_t * a_net, dap_hash_fast_t * a_tx_hash, dap_chain_net_srv_uid_t a_srv_uid)
+{
+    struct get_tx_cond_all_from_tx * l_args = DAP_NEW_Z(struct get_tx_cond_all_from_tx);
+    l_args->tx_begin_hash = a_tx_hash;
+    l_args->srv_uid = a_srv_uid;
+    dap_chain_net_get_tx_all(a_net,TX_SEARCH_TYPE_NET,s_get_tx_cond_chain_callback, l_args);
+    dap_list_t * l_ret = l_args->ret;
+    DAP_DELETE(l_args);
+    return l_ret;
+}
+
+/**
+ * @brief The get_tx_cond_all_for_addr struct
+ */
+struct get_tx_cond_all_for_addr
+{
+    dap_list_t * ret;
+    dap_chain_tx_t * tx_all_hh; // Transactions hash table for target address
+    const dap_chain_addr_t * addr;
+    dap_chain_net_srv_uid_t srv_uid;
+};
+
+/**
+ * @brief s_get_tx_cond_all_for_addr_callback
+ * @param a_net
+ * @param a_tx
+ * @param a_arg
+ */
+static void s_get_tx_cond_all_for_addr_callback(dap_chain_net_t* a_net, dap_chain_datum_tx_t *a_datum_tx, void *a_arg)
+{
+    struct get_tx_cond_all_for_addr * l_args = (struct get_tx_cond_all_for_addr* ) a_arg;
+    int l_item_idx = 0;
+    dap_chain_datum_tx_item_t *l_tx_item;
+    bool l_tx_for_addr = false; // TX with output related with our address
+    bool l_tx_from_addr = false; // TX with input that take assets from our address
+    //const char *l_tx_from_addr_token = NULL;
+    bool l_tx_collected = false;  // We already collected this TX in return list
+
+    // Get in items to detect is in or in_cond from target address
+    while ((l_tx_item = (dap_chain_datum_tx_item_t *) dap_chain_datum_tx_item_get(a_datum_tx, &l_item_idx, TX_ITEM_TYPE_ANY , NULL)) != NULL){
+        switch (l_tx_item->type){
+            case TX_ITEM_TYPE_IN:{
+                dap_chain_tx_in_t * l_in = (dap_chain_tx_in_t *) l_tx_item;
+                if( l_tx_from_addr) // Already detected thats spends from addr
+                    break;
+                dap_chain_tx_t * l_tx = dap_chain_tx_hh_find( l_args->tx_all_hh, &l_in->header.tx_prev_hash);
+                if( l_tx ){ // Its input thats closing output for target address - we note it
+                    l_tx_from_addr = true;
+                    //l_tx_from_addr_token = dap_chain_ledger_tx_get_token_ticker_by_hash(a_net->pub.ledger, &l_tx->hash);
+                }
+            }break;
+            case TX_ITEM_TYPE_IN_COND:{
+                if(l_tx_collected) // Already collected
+                    break;
+                dap_chain_tx_in_cond_t * l_in_cond = (dap_chain_tx_in_cond_t *) l_tx_item;
+                dap_chain_tx_t * l_tx = dap_chain_tx_hh_find( l_args->tx_all_hh, &l_in_cond->header.tx_prev_hash);
+                if( l_tx ){ // Its input thats closing conditioned tx related with target address, collect it
+                    //dap_chain_tx_t *l_tx_add = dap_chain_tx_wrap_packed(a_datum_tx);
+                    l_args->ret = dap_list_append(l_args->ret, a_datum_tx);
+                    l_tx_collected = true;
+                }
+            }break;
+        }
+        l_item_idx++;
+    }
+
+    // Get out items from transaction
+    while ((l_tx_item = (dap_chain_datum_tx_item_t *) dap_chain_datum_tx_item_get(a_datum_tx, &l_item_idx, TX_ITEM_TYPE_OUT_ALL , NULL)) != NULL){
+        switch (l_tx_item->type){
+            case TX_ITEM_TYPE_OUT:{
+                if(l_tx_for_addr) // Its already added
+                    break;
+                dap_chain_tx_out_t * l_out = (dap_chain_tx_out_t*) l_tx_item;
+                if ( memcmp(&l_out->addr, l_args->addr, sizeof(*l_args->addr)) == 0){ // Its our address tx
+                    dap_chain_tx_t * l_tx = dap_chain_tx_wrap_packed(a_datum_tx);
+                    dap_chain_tx_hh_add(l_args->tx_all_hh, l_tx);
+                    l_tx_for_addr = true;
+                }
+            }break;
+            case TX_ITEM_TYPE_OUT_EXT:{
+                if(l_tx_for_addr) // Its already added
+                    break;
+                dap_chain_tx_out_ext_t * l_out = (dap_chain_tx_out_ext_t*) l_tx_item;
+                if ( memcmp(&l_out->addr, l_args->addr, sizeof(*l_args->addr)) == 0){ // Its our address tx
+                    dap_chain_tx_t * l_tx = dap_chain_tx_wrap_packed(a_datum_tx);
+                    dap_chain_tx_hh_add(l_args->tx_all_hh, l_tx);
+                    l_tx_for_addr = true;
+                }
+            }break;
+            case TX_ITEM_TYPE_OUT_COND:{
+                dap_chain_tx_out_cond_t * l_out_cond = (dap_chain_tx_out_cond_t*) l_tx_item;
+                if(l_tx_collected) // Already collected for return list
+                    break;
+
+                // If this output spends monies from our address
+                if(l_tx_from_addr && l_out_cond->header.srv_uid.uint64 == l_args->srv_uid.uint64){
+                    //dap_chain_tx_t *l_tx_add = dap_chain_tx_wrap_packed(a_datum_tx);
+                    l_args->ret = dap_list_append(l_args->ret, a_datum_tx);
+                    l_tx_collected = true;
+                }
+            } break;
+        }
+        l_item_idx++;
+    }
+
+}
+
+/**
+ * @brief Compose list of all cond transactions with target srv_uid for specified address
+ * @param a_net
+ * @param a_addr
+ * @param a_srv_uid
+ * @return List of dap_chain_tx_t (don't forget to free it)
+ */
+dap_list_t * dap_chain_net_get_tx_cond_all_for_addr(dap_chain_net_t * a_net, dap_chain_addr_t * a_addr, dap_chain_net_srv_uid_t a_srv_uid)
+{
+    struct get_tx_cond_all_for_addr * l_args = DAP_NEW_Z(struct get_tx_cond_all_for_addr);
+    l_args->addr = a_addr;
+    l_args->srv_uid = a_srv_uid;
+    dap_chain_net_get_tx_all(a_net,TX_SEARCH_TYPE_NET,s_get_tx_cond_all_for_addr_callback, l_args);
+    dap_chain_tx_hh_free(l_args->tx_all_hh);
+    dap_list_t * l_ret = l_args->ret;
+    DAP_DELETE(l_args);
+    return l_ret;
+}
+
+/**
+ * @brief dap_chain_net_get_tx_cond_all_by_srv_uid
+ * @param a_net
+ * @param a_srv_uid
+ * @param a_search_type
+ * @return
+ */
+dap_list_t * dap_chain_net_get_tx_cond_all_by_srv_uid(dap_chain_net_t * a_net, const dap_chain_net_srv_uid_t a_srv_uid,
+                                                      const dap_time_t a_time_from, const dap_time_t a_time_to,
+                                                     const dap_chain_net_tx_search_type_t a_search_type)
+{
+    dap_ledger_t * l_ledger = a_net->pub.ledger;
+    dap_list_t * l_ret = NULL;
+
+    switch (a_search_type) {
+        case TX_SEARCH_TYPE_NET:
+        case TX_SEARCH_TYPE_CELL:
+        case TX_SEARCH_TYPE_LOCAL:
+        case TX_SEARCH_TYPE_CELL_SPENT:
+        case TX_SEARCH_TYPE_NET_SPENT: {
+            // pass all chains
+            for ( dap_chain_t * l_chain = a_net->pub.chains; l_chain; l_chain = l_chain->next){
+                dap_chain_cell_t * l_cell, *l_cell_tmp;
+                // Go through all cells
+                HASH_ITER(hh,l_chain->cells,l_cell, l_cell_tmp){
+                    dap_chain_atom_iter_t * l_atom_iter = l_chain->callback_atom_iter_create(l_chain,l_cell->id, false  );
+                    // try to find transaction in chain ( inside shard )
+                    size_t l_atom_size = 0;
+                    dap_chain_atom_ptr_t l_atom = l_chain->callback_atom_iter_get_first(l_atom_iter, &l_atom_size);
+
+                    // Check atoms in chain
+                    while(l_atom && l_atom_size) {
+                        size_t l_datums_count = 0;
+                        dap_chain_datum_t **l_datums = l_chain->callback_atom_get_datums(l_atom, l_atom_size, &l_datums_count);
+                        // transaction
+                        dap_chain_datum_tx_t *l_tx = NULL;
+
+                        for (size_t i = 0; i < l_datums_count; i++) {
+                            // Check if its transaction
+                            if (l_datums && (l_datums[i]->header.type_id == DAP_CHAIN_DATUM_TX)) {
+                                l_tx = (dap_chain_datum_tx_t *)l_datums[i]->data;
+                            }
+
+                            // If found TX
+                            if (l_tx){
+                                // Check for time from
+                                if(a_time_from && l_tx->header.ts_created < a_time_from)
+                                        continue;
+
+                                // Check for time to
+                                if(a_time_to && l_tx->header.ts_created > a_time_to)
+                                        continue;
+
+                                if(a_search_type == TX_SEARCH_TYPE_CELL_SPENT || a_search_type == TX_SEARCH_TYPE_NET_SPENT ){
+                                    dap_hash_fast_t * l_tx_hash = dap_chain_node_datum_tx_calc_hash(l_tx);
+                                    bool l_is_spent = dap_chain_ledger_tx_spent_find_by_hash(l_ledger,l_tx_hash);
+                                    DAP_DELETE(l_tx_hash);
+                                    if(!l_is_spent)
+                                        continue;
+                                }
+                                // Check for OUT_COND items
+                                dap_list_t *l_list_out_cond_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT_COND , NULL);
+                                if(l_list_out_cond_items){
+                                    dap_list_t *l_list_cur = l_list_out_cond_items;
+                                    while(l_list_cur){ // Go through all cond items
+                                        dap_chain_tx_out_cond_t * l_tx_out_cond = (dap_chain_tx_out_cond_t *)l_list_cur->data;
+                                        if(l_tx_out_cond) // If we found cond out with target srv_uid
+                                            if(l_tx_out_cond->header.srv_uid.uint64 == a_srv_uid.uint64)
+                                                l_ret = dap_list_append(l_ret,
+                                                                        DAP_DUP_SIZE(l_tx, dap_chain_datum_tx_get_size(l_tx)));
+                                        l_list_cur = dap_list_next(l_list_cur);
+                                    }
+                                    dap_list_free(l_list_out_cond_items);
+                                }
+                            }
+                        }
+                        DAP_DEL_Z(l_datums);
+                        // go to next atom
+                        l_atom = l_chain->callback_atom_iter_get_next(l_atom_iter, &l_atom_size);
+
+                    }
+                }
+            }
+        } break;
+
+        case TX_SEARCH_TYPE_NET_UNSPENT:
+        case TX_SEARCH_TYPE_CELL_UNSPENT:
+            l_ret = dap_chain_ledger_tx_cache_find_out_cond_all(l_ledger, a_srv_uid);
+            break;
+    }
+    return l_ret;
+
+}
+
+
+/**
+ * @brief Summarize all tx inputs
+ * @param a_net
+ * @param a_tx
+ * @return
+ */
+uint256_t dap_chain_net_get_tx_total_value(dap_chain_net_t * a_net, dap_chain_datum_tx_t * a_tx)
+{
+    uint256_t l_ret = {0};
+    int l_item_idx = 0;
+    dap_chain_tx_in_t *l_in_item = NULL;
+    do {
+        l_in_item = (dap_chain_tx_in_t*) dap_chain_datum_tx_item_get(a_tx, &l_item_idx, TX_ITEM_TYPE_IN , NULL);
+        l_item_idx++;
+        if(l_in_item ) {
+            //const char *token = l_out_cond_item->subtype.srv_xchange.token;
+            dap_chain_datum_tx_t * l_tx_prev = dap_chain_net_get_tx_by_hash(a_net,&l_in_item->header.tx_prev_hash, TX_SEARCH_TYPE_NET_SPENT);
+            if(l_tx_prev){
+                int l_tx_prev_out_index = l_in_item->header.tx_out_prev_idx;
+                dap_chain_tx_out_t *  l_tx_prev_out =(dap_chain_tx_out_t *)
+                        dap_chain_datum_tx_item_get(l_tx_prev,&l_tx_prev_out_index, TX_ITEM_TYPE_OUT,NULL);
+                if ((uint32_t)l_tx_prev_out_index == l_in_item->header.tx_out_prev_idx && l_tx_prev_out) {
+                    uint256_t l_in_value = l_tx_prev_out->header.value;
+                    if(SUM_256_256(l_in_value,l_ret, &l_ret )!= 0)
+                        log_it(L_ERROR, "Overflow on inputs values calculation (summing)");
+                }else{
+                    log_it(L_WARNING, "Can't find item with index %d in prev tx hash", l_tx_prev_out_index);
+                }
+            }else
+                log_it(L_WARNING, "Can't find prev tx hash");
+        }
+    } while(l_in_item);
+    return l_ret;
+}
+
+
+/**
+ * @brief dap_chain_net_tx_get_by_hash
+ * @param a_net
+ * @param a_tx_hash
+ * @param a_search_type
+ * @return
+ */
+dap_chain_datum_tx_t * dap_chain_net_get_tx_by_hash(dap_chain_net_t * a_net, dap_chain_hash_fast_t * a_tx_hash,
+                                                     dap_chain_net_tx_search_type_t a_search_type)
+{
+    dap_ledger_t * l_ledger = a_net->pub.ledger;
+    dap_chain_datum_tx_t * l_tx = NULL;
+
+    switch (a_search_type) {
+        case TX_SEARCH_TYPE_NET:
+        case TX_SEARCH_TYPE_CELL:
+        case TX_SEARCH_TYPE_LOCAL:
+        case TX_SEARCH_TYPE_CELL_SPENT:
+        case TX_SEARCH_TYPE_NET_SPENT: {
+
+            if ( ! l_tx ){
+                // pass all chains
+                for ( dap_chain_t * l_chain = a_net->pub.chains; l_chain; l_chain = l_chain->next){
+                    if ( l_chain->callback_tx_find_by_hash ){
+                        // try to find transaction in chain ( inside shard )
+                        l_tx = l_chain->callback_tx_find_by_hash(l_chain, a_tx_hash);
+                        if (l_tx) {
+                            if ((a_search_type == TX_SEARCH_TYPE_CELL_SPENT ||
+                                    a_search_type == TX_SEARCH_TYPE_NET_SPENT) &&
+                                    (!dap_chain_ledger_tx_spent_find_by_hash(l_ledger, a_tx_hash)))
+                                return NULL;
+                            break;
+                        }
+                    }
+                }
+            }
+        } break;
+
+        case TX_SEARCH_TYPE_NET_UNSPENT:
+        case TX_SEARCH_TYPE_CELL_UNSPENT:
+            l_tx = dap_chain_ledger_tx_find_by_hash(l_ledger, a_tx_hash);
+            break;
+    }
+    return l_tx;
+}
+
+static struct net_fee {
+    dap_chain_net_id_t net_id;
+    uint256_t value;            // Network fee value
+    dap_chain_addr_t fee_addr;  // Addr collector
+    UT_hash_handle hh;
+} *s_net_fees = NULL; // Governance statements for networks
+static pthread_rwlock_t s_net_fees_rwlock = PTHREAD_RWLOCK_INITIALIZER;
+
+bool dap_chain_net_tx_get_fee(dap_chain_net_id_t a_net_id, uint256_t *a_value, dap_chain_addr_t *a_addr)
+{
+    struct net_fee *l_net_fee;
+    HASH_FIND(hh, s_net_fees, &a_net_id, sizeof(a_net_id), l_net_fee);
+    if (!l_net_fee || IS_ZERO_256(l_net_fee->value))
+        return false;
+    if (a_value)
+        *a_value = l_net_fee->value;
+    if (a_addr)
+        *a_addr = l_net_fee->fee_addr;
+    return true;
+}
diff --git a/modules/net/dap_chain_node.c b/modules/net/dap_chain_node.c
index 02402d03ad58f3e23a31fe80da06c9b5678f27e6..6aa7e06e55c50383ae330e151d42ce649c9a7bb7 100644
--- a/modules/net/dap_chain_node.c
+++ b/modules/net/dap_chain_node.c
@@ -198,83 +198,55 @@ dap_chain_node_info_t* dap_chain_node_info_read( dap_chain_net_t * a_net,dap_cha
     return l_node_info;
 }
 
+bool dap_chain_node_mempool_need_process(dap_chain_t *a_chain, dap_chain_datum_t *a_datum) {
+    for (uint16_t j = 0; j < a_chain->autoproc_datum_types_count; j++)
+        if (a_datum->header.type_id == a_chain->autoproc_datum_types[j])
+            return true;
+    return false;
+}
 
-/**
- * Serialize dap_chain_node_info_t
- * size[out] - length of output string
- * return data or NULL if error
- */
-/*uint8_t* dap_chain_node_info_serialize(dap_chain_node_info_t *node_info, size_t *size)
-{
-    if(!node_info)
-        return NULL;
-    size_t node_info_size = dap_chain_node_info_get_size(node_info);
-    size_t node_info_str_size = 2 * node_info_size + 1;
-    uint8_t *node_info_str = DAP_NEW_Z_SIZE(uint8_t, node_info_str_size);
-    if(bin2hex(node_info_str, (const unsigned char *) node_info, node_info_size) == -1) {
-        DAP_DELETE(node_info_str);
-        return NULL;
-    }
-
-    if(size)
-        *size = node_info_str_size;
-    return node_info_str;
-}*/
-
-/**
- * Deserialize dap_chain_node_info_t
- * size[in] - length of input string
- * return data or NULL if error
- */
-/*dap_chain_node_info_t* dap_chain_node_info_deserialize(uint8_t *node_info_str, size_t size)
-{
-    if(!node_info_str || size<=0)
-        return NULL;
-    dap_chain_node_info_t *node_info = DAP_NEW_Z_SIZE(dap_chain_node_info_t, (size / 2 + 1));
-    if(hex2bin((char*) node_info, (const unsigned char *) node_info_str, size) == -1 ||
-            (size / 2) != dap_chain_node_info_get_size(node_info)) {
-        log_it(L_ERROR, "node_info_deserialize - incorrect node_info size (%ld!=%ld)",
-                size / 2, dap_chain_node_info_get_size(node_info));
-        DAP_DELETE(node_info);
-        return NULL;
-    }
-    return node_info;
-}*/
-
-int dap_chain_node_mempool_process(dap_chain_t *a_chain, dap_chain_datum_t *a_datum)
-{
-    bool l_need_process = false;
-    for (uint16_t j = 0; j < a_chain->autoproc_datum_types_count; j++) {
-        if (a_datum->header.type_id == a_chain->autoproc_datum_types[j]) {
-            l_need_process = true;
-            break;
-        }
-    }
-    if (!l_need_process)
-        return -1;
-    // Auth signs for emissions already verified by this callback
-    return (int)a_chain->callback_add_datums(a_chain, &a_datum, 1);
+// Return true if processed datum should be deleted from mempool
+bool dap_chain_node_mempool_process(dap_chain_t *a_chain, dap_chain_datum_t *a_datum) {
+    if (!a_chain->callback_add_datums)
+        return false;
+    // Verify for correctness
+    dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
+    int l_verify_datum = dap_chain_net_verify_datum_for_add(l_net, a_datum);
+    if (l_verify_datum != 0 &&
+            l_verify_datum != DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS &&
+            l_verify_datum != DAP_CHAIN_CS_VERIFY_CODE_TX_NO_EMISSION &&
+            l_verify_datum != DAP_CHAIN_CS_VERIFY_CODE_TX_NO_TOKEN)
+        return true;
+    if (!l_verify_datum)
+        a_chain->callback_add_datums(a_chain, &a_datum, 1);
+    return false;
 }
 
-static void s_chain_node_mempool_autoproc_notify(void *a_arg, const char a_op_code, const char *a_group,
-                                             const char *a_key, const void *a_value, const size_t a_value_len)
-{
-    UNUSED(a_value_len);
-    if (!a_arg || !a_value || a_op_code != 'a') {
-        return;
-    }
-    dap_chain_t *l_chain =(dap_chain_t *)a_arg;
-    dap_chain_net_t *l_net = dap_chain_net_by_id(l_chain->net_id);
+void dap_chain_node_mempool_process_all(dap_chain_t *a_chain) {
+    dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
     if (!l_net->pub.mempool_autoproc)
         return;
-    dap_chain_datum_t *l_datum = (dap_chain_datum_t *)a_value;
-    if (dap_chain_node_mempool_process(l_chain, l_datum) >= 0) {
-        dap_global_db_context_t * l_gdb_context = dap_global_db_context_current();
-        assert(l_gdb_context);
-        dap_global_db_del_unsafe(l_gdb_context,a_group, a_key);
+    char *l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(a_chain);
+    size_t l_objs_size = 0;
+    dap_global_db_obj_t *l_objs = dap_global_db_get_all_sync(l_gdb_group_mempool, &l_objs_size);
+    if (l_objs_size) {
+        for (size_t i = 0; i < l_objs_size; i++) {
+            if (!l_objs[i].value_len)
+                continue;
+            dap_chain_datum_t *l_datum = (dap_chain_datum_t *)l_objs[i].value;
+            if (dap_chain_node_mempool_need_process(a_chain, l_datum)) {
+                if (dap_chain_node_mempool_process(a_chain, l_datum)) {
+                    // Delete processed objects
+                    dap_global_db_del(l_gdb_group_mempool, l_objs[i].key, NULL, NULL);
+                }
+            }
+        }
+        dap_global_db_objs_delete(l_objs, l_objs_size);
     }
+    DAP_DELETE(l_gdb_group_mempool);
 }
 
+
 /**
  * @brief
  * get automatic mempool processing, when network config contains mempool_auto_types for specific datums
@@ -302,27 +274,8 @@ bool dap_chain_node_mempool_autoproc_init()
         }
         dap_chain_t *l_chain;
         DL_FOREACH(l_net_list[i]->pub.chains, l_chain) {
-            if (!l_chain) {
-                continue;
-            }
-            char *l_gdb_group_mempool = NULL;
-            l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(l_chain);
-            size_t l_objs_size = 0;
-            dap_global_db_obj_t *l_objs = dap_global_db_get_all_sync(l_gdb_group_mempool, &l_objs_size);
-            if (l_objs_size) {
-                for (size_t i = 0; i < l_objs_size; i++) {
-                    if (!l_objs[i].value_len)
-                        continue;
-                    dap_chain_datum_t *l_datum = (dap_chain_datum_t *)l_objs[i].value;
-                    if (dap_chain_node_mempool_process(l_chain, l_datum) >= 0) {
-                        // Delete processed objects
-                        dap_global_db_del_sync(l_gdb_group_mempool, l_objs[i].key );
-                    }
-                }
-                dap_global_db_objs_delete(l_objs, l_objs_size);
-            }
-            DAP_DELETE(l_gdb_group_mempool);
-            dap_chain_add_mempool_notify_callback(l_chain, s_chain_node_mempool_autoproc_notify, l_chain);
+            if (l_chain)
+                dap_chain_node_mempool_process_all(l_chain);
         }
     }
     DAP_DELETE(l_net_list);
diff --git a/modules/net/dap_chain_node_cli.c b/modules/net/dap_chain_node_cli.c
index 11dcbf7cabce78e04f8d3680dd6f74c96f67cb38..6529f934aff7f3c1cd0366a1072562e27690582b 100644
--- a/modules/net/dap_chain_node_cli.c
+++ b/modules/net/dap_chain_node_cli.c
@@ -131,66 +131,66 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
 
     // Token commands
     dap_cli_server_cmd_add ("token_update", com_token_update, "Token update",
-            "\nPrivate token update\n"
-            "token_update -net <net_name> -chain <chain_name> -token <token_ticker> [-type private] [-<Param name 1> <Param Value 1>] [-Param name 2> <Param Value 2>] ...[-<Param Name N> <Param Value N>]\n"
-            "\t   Update private token <token_ticker> for <netname>:<chain_name> with"
-            "\t   custom parameters list <Param 1>, <Param 2>...<Param N>."
-            "\n"
-            "==Params==\n"
-            "General:\n"
-            "\t -flags_set <value>:\t Set list of flags from <value> to token declaration\n"
-            "\t -flags_unset <value>:\t Unset list of flags from <value> from token declaration\n"
-            "\t -total_supply <value>:\t Set total supply - emission's maximum - to the <value>\n"
-            "\t -total_signs_valid <value>:\t Set valid signatures count's minimum\n"
-            "\t -signs_add <value>:\t Add signature's pkey fingerprint to the list of owners\n"
-            "\t -signs_remove <value>:\t Remove signature's pkey fingerprint from the owners\n"
-            "\nDatum type allowed/blocked updates:\n"
-            "\t -datum_type_allowed_add <value>:\t Add allowed datum type(s)\n"
-            "\t -datum_type_allowed_remove <value>:\t Remove datum type(s) from allowed\n"
-            "\t -datum_type_allowed_clear:\t Remove all datum types from allowed\n"
-            "\t -datum_type_blocked_add <value>:\t Add blocked datum type(s)\n"
-            "\t -datum_type_blocked_remove <value>:\t Remove datum type(s) from blocked\n"
-            "\t -datum_type_blocked_clear:\t Remove all datum types from blocked\n"
-            "\nTx receiver addresses allowed/blocked updates:\n"
-            "\t -tx_receiver_allowed_add <value>:\t Add allowed tx receiver(s)\n"
-            "\t -tx_receiver_allowed_remove <value>:\t Remove tx receiver(s) from allowed\n"
-            "\t -tx_receiver_allowed_clear:\t Remove all tx receivers from allowed\n"
-            "\t -tx_receiver_blocked_add <value>:\t Add blocked tx receiver(s)\n"
-            "\t -tx_receiver_blocked_remove <value>:\t Remove tx receiver(s) from blocked\n"
-            "\t -tx_receiver_blocked_clear:\t Remove all tx receivers from blocked\n"
-            "\nTx sender addresses allowed/blocked updates:\n"
-            "\t -tx_sender_allowed_add <value>:\t Add allowed tx sender(s)\n"
-            "\t -tx_sender_allowed_remove <value>:\t Remove tx sender(s) from allowed\n"
-            "\t -tx_sender_allowed_clear:\t Remove all tx senders from allowed\n"
-            "\t -tx_sender_blocked_add <value>:\t Add allowed tx sender(s)\n"
-            "\t -tx_sender_blocked_remove <value>:\t Remove tx sender(s) from blocked\n"
-            "\t -tx_sender_blocked_clear:\t Remove all tx sender(s) from blocked\n"
-            "\n"
-            "==Flags=="
-            "\t ALL_BLOCKED:\t Blocked all permissions, usefull add it first and then add allows what you want to allow\n"
-            "\t ALL_ALLOWED:\t Allowed all permissions if not blocked them. Be careful with this mode\n"
-            "\t ALL_FROZEN:\t All permissions are temprorary frozen\n"
-            "\t ALL_UNFROZEN:\t Unfrozen permissions\n"
-            "\t STATIC_ALL:\t No token manipulations after declarations at all. Token declares staticly and can't variabed after\n"
-            "\t STATIC_FLAGS:\t No token manipulations after declarations with flags\n"
-            "\t STATIC_PERMISSIONS_ALL:\t No all permissions lists manipulations after declarations\n"
-            "\t STATIC_PERMISSIONS_DATUM_TYPE:\t No datum type permissions lists manipulations after declarations\n"
-            "\t STATIC_PERMISSIONS_TX_SENDER:\t No tx sender permissions lists manipulations after declarations\n"
-            "\t STATIC_PERMISSIONS_TX_RECEIVER:\t No tx receiver permissions lists manipulations after declarations\n"
-            "\n"
-            );
+                            "\nPrivate or CF20 token update\n"
+                            "\nPrivate token update\n"
+                            "token_update -net <net_name> -chain <chain_name> -token <existing token_ticker> -type private -total_supply <the same or more> -decimals <18>\n"
+                            "-signs_total <the same total as the token you are updating> -signs_emission <the same total as the token you are updating> -certs <use the certificates of the token you are update>\n"
+                            "-flags [<Flag 1>][,<Flag 2>]...[,<Flag N>]...\n"
+                            "\t [-<Param name 1> <Param Value 1>] [-Param name 2> <Param Value 2>] ...[-<Param Name N> <Param Value N>]\n"
+                            "\t   Update token for <netname>:<chain name> with ticker <token ticker>, flags <Flag 1>,<Flag2>...<Flag N>\n"
+                            "\t   and custom parameters list <Param 1>, <Param 2>...<Param N>.\n"
+                            "\nCF20 token update\n"
+                            "token_update -net <net_name> -chain <chain_name> -token <existing token_ticker> -type CF20 -total_supply <the same or more/if 0 = endless> -decimals <18>\n"
+                            "-signs_total <the same total as the token you are updating> -signs_emission <the same total as the token you are updating> -certs <use the certificates of the token you are update>\n"
+                            "\t -flags [<Flag 1>][,<Flag 2>]...[,<Flag N>]...\n"
+                            "\t [-<Param name 1> <Param Value 1>] [-Param name 2> <Param Value 2>] ...[-<Param Name N> <Param Value N>]\n"
+                            "\t   Update token for <netname>:<chain name> with ticker <token ticker>, flags <Flag 1>,<Flag2>...<Flag N>\n"
+                            "\t   and custom parameters list <Param 1>, <Param 2>...<Param N>.\n"
+                            "\n"
+                            "==Flags=="
+                            "\t ALL_BLOCKED:\t Blocked all permissions, usefull add it first and then add allows what you want to allow\n"
+                            "\t ALL_ALLOWED:\t Allowed all permissions if not blocked them. Be careful with this mode\n"
+                            "\t ALL_FROZEN:\t All permissions are temprorary frozen\n"
+                            "\t ALL_UNFROZEN:\t Unfrozen permissions\n"
+                            "\t STATIC_ALL:\t No token manipulations after declarations at all. Token declares staticly and can't variabed after\n"
+                            "\t STATIC_FLAGS:\t No token manipulations after declarations with flags\n"
+                            "\t STATIC_PERMISSIONS_ALL:\t No all permissions lists manipulations after declarations\n"
+                            "\t STATIC_PERMISSIONS_DATUM_TYPE:\t No datum type permissions lists manipulations after declarations\n"
+                            "\t STATIC_PERMISSIONS_TX_SENDER:\t No tx sender permissions lists manipulations after declarations\n"
+                            "\t STATIC_PERMISSIONS_TX_RECEIVER:\t No tx receiver permissions lists manipulations after declarations\n"
+                            "\n"
+                            "==Params==\n"
+                            "General:\n"
+                            "\t -flags <value>:\t List of flags from <value> to token declaration or update\n"
+                            "\t -total_supply <value>:\t Set total supply - emission's maximum - to the <value>\n"
+                            "\t -total_signs_valid <value>:\t Set valid signatures count's minimum\n"
+                            "\nDatum type allowed/blocked:\n"
+                            "\t -datum_type_allowed <value>:\t Set allowed datum type(s)\n"
+                            "\t -datum_type_blocked <value>:\t Set blocked datum type(s)\n"
+                            "\nTx receiver addresses allowed/blocked:\n"
+                            "\t -tx_receiver_allowed <value>:\t Set allowed tx receiver(s)\n"
+                            "\t -tx_receiver_blocked <value>:\t Set blocked tx receiver(s)\n"
+                            "\nTx sender addresses allowed/blocked:\n"
+                            "\t -tx_sender_allowed <value>:\t Set allowed tx sender(s)\n"
+                            "\t -tx_sender_blocked <value>:\t Set allowed tx sender(s)\n"
+                            "\n"
+                            );
+
+
     // Token commands
     dap_cli_server_cmd_add ("token_decl", com_token_decl, "Token declaration",
             "Simple token declaration:\n"
             "token_decl -net <net_name> -chain <chain_name> -token <token_ticker> -total_supply <total supply> -signs_total <sign total> -signs_emission <signs for emission> -certs <certs list>\n"
             "\t  Declare new simple token for <netname>:<chain_name> with ticker <token_ticker>, maximum emission <total supply> and <signs for emission> from <signs total> signatures on valid emission\n"
             "\nExtended private token declaration\n"
-            "token_decl -net <net_name> -chain <chain_name> -token <token_ticker> -type private -flags [<Flag 1>][,<Flag 2>]...[,<Flag N>]...\n"
+            "token_decl -net <net_name> -chain <chain_name> -token <token_ticker> -type private -total_supply <total supply> "
+                "-decimals <18> -signs_total <sign total> -signs_emission <signs for emission> -certs <certs list> -flags [<Flag 1>][,<Flag 2>]...[,<Flag N>]...\n"
             "\t [-<Param name 1> <Param Value 1>] [-Param name 2> <Param Value 2>] ...[-<Param Name N> <Param Value N>]\n"
             "\t   Declare new token for <netname>:<chain_name> with ticker <token_ticker>, flags <Flag 1>,<Flag2>...<Flag N>\n"
             "\t   and custom parameters list <Param 1>, <Param 2>...<Param N>.\n"
             "\nExtended CF20 token declaration\n"
-            "token_decl -net <net_name> -chain <chain_name> -token <token_ticker> -type CF20 -decimals <18> -signs_total <sign total> -signs_emission <signs for emission> -certs <certs list>"
+            "token_decl -net <net_name> -chain <chain_name> -token <token_ticker> -type CF20 "
+                "-total_supply <total supply/if 0 = endless> -decimals <18> -signs_total <sign total> -signs_emission <signs for emission> -certs <certs list>\n"
             "\t -flags [<Flag 1>][,<Flag 2>]...[,<Flag N>]...\n"
             "\t [-<Param name 1> <Param Value 1>] [-Param name 2> <Param Value 2>] ...[-<Param Name N> <Param Value N>]\n"
             "\t   Declare new token for <netname>:<chain_name> with ticker <token_ticker>, flags <Flag 1>,<Flag2>...<Flag N>\n"
@@ -213,7 +213,6 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
             "\t -flags <value>:\t List of flags from <value> to token declaration\n"
             "\t -total_supply <value>:\t Set total supply - emission's maximum - to the <value>\n"
             "\t -total_signs_valid <value>:\t Set valid signatures count's minimum\n"
-            "\t -signs <value>:\t Signature's fingerprint list\n"
             "\nDatum type allowed/blocked:\n"
             "\t -datum_type_allowed <value>:\t Set allowed datum type(s)\n"
             "\t -datum_type_blocked <value>:\t Set blocked datum type(s)\n"
@@ -232,11 +231,17 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
             );
 
     dap_cli_server_cmd_add ("token_emit", com_token_emit, "Token emission",
-            "token_emit {sign | -token <mempool_token_ticker> -emission_value <val>} -net <net_name> [-chain_emission <chain_name>] [-chain_base_tx <chain_name> -addr <addr>] -certs <cert list>\n");
+                            "token_emit { sign | -token <mempool_token_ticker> -emission_value <value> "
+                            "-addr <addr> [-chain_emission <chain_name>] "
+                            "[-chain_base_tx <chain_name> | use flag '-no_base_tx' if you need create emission has no base transaction] } "
+                            "-net <net_name> -certs <cert list>\n");
 
     dap_cli_server_cmd_add ("mempool_list", com_mempool_list, "List mempool entries for selected chain network",
             "mempool_list -net <net_name>\n");
 
+    dap_cli_server_cmd_add ("mempool_check", com_mempool_check, "Check mempool entrie for presence in selected chain network",
+            "mempool_check -net <net_name> -datum <datum hash>\n");
+
     dap_cli_server_cmd_add ("mempool_proc", com_mempool_proc, "Proc mempool entrie with specified hash for selected chain network",
             "mempool_proc -net <net_name> -datum <datum hash>\n");
 
@@ -293,21 +298,22 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
     dap_cli_server_cmd_add("stats", com_stats, "Print statistics",
                 "stats cpu");
 
-
-
-    // Exit
-    dap_cli_server_cmd_add ("exit", com_exit, "Stop application and exit",
-                "exit\n" );
-
-     // Export GDB to JSON
-     dap_cli_server_cmd_add("gdb_export", cmd_gdb_export, "Export gdb to JSON",
+    // Export GDB to JSON
+    dap_cli_server_cmd_add("gdb_export", cmd_gdb_export, "Export gdb to JSON",
                                         "gdb_export filename <filename without extension> [-groups <group names list>]");
 
-     //Import GDB from JSON
-     dap_cli_server_cmd_add("gdb_import", cmd_gdb_import, "Import gdb from JSON",
+    //Import GDB from JSON
+    dap_cli_server_cmd_add("gdb_import", cmd_gdb_import, "Import gdb from JSON",
                                         "gdb_import filename <filename without extension>");
 
+    dap_cli_server_cmd_add ("remove", cmd_remove, "Delete chain files or global database",
+           "remove -gdb\n"
+           "remove -chains [-net <net_name> | -all]\n"
+                     "Be careful, the '-all' option for '-chains' will delete all chains and won't ask you for permission!");
 
+    // Exit - always last!
+    dap_cli_server_cmd_add ("exit", com_exit, "Stop application and exit",
+                "exit\n" );
     return 0;
 }
 
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index c27479e480663795ae568f625c3e04ec42b469da..4904bd70ee8ac22611400ea7e87ff6b65ea01e98 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -52,13 +52,10 @@
 #include <signal.h>
 #endif
 #include <pthread.h>
-
-#include "iputils/iputils.h"
+#include <iputils/iputils.h>
 
 #include "uthash.h"
 #include "utlist.h"
-
-
 #include "dap_string.h"
 #include "dap_hash.h"
 #include "dap_chain_common.h"
@@ -73,11 +70,11 @@
 #include "dap_chain_node.h"
 #include "dap_global_db.h"
 #include "dap_chain_node_client.h"
-#include "dap_chain_node_remote.h"
 #include "dap_chain_node_cli_cmd.h"
 #include "dap_chain_node_cli_cmd_tx.h"
 #include "dap_chain_node_ping.h"
 #include "dap_chain_net_srv.h"
+#include "dap_chain_net_tx.h"
 
 #ifndef _WIN32
 #include "dap_chain_net_news.h"
@@ -1170,7 +1167,7 @@ int com_node(int a_argc, char ** a_argv, char **a_str_reply)
                     l_node_addr.uint64 = l_remote_node_addr->uint64;
 
                     // clean client struct
-                    dap_chain_node_client_close(l_node_client);
+                    dap_chain_node_client_close(l_node_client->uuid);
                     DAP_DELETE(l_remote_node_info);
                     //return -1;
                     continue;
@@ -1192,7 +1189,7 @@ int com_node(int a_argc, char ** a_argv, char **a_str_reply)
             dap_cli_server_cmd_set_reply_text(a_str_reply, "no response from remote node(s)");
             log_it(L_WARNING, "No response from remote node(s): err code %d", res);
             // clean client struct
-            dap_chain_node_client_close(l_node_client);
+            dap_chain_node_client_close(l_node_client->uuid);
             //DAP_DELETE(l_remote_node_info);
             return -1;
         }
@@ -1221,7 +1218,7 @@ int com_node(int a_argc, char ** a_argv, char **a_str_reply)
             NULL, 0);
             if(res == 0) {
                 log_it(L_WARNING, "Can't send DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_NODE_ADDR_REQUEST packet");
-                dap_chain_node_client_close(l_node_client);
+                dap_chain_node_client_close(l_node_client->uuid);
                 DAP_DELETE(l_remote_node_info);
                 return -1;
             }
@@ -1250,22 +1247,6 @@ int com_node(int a_argc, char ** a_argv, char **a_str_reply)
                 DAP_DELETE(l_remote_node_info);
                 return -1;*/
             }
-            /*                if(0 == dap_stream_ch_chain_pkt_write_unsafe(l_ch_chain, DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_NODE_ADDR_REQUEST,
-             l_net->pub.id, l_chain_id_null, l_chain_cell_id_null, &l_sync_request,
-             sizeof(l_sync_request))) {
-             dap_cli_server_cmd_set_reply_text(a_str_reply, "Error: Cant send sync chains request");
-             // clean client struct
-             dap_chain_node_client_close(l_node_client);
-             DAP_DELETE(l_remote_node_info);
-             return -1;
-             }
-            dap_stream_ch_set_ready_to_write(l_ch_chain, true);
-            // wait for finishing of request
-            timeout_ms = 120000; // 20 min = 1200 sec = 1 200 000 ms
-            // TODO add progress info to console
-            res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_SYNCED, timeout_ms);
-            */
-
         }
         log_it(L_NOTICE, "Now lets sync all");
 
@@ -1287,7 +1268,7 @@ int com_node(int a_argc, char ** a_argv, char **a_str_reply)
                 sizeof(l_sync_request))) {
             dap_cli_server_cmd_set_reply_text(a_str_reply, "Error: Can't send sync chains request");
             // clean client struct
-            dap_chain_node_client_close(l_node_client);
+            dap_chain_node_client_close(l_node_client->uuid);
             DAP_DELETE(l_remote_node_info);
             return -1;
         }
@@ -1299,7 +1280,7 @@ int com_node(int a_argc, char ** a_argv, char **a_str_reply)
         if(res < 0) {
             dap_cli_server_cmd_set_reply_text(a_str_reply, "Error: can't sync with node "NODE_ADDR_FP_STR,
                                             NODE_ADDR_FP_ARGS_S(l_node_client->remote_node_addr));
-            dap_chain_node_client_close(l_node_client);
+            dap_chain_node_client_close(l_node_client->uuid);
             DAP_DELETE(l_remote_node_info);
             log_it(L_WARNING, "Gdb synced err -2");
             return -2;
@@ -1327,7 +1308,7 @@ int com_node(int a_argc, char ** a_argv, char **a_str_reply)
                     sizeof(l_sync_request))) {
                 dap_cli_server_cmd_set_reply_text(a_str_reply, "Error: Can't send sync chains request");
                 // clean client struct
-                dap_chain_node_client_close(l_node_client);
+                dap_chain_node_client_close(l_node_client->uuid);
                 DAP_DELETE(l_remote_node_info);
                 log_it(L_INFO, "Chain '%s' synced error: Can't send sync chains request", l_chain->name);
                 return -3;
@@ -1347,7 +1328,7 @@ int com_node(int a_argc, char ** a_argv, char **a_str_reply)
         DAP_DELETE(l_remote_node_info);
         //dap_client_disconnect(l_node_client->client);
         //l_node_client->client = NULL;
-        dap_chain_node_client_close(l_node_client);
+        dap_chain_node_client_close(l_node_client->uuid);
         dap_cli_server_cmd_set_reply_text(a_str_reply, "Node sync completed: Chains and gdb are synced");
         return 0;
 
@@ -1387,25 +1368,11 @@ int com_node(int a_argc, char ** a_argv, char **a_str_reply)
         if (res) {
             dap_cli_server_cmd_set_reply_text(a_str_reply, "No response from node");
             // clean client struct
-            dap_chain_node_client_close(client);
+            dap_chain_node_client_close(client->uuid);
             DAP_DELETE(node_info);
             return -8;
         }
         DAP_DELETE(node_info);
-
-        //Add new established connection in the list
-        int ret = dap_chain_node_client_list_add(&l_node_addr, client);
-        switch (ret)
-        {
-        case -1:
-            dap_chain_node_client_close(client);
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "Connection established, but not saved");
-            return -9;
-        case -2:
-            dap_chain_node_client_close(client);
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "Connection already present");
-            return -10;
-        }
         dap_cli_server_cmd_set_reply_text(a_str_reply, "Connection established");
     }
         break;
@@ -2308,7 +2275,7 @@ void s_com_mempool_list_print_for_chain(dap_chain_net_t * a_net, dap_chain_t * a
             }
             char buf[50] = {[0]='\0'};
             dap_hash_fast_t l_data_hash;
-            char l_data_hash_str[70] = {[0]='\0'};
+            char l_data_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE] = {[0]='\0'};
             dap_hash_fast(l_datum->data,l_datum->header.data_size,&l_data_hash);
             dap_hash_fast_to_str(&l_data_hash,l_data_hash_str,DAP_CHAIN_HASH_FAST_STR_SIZE);
             const char *l_type = NULL;
@@ -2333,9 +2300,8 @@ void s_com_mempool_list_print_for_chain(dap_chain_net_t * a_net, dap_chain_t * a
             dap_chain_datum_dump(a_str_tmp, l_datum, a_hash_out_type);
         }
         dap_global_db_objs_delete(l_objs, l_objs_size);
+        DAP_DELETE(l_gdb_group_mempool);
     }
-
-    DAP_DELETE(l_gdb_group_mempool);
 }
 
 /**
@@ -2364,24 +2330,12 @@ int com_mempool_list(int argc, char ** argv, char ** a_str_reply)
         }
     }
 
-    if(l_net) {
-        dap_string_t * l_str_tmp = dap_string_new(NULL);
-
-        if(l_chain)
-            s_com_mempool_list_print_for_chain(l_net, l_chain, l_str_tmp, l_hash_out_type);
-        else
-            DL_FOREACH(l_net->pub.chains, l_chain)
-                    s_com_mempool_list_print_for_chain(l_net, l_chain, l_str_tmp, l_hash_out_type);
-
-        dap_cli_server_cmd_set_reply_text(a_str_reply, l_str_tmp->str);
-        dap_string_free(l_str_tmp, false);
-
-        return 0;
-    } else {
-        dap_cli_server_cmd_set_reply_text(a_str_reply,
-                "Error! Need both -net <network name> and -chain <chain name> params\n");
-        return -2;
-    }
+    dap_string_t * l_str_tmp = dap_string_new(NULL);
+    DL_FOREACH(l_net->pub.chains, l_chain)
+        s_com_mempool_list_print_for_chain(l_net, l_chain, l_str_tmp, l_hash_out_type);
+    dap_cli_server_cmd_set_reply_text(a_str_reply, l_str_tmp->str);
+    dap_string_free(l_str_tmp, true);
+    return 0;
 }
 
 /**
@@ -2398,62 +2352,76 @@ int com_mempool_delete(int argc, char ** argv, char ** a_str_reply)
     dap_chain_t * l_chain = NULL;
     dap_chain_net_t * l_net = NULL;
 
-    const char * l_hash_out_type = NULL;
-    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-H", &l_hash_out_type);
-    if(!l_hash_out_type)
-        l_hash_out_type = "hex";
-    if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type,"base58")) {
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "invalid parameter -H, valid values: -H <hex | base58>");
+    if(dap_chain_node_cli_cmd_values_parse_net_chain(&arg_index, argc, argv, a_str_reply, &l_chain, &l_net) != 0) {
         return -1;
     }
+    const char * l_datum_hash_str = NULL;
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-datum", &l_datum_hash_str);
+    if (l_datum_hash_str) {
+        char *l_datum_hash_hex_str = NULL;
+        // datum hash may be in hex or base58 format
+        if(dap_strncmp(l_datum_hash_str, "0x", 2) && dap_strncmp(l_datum_hash_str, "0X", 2))
+                        l_datum_hash_hex_str = dap_enc_base58_to_hex_str_from_str(l_datum_hash_str);
 
-    if(dap_chain_node_cli_cmd_values_parse_net_chain(&arg_index, argc, argv, a_str_reply, &l_chain, &l_net) != 0) {
-        //dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! Need both -net <network name> and -chain <chain name> params\n");
-        return -1;
+        char * l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(l_chain);
+        uint8_t *l_data_tmp = dap_global_db_get_sync(l_gdb_group_mempool, l_datum_hash_hex_str ? l_datum_hash_hex_str : l_datum_hash_str,
+                                                     NULL, NULL, NULL);
+        if(l_data_tmp && dap_global_db_del_sync(l_gdb_group_mempool, l_datum_hash_hex_str) == 0) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Datum %s deleted", l_datum_hash_str);
+            return 0;
+        } else {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! Can't find datum %s", l_datum_hash_str);
+            return -4;
+        }
+        DAP_DELETE(l_gdb_group_mempool);
+        DAP_DELETE(l_data_tmp);
+        DAP_DEL_Z(l_datum_hash_hex_str);
+    } else {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! %s requires -datum <datum hash> option", argv[0]);
+        return -3;
     }
+}
 
-    if(l_chain && l_net) {  // UNUSED(l_net)
-        const char * l_datum_hash_str = NULL;
-        dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-datum", &l_datum_hash_str);
-        if(l_datum_hash_str) {
-            char *l_datum_hash_hex_str;
-            char *l_datum_hash_base58_str;
-            // datum hash may be in hex or base58 format
-            if(!dap_strncmp(l_datum_hash_str, "0x", 2) || !dap_strncmp(l_datum_hash_str, "0X", 2)) {
-                l_datum_hash_hex_str = dap_strdup(l_datum_hash_str);
-                l_datum_hash_base58_str = dap_enc_base58_from_hex_str_to_str(l_datum_hash_str);
-            }
-            else {
-                l_datum_hash_hex_str = dap_enc_base58_to_hex_str_from_str(l_datum_hash_str);
-                l_datum_hash_base58_str = dap_strdup(l_datum_hash_str);
-            }
-            char * l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(l_chain);
-            uint8_t *l_data_tmp = l_datum_hash_hex_str ? dap_global_db_get_sync(l_gdb_group_mempool, l_datum_hash_hex_str, NULL, NULL, NULL ) : NULL;
-            if(l_data_tmp && dap_global_db_del_sync(l_gdb_group_mempool, l_datum_hash_hex_str) == 0) {
-                if(!dap_strcmp(l_hash_out_type,"hex"))
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Datum %s deleted", l_datum_hash_hex_str);
-                else
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Datum %s deleted", l_datum_hash_base58_str);
-                return 0;
-            } else {
-                if(!dap_strcmp(l_hash_out_type,"hex"))
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! Can't find datum %s", l_datum_hash_hex_str);
-                else
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! Can't find datum %s", l_datum_hash_base58_str);
-                return -4;
-            }
-            DAP_DELETE(l_gdb_group_mempool);
-            DAP_DELETE(l_data_tmp);
-            DAP_DELETE(l_datum_hash_hex_str);
-            DAP_DELETE(l_datum_hash_base58_str);
+/**
+ * @brief com_mempool_check
+ * @param argc
+ * @param argv
+ * @param arg_func
+ * @param a_str_reply
+ * @return
+ */
+int com_mempool_check(int argc, char ** argv, char ** a_str_reply)
+{
+    int arg_index = 1;
+    dap_chain_t * l_chain = NULL;
+    dap_chain_net_t * l_net = NULL;
+
+    if (dap_chain_node_cli_cmd_values_parse_net_chain(&arg_index, argc, argv, a_str_reply, &l_chain, &l_net))
+        return -1;
+
+    const char * l_datum_hash_str = NULL;
+    dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-datum", &l_datum_hash_str);
+    if(l_datum_hash_str) {
+        char *l_datum_hash_hex_str = NULL;
+        // datum hash may be in hex or base58 format
+        if(dap_strncmp(l_datum_hash_str, "0x", 2) && dap_strncmp(l_datum_hash_str, "0X", 2))
+            l_datum_hash_hex_str = dap_enc_base58_to_hex_str_from_str(l_datum_hash_str);
+        char * l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(l_chain);
+        uint8_t *l_data_tmp = dap_global_db_get_sync(l_gdb_group_mempool, l_datum_hash_hex_str ? l_datum_hash_hex_str : l_datum_hash_str,
+                                                     NULL, NULL, NULL);
+        if (l_data_tmp) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Datum %s is present in mempool", l_datum_hash_str);
+            return 0;
         } else {
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! %s requires -datum <datum hash> option", argv[0]);
-            return -3;
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't find datum %s", l_datum_hash_str);
+            return -4;
         }
+        DAP_DELETE(l_gdb_group_mempool);
+        DAP_DELETE(l_data_tmp);
+        DAP_DEL_Z(l_datum_hash_hex_str);
     } else {
-        dap_cli_server_cmd_set_reply_text(a_str_reply,
-                "Error! Need both -net <network name> and -chain <chain name> params\n");
-        return -2;
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! %s requires -datum <datum hash> option", argv[0]);
+        return -3;
     }
 }
 
@@ -2580,328 +2548,6 @@ int com_mempool_proc(int argc, char ** argv, char ** a_str_reply)
     return  ret;
 }
 
-
-/**
- * @brief com_token_decl_update
- * @param argc
- * @param argv
- * @param arg_func
- * @param str_reply
- * @return
- * @details token_update -net <net_name> -chain <chain_name> -token <token_ticker> [-type private] -flags [<Flag 1>][,<Flag 2>]...[,<Flag N>]...  [-<Param name 1> <Param Value 1>] [-Param name 2> <Param Value 2>] ...[-<Param Name N> <Param Value N>]\n"
- *  \t   Update token for <netname>:<chain name> with ticker <token ticker>, flags <Flag 1>,<Flag2>...<Flag N>"
- *  \t   and custom parameters list <Param 1>, <Param 2>...<Param N>."
- *  \n"
- *  ==Flags=="
- *  \t ALL_BLOCKED:\t Blocked all permissions, usefull add it first and then add allows what you want to allow\n"
- *  \t ALL_ALLOWED:\t Allowed all permissions if not blocked them. Be careful with this mode\n"
- *  \t ALL_FROZEN:\t All permissions are temprorary frozen\n"
- *  \t ALL_UNFROZEN:\t Unfrozen permissions\n"
- *  \t STATIC_ALL:\t No token manipulations after declarations at all. Token declares staticly and can't variabed after\n"
- *  \t STATIC_FLAGS:\t No token manipulations after declarations with flags\n"
- *  \t STATIC_PERMISSIONS_ALL:\t No all permissions lists manipulations after declarations\n"
- *  \t STATIC_PERMISSIONS_DATUM_TYPE:\t No datum type permissions lists manipulations after declarations\n"
- *  \t STATIC_PERMISSIONS_TX_SENDER:\t No tx sender permissions lists manipulations after declarations\n"
- *  \t STATIC_PERMISSIONS_TX_RECEIVER:\t No tx receiver permissions lists manipulations after declarations\n"
-    "\n"
-    "==Params==\n"
-    "General:\n"
-    "\t -flags_set <value>:\t Set list of flags from <value> to token declaration\n"
-    "\t -flags_unset <value>:\t Unset list of flags from <value> from token declaration\n"
-    "\t -total_supply <value>:\t Set total supply - emission's maximum - to the <value>\n"
-    "\t -total_signs_valid <value>:\t Set valid signatures count's minimum\n"
-    "\t -total_signs_add <value>:\t Add signature's pkey fingerprint to the list of owners\n"
-    "\t -total_signs_remove <value>:\t Remove signature's pkey fingerprint from the owners\n"
-    "\nDatum type allowed/blocked updates:\n"
-    "\t -datum_type_allowed_add <value>:\t Add allowed datum type(s)\n"
-    "\t -datum_type_allowed_remove <value>:\t Remove datum type(s) from allowed\n"
-    "\t -datum_type_blocked_add <value>:\t Add blocked datum type(s)\n"
-    "\t -datum_type_blocked_remove <value>:\t Remove datum type(s) from blocked\n"
-    "\nTx receiver addresses allowed/blocked updates:\n"
-    "\t -tx_receiver_allowed_add <value>:\t Add allowed tx receiver(s)\n"
-    "\t -tx_receiver_allowed_remove <value>:\t Remove tx receiver(s) from allowed\n"
-    "\t -tx_receiver_blocked_add <value>:\t Add blocked tx receiver(s)\n"
-    "\t -tx_receiver_blocked_remove <value>:\t Remove tx receiver(s) from blocked\n"
-    "\n Tx sender addresses allowed/blocked updates:\n"
-    "\t -tx_sender_allowed_add <value>:\t Add allowed tx sender(s)\n"
-    "\t -tx_sender_allowed_remove <value>:\t Remove tx sender(s) from allowed\n"
-    "\t -tx_sender_blocked_add <value>:\t Add allowed tx sender(s)\n"
-    "\t -tx_sender_blocked_remove <value>:\t Remove tx sender(s) from blocked\n"
-    "\n"
- */
-int com_token_update(int a_argc, char ** a_argv, char ** a_str_reply)
-{
-    int l_arg_index = 1;
-
-    const char * l_type_str = NULL;
-    uint16_t l_type = DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE;
-
-    const char * l_ticker = NULL;
-
-    uint16_t l_signs_total = 0;
-
-    dap_cert_t ** l_certs = NULL;
-    size_t l_certs_count = 0;
-
-    dap_chain_t * l_chain = NULL;
-    dap_chain_net_t * l_net = NULL;
-
-    const char * l_hash_out_type = NULL;
-    dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-H", &l_hash_out_type);
-    if(!l_hash_out_type)
-        l_hash_out_type = "hex";
-    if(dap_strcmp(l_hash_out_type, "hex") && dap_strcmp(l_hash_out_type, "base58")) {
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "invalid parameter -H, valid values: -H <hex | base58>");
-        return -1;
-    }
-
-    if (dap_chain_node_cli_cmd_values_parse_net_chain(&l_arg_index, a_argc, a_argv, a_str_reply, &l_chain, &l_net))
-        return -1;
-    // Token ticker
-    l_arg_index=dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-token", &l_ticker);
-    // Check for ticker
-    if(!l_ticker) {
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "token_update requires parameter 'token'");
-        return -2;
-    }
-
-    // Token type
-    l_arg_index=dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-type", &l_type_str);
-
-    if (l_type_str && strcmp(l_type_str, "private")) {
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "token_update can't accept type \"%s\"", l_type_str);
-        return -22;
-    }
-
-    dap_chain_datum_token_t * l_datum_token_update = NULL;
-    size_t l_datum_data_offset = 0;
-    uint32_t l_sign_counter = 0;
-
-    switch(l_type){
-        case DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE: // 256
-        case DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_UPDATE: {
-            dap_list_t *l_tsd_list = dap_list_alloc();
-            size_t l_tsd_total_size = 0;
-            l_arg_index++;
-            while (l_arg_index<a_argc-1){
-                char * l_arg_param=  a_argv[l_arg_index+1];
-                if ( strcmp( a_argv[l_arg_index],"-flags_set" )==0){   // Flags
-                     char ** l_str_flags = NULL;
-                     l_str_flags = dap_strsplit( l_arg_param,",",0xffff );
-                     uint16_t l_flags = 0;
-                     while (l_str_flags && *l_str_flags){
-                         uint16_t l_flag = dap_chain_datum_token_flag_from_str(*l_str_flags);
-                         if ( l_flag == DAP_CHAIN_DATUM_TOKEN_FLAG_UNDEFINED ){
-                             dap_cli_server_cmd_set_reply_text(a_str_reply, "Flag can't be \"%s\"",*l_str_flags);
-                             return -20;
-                         }
-                         l_flags |= (1<<l_flag);
-                         l_str_flags++;
-                     }
-                     // Add flags as set_flags TDS section
-                     dap_tsd_t * l_tsd = dap_tsd_create_scalar(
-                                                    DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_SET_FLAGS, l_flags);
-                     dap_list_append( l_tsd_list, l_tsd);
-                     l_tsd_total_size+= dap_tsd_size( l_tsd);
-
-                }else if ( strcmp( a_argv[l_arg_index],"-flags_unset" )==0){   // Flags
-                    char ** l_str_flags = NULL;
-                    l_str_flags = dap_strsplit( l_arg_param,",",0xffff );
-                    uint16_t l_flags = 0;
-                    while (l_str_flags && *l_str_flags ){
-                        uint16_t l_flag = dap_chain_datum_token_flag_from_str(*l_str_flags);
-                        if ( l_flag == DAP_CHAIN_DATUM_TOKEN_FLAG_UNDEFINED ){
-                            dap_cli_server_cmd_set_reply_text(a_str_reply, "Flag can't be \"%s\"",*l_str_flags);
-                            return -20;
-                        }
-                        l_flags |= l_flag;
-                        l_str_flags++;
-                    }
-                    // Add flags as unset_flags TDS section
-                    dap_tsd_t * l_tsd = dap_tsd_create_scalar(
-                                                            DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_UNSET_FLAGS, l_flags);
-                    dap_list_append( l_tsd_list, l_tsd);
-                    l_tsd_total_size+= dap_tsd_size( l_tsd);
-
-               }else if ( strcmp( a_argv[l_arg_index],"-signs" )==0){
-                    dap_cert_parse_str_list(l_arg_param, &l_certs, &l_certs_count);
-                    if(!l_certs_count) {
-                        dap_cli_server_cmd_set_reply_text(a_str_reply,
-                                "token_update command requres at least one valid certificate to sign the basic transaction of emission");
-                        return -10;
-                    }
-                } else if ( strcmp( a_argv[l_arg_index],"-total_supply" )==0){ // Total supply
-                    dap_tsd_t * l_tsd;
-                    uint256_t l_param_value = dap_chain_balance_scan(l_arg_param);
-                    l_tsd = dap_tsd_create_scalar(
-                                            DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TOTAL_SUPPLY, l_param_value);
-                    dap_list_append( l_tsd_list, l_tsd);
-                    l_tsd_total_size+= dap_tsd_size( l_tsd);
-                }else if ( strcmp( a_argv[l_arg_index],"-total_signs_valid" )==0){ // Signs valid
-                    uint16_t l_param_value = (uint16_t)atoi(l_arg_param);
-                    l_signs_total = l_param_value;
-                    dap_tsd_t * l_tsd = dap_tsd_create_scalar(
-                                                            DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TOTAL_SIGNS_VALID, l_param_value);
-                    dap_list_append( l_tsd_list, l_tsd);
-                    l_tsd_total_size+= dap_tsd_size( l_tsd);
-                }else if ( strcmp( a_argv[l_arg_index],"-datum_type_allowed_add" )==0){ // Datum type allowed add
-                    dap_tsd_t * l_tsd = dap_tsd_create_string(
-                                                            DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DATUM_TYPE_ALLOWED_ADD, l_arg_param);
-                    dap_list_append( l_tsd_list, l_tsd);
-                    l_tsd_total_size+= dap_tsd_size( l_tsd);
-                }else if ( strcmp( a_argv[l_arg_index],"-datum_type_allowed_remove" )==0){ // Datum type allowed remove
-                    dap_tsd_t * l_tsd = dap_tsd_create_string(
-                                                            DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DATUM_TYPE_ALLOWED_REMOVE, l_arg_param);
-                    dap_list_append( l_tsd_list, l_tsd);
-                    l_tsd_total_size+= dap_tsd_size( l_tsd);
-                }else if ( strcmp( a_argv[l_arg_index],"-datum_type_blocked_add" )==0){ // Datum type blocked add
-                    dap_tsd_t * l_tsd = dap_tsd_create_string(
-                                                            DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DATUM_TYPE_BLOCKED_ADD, l_arg_param);
-                    dap_list_append( l_tsd_list, l_tsd);
-                    l_tsd_total_size+= dap_tsd_size( l_tsd);
-                }else if ( strcmp( a_argv[l_arg_index],"-datum_type_blocked_remove" )==0){ // Datum type blocked remove
-                    dap_tsd_t * l_tsd = dap_tsd_create_string(
-                                                            DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DATUM_TYPE_BLOCKED_REMOVE, l_arg_param);
-                    dap_list_append( l_tsd_list, l_tsd);
-                    l_tsd_total_size+= dap_tsd_size( l_tsd);
-                }else if ( strcmp( a_argv[l_arg_index],"-tx_receiver_allowed_add" )==0){ // TX Receiver add
-                    dap_tsd_t * l_tsd = dap_tsd_create_string(
-                                                            DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_ALLOWED_ADD, l_arg_param);
-                    dap_list_append( l_tsd_list, l_tsd);
-                    l_tsd_total_size+= dap_tsd_size( l_tsd);
-                }else if ( strcmp( a_argv[l_arg_index],"-tx_receiver_allowed_remove" )==0){ // TX Receiver remove
-                    dap_tsd_t * l_tsd = dap_tsd_create_string(
-                                                            DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_ALLOWED_REMOVE, l_arg_param);
-                    dap_list_append( l_tsd_list, l_tsd);
-                    l_tsd_total_size+= dap_tsd_size( l_tsd);
-                }else if ( strcmp( a_argv[l_arg_index],"-tx_receiver_blocked_add" )==0){ // TX Receiver blocked add
-                    dap_tsd_t * l_tsd = dap_tsd_create_string(
-                                                            DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_BLOCKED_ADD, l_arg_param);
-                    dap_list_append( l_tsd_list, l_tsd);
-                    l_tsd_total_size+= dap_tsd_size( l_tsd);
-                }else if ( strcmp( a_argv[l_arg_index],"-tx_receiver_blocked_remove" )==0){ // TX Receiver blocked remove
-                    dap_tsd_t * l_tsd = dap_tsd_create_string(
-                                                            DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_BLOCKED_REMOVE, l_arg_param);
-                    dap_list_append( l_tsd_list, l_tsd);
-                    l_tsd_total_size+= dap_tsd_size( l_tsd);
-                }else if ( strcmp( a_argv[l_arg_index],"-tx_sender_allowed_add" )==0){ // TX Sender allowed add
-                    dap_tsd_t * l_tsd = dap_tsd_create_string(
-                                                            DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_SENDER_ALLOWED_ADD, l_arg_param);
-                    dap_list_append( l_tsd_list, l_tsd);
-                    l_tsd_total_size+= dap_tsd_size( l_tsd);
-                }else if ( strcmp( a_argv[l_arg_index],"-tx_sender_allowed_remove" )==0){ // TX Sender allowed remove
-                    dap_tsd_t * l_tsd = dap_tsd_create_string(
-                                                            DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_SENDER_ALLOWED_REMOVE, l_arg_param);
-                    dap_list_append( l_tsd_list, l_tsd);
-                    l_tsd_total_size+= dap_tsd_size( l_tsd);
-                }else if ( strcmp( a_argv[l_arg_index],"-tx_sender_blocked_add" )==0){  // TX Sender blocked add
-                    dap_tsd_t * l_tsd = dap_tsd_create_string(
-                                                            DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_SENDER_BLOCKED_ADD, l_arg_param);
-                    dap_list_append( l_tsd_list, l_tsd);
-                    l_tsd_total_size+= dap_tsd_size( l_tsd);
-                }else if ( strcmp( a_argv[l_arg_index],"-tx_sender_blocked_remove" )==0){  // TX Sender blocked remove
-                    dap_tsd_t * l_tsd = dap_tsd_create_string(
-                                                            DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_SENDER_BLOCKED_REMOVE, l_arg_param);
-                    dap_list_append( l_tsd_list, l_tsd);
-                    l_tsd_total_size+= dap_tsd_size( l_tsd);
-                } else if (strcmp( a_argv[l_arg_index], "-chain") && strcmp( a_argv[l_arg_index], "-net") &&
-                           strcmp( a_argv[l_arg_index], "-token") && !strcmp( a_argv[l_arg_index], "-type")) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Unknown param \"%s\"",a_argv[l_arg_index]);
-                    return -20;
-                }
-                l_arg_index+=2;
-            }
-
-            if (!l_tsd_total_size) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "No valid params to update");
-                return -21;
-            }
-
-            // If we have more certs than we need signs - use only first part of the list
-            if(l_certs_count > l_signs_total)
-                l_certs_count = l_signs_total;
-
-            // Create new datum token
-            l_datum_token_update = DAP_NEW_Z_SIZE(dap_chain_datum_token_t, sizeof(dap_chain_datum_token_t)+l_tsd_total_size ) ;
-            l_datum_token_update->type = DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE; // 256
-            dap_snprintf(l_datum_token_update->ticker, sizeof(l_datum_token_update->ticker), "%s", l_ticker);
-            l_datum_token_update->header_private_update.tsd_total_size = l_tsd_total_size;
-
-            // Sign header with all certificates in the list and add signs to the end of token update
-            uint16_t l_sign_counter = 0;
-            l_datum_token_update = s_sign_cert_in_cycle(l_certs, l_datum_token_update, l_certs_count, &l_tsd_total_size,
-                                                        &l_sign_counter);
-            l_datum_token_update->signs_total = l_sign_counter;
-
-            // Add TSD sections in the end
-            for ( dap_list_t* l_iter=dap_list_first(l_tsd_list); l_iter; l_iter=l_iter->next){
-                dap_tsd_t * l_tsd = (dap_tsd_t *) l_iter->data;
-                size_t l_tsd_size = dap_tsd_size( l_tsd);
-                memcpy(l_datum_token_update->data_n_tsd + l_datum_data_offset, l_tsd, l_tsd_size);
-                l_datum_data_offset += l_tsd_size;
-            }
-
-
-        }break;
-
-        default:
-            dap_cli_server_cmd_set_reply_text(a_str_reply,
-                    "Unknown token type");
-            return -8;
-    }
-
-    if (l_sign_counter == 0)
-    {
-        dap_cli_server_cmd_set_reply_text(a_str_reply,
-                    "Token declaration failed. Successful count of certificate signing is 0");
-            return -9;
-    }
-
-    dap_chain_datum_t * l_datum = dap_chain_datum_create(DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE, l_datum_token_update,
-            sizeof(l_datum_token_update->header_simple) + l_datum_data_offset);
-    size_t l_datum_size = dap_chain_datum_size(l_datum);
-
-    // Calc datum's hash
-    dap_chain_hash_fast_t l_key_hash;
-    dap_hash_fast(l_datum, l_datum_size, &l_key_hash);
-    char * l_key_str = dap_chain_hash_fast_to_str_new(&l_key_hash);
-    char * l_key_str_base58 = dap_enc_base58_encode_hash_to_str(&l_key_hash);
-
-    // Add datum to mempool with datum_token_update hash as a key
-    char * l_gdb_group_mempool;
-    if(l_chain) {
-        l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(l_chain);
-    }
-    else {
-        l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_by_chain_type(l_net, CHAIN_TYPE_TOKEN);
-
-    }
-    if(dap_global_db_set_sync(l_gdb_group_mempool, l_key_str, l_datum, l_datum_size, true) == 0) {
-        if(!dap_strcmp(l_hash_out_type,"hex"))
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "datum %s with token update %s is placed in datum pool ", l_key_str, l_ticker);
-        else
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "datum %s with token update %s is placed in datum pool ", l_key_str_base58, l_ticker);
-        DAP_DELETE(l_datum);
-        DAP_DELETE(l_datum_token_update);
-        DAP_DELETE(l_gdb_group_mempool);
-        DAP_DELETE(l_key_str);
-        DAP_DELETE(l_key_str_base58);
-        return 0;
-    }
-    else {
-        if(!dap_strcmp(l_hash_out_type,"hex"))
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "datum tx %s is not placed in datum pool ", l_key_str);
-        else
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "datum tx %s is not placed in datum pool ", l_key_str_base58);
-        DAP_DELETE(l_datum);
-        DAP_DELETE(l_datum_token_update);
-        DAP_DELETE(l_gdb_group_mempool);
-        DAP_DELETE(l_key_str);
-        DAP_DELETE(l_key_str_base58);
-        return -2;
-    }
-}
-
 /**
  * @brief
  *
@@ -2952,41 +2598,43 @@ typedef struct _dap_cli_token_additional_params {
     const char* tx_receiver_blocked;
     const char* tx_sender_allowed;
     const char* tx_sender_blocked;
+    uint16_t parsed_flags;
+    size_t tsd_total_size;
+    byte_t *parsed_tsd;
 } dap_cli_token_additional_params;
 
 typedef struct _dap_sdk_cli_params {
-    const char* l_hash_out_type;
-    dap_chain_t * l_chain;
-    dap_chain_net_t * l_net;
-    const char* l_chain_str;
-    const char* l_net_str;
-    const char* l_ticker;
-    const char* l_type_str;
-    uint16_t l_type;
-    const char* l_certs_str;
-    uint16_t l_signs_total;
-    uint16_t l_signs_emission;
-    uint256_t l_total_supply;
-    const char* l_decimals_str;
+    const char *hash_out_type;
+    const char *chain_str;
+    const char *net_str;
+    const char *ticker;
+    const char *type_str;
+    const char *certs_str;
+    dap_chain_t *chain;
+    dap_chain_net_t *net;
+    uint16_t type;
+    uint16_t signs_total;
+    uint16_t signs_emission;
+    uint256_t total_supply;
+    const char* decimals_str;
     dap_cli_token_additional_params ext;
 } dap_sdk_cli_params, *pdap_sdk_cli_params;
 
-
-int s_parse_common_token_decl_arg(int a_argc, char ** a_argv, char ** a_str_reply, dap_sdk_cli_params* l_params)
+static int s_parse_common_token_decl_arg(int a_argc, char ** a_argv, char ** a_str_reply, dap_sdk_cli_params* a_params, bool a_update_token)
 {
-    l_params->l_type = DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE;
-    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-H", &l_params->l_hash_out_type);
-    if(!l_params->l_hash_out_type)
-        l_params->l_hash_out_type = "hex";
-    if(dap_strcmp(l_params->l_hash_out_type,"hex") && dap_strcmp(l_params->l_hash_out_type,"base58")) {
+    a_params->type = DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE;
+    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-H", &a_params->hash_out_type);
+    if(!a_params->hash_out_type)
+        a_params->hash_out_type = "hex";
+    if(dap_strcmp(a_params->hash_out_type,"hex") && dap_strcmp(a_params->hash_out_type,"base58")) {
         dap_cli_server_cmd_set_reply_text(a_str_reply, "invalid parameter -H, valid values: -H <hex | base58>");
         return -1;
     }
 
     int l_arg_index = 0;
-    int l_res = dap_chain_node_cli_cmd_values_parse_net_chain(&l_arg_index, a_argc, a_argv, a_str_reply, &l_params->l_chain, &l_params->l_net);
+    int l_res = dap_chain_node_cli_cmd_values_parse_net_chain(&l_arg_index, a_argc, a_argv, a_str_reply, &a_params->chain, &a_params->net);
 
-    if(!l_params->l_net || !l_params->l_chain)
+    if(!a_params->net || !a_params->chain)
         return l_res;
     else {
         if(*a_str_reply) {
@@ -2995,44 +2643,56 @@ int s_parse_common_token_decl_arg(int a_argc, char ** a_argv, char ** a_str_repl
         }
     }
     //net name
-    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-net", &l_params->l_net_str);
+    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-net", &a_params->net_str);
     //chainname
-    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-chain", &l_params->l_chain_str);
+    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-chain", &a_params->chain_str);
     //token_ticker
-    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-token", &l_params->l_ticker);
+    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-token", &a_params->ticker);
 
     // Token type
-    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-type", &l_params->l_type_str);
-
-    if (l_params->l_type_str) {
-        if (strcmp(l_params->l_type_str, "private") == 0){
-            l_params->l_type = DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL; // 256
-        }else if (strcmp(l_params->l_type_str, "private_simple") == 0){
-            l_params->l_type = DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE; // 256
-        }else if (strcmp(l_params->l_type_str, "public_simple") == 0){
-            l_params->l_type = DAP_CHAIN_DATUM_TOKEN_TYPE_PUBLIC; // 256
-        }else if (strcmp(l_params->l_type_str, "CF20") == 0){
-            l_params->l_type = DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL; // 256
-        }else{
+    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-type", &a_params->type_str);
+
+    if (a_params->type_str) {
+        if (strcmp(a_params->type_str, "private") == 0) {
+            a_params->type = a_update_token ? DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE : DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL; // 256
+        } else if (strcmp(a_params->type_str, "CF20") == 0) {
+            a_params->type = a_update_token ? DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_UPDATE : DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL; // 256
+        } else if (strcmp(a_params->type_str, "private_simple") == 0 && !a_update_token) {
+            a_params->type = DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE; // 256
+        } else if (strcmp(a_params->type_str, "public_simple") == 0 && !a_update_token) {
+            a_params->type = DAP_CHAIN_DATUM_TOKEN_TYPE_PUBLIC; // 256
+        } else if (strcmp(a_params->type_str, "CF20") == 0) {
+            a_params->type = DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL; // 256
+        } else if (!a_update_token) {
             dap_cli_server_cmd_set_reply_text(a_str_reply,
                         "Unknown token type %s was specified. Supported types:\n"
                         "   private_simple\n"
                         "   private\n"
                         "   CF20\n"
-                        "Default token type is private_simple.\n", l_params->l_type_str);
+                        "Default token type is private_simple.\n", a_params->type_str);
             return -1;
-        }
+        } else {
+           dap_cli_server_cmd_set_reply_text(a_str_reply,
+                           "Unknown token type %s was specified. Supported types:\n"
+                       "   private\n"
+                       "   CF20\n", a_params->type_str);
+           return -1;
+        }
+    } else if (a_update_token) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply,"update_token command required parameter:\n-type <CF20 or private>");
+        return -1;
     }
 
+
     // Certificates thats will be used to sign currend datum token
-    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-certs", &l_params->l_certs_str);
+    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-certs", &a_params->certs_str);
     // Signs number thats own emissioncan't find
     const char* l_signs_total_str = NULL;
     dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-signs_total", &l_signs_total_str);
     // Signs total
     char* l_tmp = NULL;
     if(l_signs_total_str){
-        if((l_params->l_signs_total = (uint16_t) strtol(l_signs_total_str, &l_tmp, 10)) == 0){
+        if((a_params->signs_total = (uint16_t) strtol(l_signs_total_str, &l_tmp, 10)) == 0){
             dap_cli_server_cmd_set_reply_text(a_str_reply,
                     "'signs_total' parameter must be unsigned integer value that fits in 2 bytes");
             return -8;
@@ -3043,9 +2703,9 @@ int s_parse_common_token_decl_arg(int a_argc, char ** a_argv, char ** a_str_repl
     l_tmp = NULL;
     dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-signs_emission", &l_signs_emission_str);
     if (l_signs_emission_str){
-        if((l_params->l_signs_emission = (uint16_t) strtol(l_signs_emission_str, &l_tmp, 10)) == 0){
+        if((a_params->signs_emission = (uint16_t) strtol(l_signs_emission_str, &l_tmp, 10)) == 0){
             dap_cli_server_cmd_set_reply_text(a_str_reply,
-                "token_decl requires parameter 'signs_emission' to be unsigned integer value that fits in 2 bytes");
+                "%s requires parameter 'signs_emission' to be unsigned integer value that fits in 2 bytes", a_update_token ? "token_update" : "token_decl");
             return -6;
         }
     }
@@ -3053,95 +2713,204 @@ int s_parse_common_token_decl_arg(int a_argc, char ** a_argv, char ** a_str_repl
     const char* l_total_supply_str = NULL;
     dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-total_supply", &l_total_supply_str);
     if (l_total_supply_str){
-        l_params->l_total_supply = dap_chain_balance_scan(l_total_supply_str);
-        if (IS_ZERO_256(l_params->l_total_supply)){
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "'-total_supply' must be unsigned integer value that fits in 8 bytes");
-            return -4;
-        }
+        a_params->total_supply = dap_chain_balance_scan(l_total_supply_str);
+    } else if (!a_update_token) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "'-total_supply' must be unsigned integer value that fits in 32 bytes\n"
+                                                       "If your token is type native (CF20) you can use value 0 for infinite total_supply.");
+        return -4;
+    } else {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "'-total_supply' must be unsigned integer value that fits in 32 bytes\n"
+                                                       "You are update a token, be careful!\n"
+                                                       "You can reset total_supply and make it infinite for native (CF20) tokens only, if set 0"
+                                                       "for private tokens, you must specify the same or more total_supply.");
+        return -4;
     }
-
     // Total supply value
-    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-decimals", &l_params->l_decimals_str);
+    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-decimals", &a_params->decimals_str);
 
     return 0;
 }
 
-int s_parse_additional_token_decl_arg(int a_argc, char ** a_argv, char ** a_str_reply, dap_sdk_cli_params* l_params)
+static int s_parse_additional_token_decl_arg(int a_argc, char ** a_argv, char ** a_str_reply, dap_sdk_cli_params* a_params)
 {
-    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-flags", &l_params->ext.flags);
-    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-total_signs_valid", &l_params->ext.total_signs_valid);
-    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-delegated_token_from", &l_params->ext.delegated_token_from);
-    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-datum_type_allowed", &l_params->ext.datum_type_allowed);
-    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-datum_type_blocked", &l_params->ext.datum_type_blocked);
-    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-tx_receiver_allowed", &l_params->ext.tx_receiver_allowed);
-    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-tx_receiver_blocked", &l_params->ext.tx_receiver_blocked);
-    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-tx_sender_allowed", &l_params->ext.tx_sender_allowed);
-    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-tx_receiver_allowed", &l_params->ext.tx_receiver_allowed);
-    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-tx_sender_blocked", &l_params->ext.tx_sender_blocked);
+    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-flags", &a_params->ext.flags);
+    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-total_signs_valid", &a_params->ext.total_signs_valid);
+    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-delegated_token_from", &a_params->ext.delegated_token_from);
+    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-datum_type_allowed", &a_params->ext.datum_type_allowed);
+    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-datum_type_blocked", &a_params->ext.datum_type_blocked);
+    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-tx_receiver_allowed", &a_params->ext.tx_receiver_allowed);
+    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-tx_receiver_blocked", &a_params->ext.tx_receiver_blocked);
+    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-tx_sender_allowed", &a_params->ext.tx_sender_allowed);
+    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-tx_receiver_allowed", &a_params->ext.tx_receiver_allowed);
+    dap_cli_server_cmd_find_option_val(a_argv, 0, a_argc, "-tx_sender_blocked", &a_params->ext.tx_sender_blocked);
+
+    if (a_params->type == DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE)
+        return 0;
+
+    dap_list_t *l_tsd_list = NULL;
+    size_t l_tsd_total_size = 0;
+    uint16_t l_flags = 0;
+    char ** l_str_flags = NULL;
+
+    if (a_params->ext.flags){   // Flags
+         l_str_flags = dap_strsplit(a_params->ext.flags,",",0xffff );
+         while (l_str_flags && *l_str_flags){
+             uint16_t l_flag = dap_chain_datum_token_flag_from_str(*l_str_flags);
+             if (l_flag == DAP_CHAIN_DATUM_TOKEN_FLAG_UNDEFINED ){
+                 dap_cli_server_cmd_set_reply_text(a_str_reply, "Flag can't be \"%s\"",*l_str_flags);
+                 return -20;
+             }
+             l_flags |= l_flag; // if we have multiple flags
+             l_str_flags++;
+        }
+    }
+    a_params->ext.parsed_flags = l_flags;
+    if (a_params->ext.delegated_token_from) {
+        dap_chain_datum_token_t* l_delegated_token_from;
+        if (NULL == (l_delegated_token_from = dap_chain_ledger_token_ticker_check(a_params->net->pub.ledger, a_params->ext.delegated_token_from))) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "To create a delegated token %s, can't find token by ticker %s", a_params->ticker, a_params->ext.delegated_token_from);
+            return -91;
+        }
+        dap_chain_datum_token_tsd_delegate_from_stake_lock_t l_tsd_section;
+        strcpy(l_tsd_section.ticker_token_from, a_params->ext.delegated_token_from);
+        l_tsd_section.emission_rate = dap_chain_coins_to_balance("0.001");
+        dap_tsd_t* l_tsd = dap_tsd_create_scalar(
+            DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DELEGATE_EMISSION_FROM_STAKE_LOCK, l_tsd_section);
+        l_tsd_list = dap_list_append(l_tsd_list, l_tsd);
+        l_tsd_total_size += dap_tsd_size(l_tsd);
+    }
+    if (a_params->ext.total_signs_valid){ // Signs valid
+        uint16_t l_param_value = (uint16_t)atoi(a_params->ext.total_signs_valid);
+        a_params->signs_emission = l_param_value;
+        dap_tsd_t * l_tsd = dap_tsd_create_scalar(
+                                                DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TOTAL_SIGNS_VALID, l_param_value);
+        l_tsd_list = dap_list_append(l_tsd_list, l_tsd);
+        l_tsd_total_size+= dap_tsd_size(l_tsd);
+    }
+    if (a_params->ext.datum_type_allowed){
+        dap_tsd_t * l_tsd = dap_tsd_create_string(
+                                                DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DATUM_TYPE_ALLOWED_ADD, a_params->ext.datum_type_allowed);
+        l_tsd_list = dap_list_append(l_tsd_list, l_tsd);
+        l_tsd_total_size+= dap_tsd_size(l_tsd);
+    }
+    if (a_params->ext.datum_type_blocked){
+        dap_tsd_t * l_tsd = dap_tsd_create_string(
+                                                DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DATUM_TYPE_BLOCKED_ADD, a_params->ext.datum_type_blocked);
+        l_tsd_list = dap_list_append(l_tsd_list, l_tsd);
+        l_tsd_total_size+= dap_tsd_size(l_tsd);
+    }
+    if (a_params->ext.tx_receiver_allowed)
+        l_tsd_list = s_parse_wallet_addresses(a_params->ext.tx_receiver_allowed, l_tsd_list, &l_tsd_total_size, DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_ALLOWED_ADD);
+
+    if (a_params->ext.tx_receiver_blocked)
+        l_tsd_list = s_parse_wallet_addresses(a_params->ext.tx_receiver_blocked, l_tsd_list, &l_tsd_total_size, DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_BLOCKED_ADD);
+
+    if (a_params->ext.tx_sender_allowed)
+        l_tsd_list = s_parse_wallet_addresses(a_params->ext.tx_sender_allowed, l_tsd_list, &l_tsd_total_size, DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_SENDER_ALLOWED_ADD);
+
+    if (a_params->ext.tx_sender_blocked)
+        l_tsd_list = s_parse_wallet_addresses(a_params->ext.tx_sender_blocked, l_tsd_list, &l_tsd_total_size, DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_SENDER_BLOCKED_ADD);
+
+    if (!l_tsd_total_size)
+        return 0;
+
+    size_t l_tsd_offset = 0;
+    a_params->ext.parsed_tsd = DAP_NEW_SIZE(byte_t, l_tsd_total_size);
+    for (dap_list_t *l_iter = dap_list_first(l_tsd_list); l_iter; l_iter = l_iter->next) {
+        dap_tsd_t * l_tsd = (dap_tsd_t *) l_iter->data;
+        if (l_tsd == NULL){
+            log_it(L_ERROR, "NULL tsd in list!");
+            continue;
+        }
+        switch (l_tsd->type){
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TOTAL_SIGNS_VALID:
+                log_it(L_DEBUG,"== TOTAL_SIGNS_VALID: %u",
+                        dap_tsd_get_scalar(l_tsd,uint16_t) );
+            break;
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DATUM_TYPE_ALLOWED_ADD:
+                log_it(L_DEBUG,"== DATUM_TYPE_ALLOWED_ADD: %s",
+                       dap_tsd_get_string_const(l_tsd) );
+            break;
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_SENDER_ALLOWED_ADD:
+                log_it(L_DEBUG,"== TX_SENDER_ALLOWED_ADD: binary data");
+            break;
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_SENDER_BLOCKED_ADD:
+                log_it(L_DEBUG,"== TYPE_TX_SENDER_BLOCKED: binary data");
+            break;
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_ALLOWED_ADD:
+                log_it(L_DEBUG,"== TX_RECEIVER_ALLOWED_ADD: binary data");
+            break;
+            case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_BLOCKED_ADD:
+                log_it(L_DEBUG,"== TX_RECEIVER_BLOCKED_ADD: binary data");
+            break;
+            default: log_it(L_DEBUG, "== 0x%04X: binary data %u size ",l_tsd->type, l_tsd->size );
+        }
+        size_t l_tsd_size = dap_tsd_size(l_tsd);
+        memcpy(a_params->ext.parsed_tsd + l_tsd_offset, l_tsd, l_tsd_size);
+        l_tsd_offset += l_tsd_size;
+    }
+    a_params->ext.tsd_total_size = l_tsd_total_size;
+
     return 0;
 }
 
-int s_token_decl_check_params(int a_argc, char ** a_argv, char ** a_str_reply, dap_sdk_cli_params* l_params)
+static int s_token_decl_check_params(int a_argc, char **a_argv, char **a_str_reply, dap_sdk_cli_params *a_params, bool a_update_token)
 {
-    int l_parse_params = s_parse_common_token_decl_arg(a_argc,a_argv,a_str_reply,l_params);
+    int l_parse_params = s_parse_common_token_decl_arg(a_argc,a_argv,a_str_reply,a_params, a_update_token);
     if (l_parse_params)
         return l_parse_params;
 
-    l_parse_params = s_parse_additional_token_decl_arg(a_argc,a_argv,a_str_reply,l_params);
+    l_parse_params = s_parse_additional_token_decl_arg(a_argc,a_argv,a_str_reply,a_params);
     if (l_parse_params)
         return l_parse_params;
 
-
-    dap_chain_datum_token_t * l_datum_token = NULL;
-    size_t l_datum_data_offset = 0;
-
     //DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL uses decimals parameter
-    if (l_params->l_type == DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE || l_params->l_type == DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL){
-        if(!l_params->l_decimals_str) {
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "token_decl requires parameter '-decimals'");
+    if (a_params->type == DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE
+            ||	a_params->type == DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL
+            ||	a_params->type == DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE) {
+        if(!a_params->decimals_str) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "%s requires parameter '-decimals'", a_update_token ? "token_update" : "token_decl");
             return -3;
-        } else if (dap_strcmp(l_params->l_decimals_str, "18")) {
+        } else if (dap_strcmp(a_params->decimals_str, "18")) {
             dap_cli_server_cmd_set_reply_text(a_str_reply,
-                                              "token_decl support '-decimals' to be 18 only");
+                                              "%s support '-decimals' to be 18 only", a_update_token ? "token_update" : "token_decl");
             return -4;
         }
-        if(IS_ZERO_256(l_params->l_total_supply)) {
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "token_decl requires parameter '-total_supply'");
+        if(IS_ZERO_256(a_params->total_supply)) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "%s requires parameter '-total_supply'", a_update_token ? "token_update" : "token_decl");
             return -3;
         }
-    } else if (l_params->l_type == DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL){ //// check l_decimals in CF20 token TODO: At the moment the checks are the same.
-        if(!l_params->l_decimals_str) {
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "token_decl requires parameter '-decimals'");
+    } else if (	a_params->type == DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL
+    ||			a_params->type == DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_UPDATE){
+        //// check l_decimals in CF20 token TODO: At the moment the checks are the same.
+        if(!a_params->decimals_str) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "%s requires parameter '-decimals'", a_update_token ? "token_update" : "token_decl");
             return -3;
-        } else if (dap_strcmp(l_params->l_decimals_str, "18")) {
+        } else if (dap_strcmp(a_params->decimals_str, "18")) {
             dap_cli_server_cmd_set_reply_text(a_str_reply,
-                                              "token_decl support '-decimals' to be 18 only");
+                                              "%s support '-decimals' to be 18 only", a_update_token ? "token_update" : "token_decl");
             return -4;
         }
-        if(IS_ZERO_256(l_params->l_total_supply)) {
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "token_decl requires parameter '-total_supply'");
-            return -3;
-        }
     }
 
-    if (!l_params->l_signs_emission){
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "token_decl requires parameter '-signs_emission'");
+    if (!a_params->signs_emission){
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "%s requires parameter '-signs_emission'", a_update_token ? "token_update" : "token_decl");
         return -5;
     }
 
-    if (!l_params->l_signs_total){
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "token_decl requires parameter 'signs_total'");
+    if (!a_params->signs_total){
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "%s requires parameter '-signs_total'", a_update_token ? "token_update" : "token_decl");
         return -7;
     }
 
-    if(!l_params->l_ticker){
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "token_decl requires parameter '-token'");
+    if(!a_params->ticker){
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "%s requires parameter '-token'", a_update_token ? "token_update" : "token_decl");
         return -2;
     }
 
     // Check certs list
-    if(!l_params->l_certs_str){
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "token_decl requires parameter 'certs'");
+    if(!a_params->certs_str){
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "%s requires parameter 'certs'", a_update_token ? "token_update" : "token_decl");
         return -9;
     }
     return 0;
@@ -3209,9 +2978,9 @@ int com_token_decl(int a_argc, char ** a_argv, char ** a_str_reply)
     if (!l_params)
         return -1;
 
-    l_params->l_type = DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE;
+    l_params->type = DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE;
 
-    int l_parse_params = s_token_decl_check_params(a_argc,a_argv,a_str_reply,l_params);
+    int l_parse_params = s_token_decl_check_params(a_argc,a_argv,a_str_reply,l_params, false);
     if (l_parse_params)
         return l_parse_params;
 
@@ -3219,146 +2988,52 @@ int com_token_decl(int a_argc, char ** a_argv, char ** a_str_reply)
     size_t l_datum_data_offset = 0;
 
     // Load certs lists
-    dap_cert_parse_str_list(l_params->l_certs_str, &l_certs, &l_certs_count);
+    dap_cert_parse_str_list(l_params->certs_str, &l_certs, &l_certs_count);
     if(!l_certs_count){
         dap_cli_server_cmd_set_reply_text(a_str_reply,
                 "token_decl command requres at least one valid certificate to sign token");
         return -10;
     }
 
-    l_signs_emission = l_params->l_signs_emission;
-    l_signs_total = l_params->l_signs_total;
-    l_total_supply = l_params->l_total_supply;
-    l_chain = l_params->l_chain;
-    l_net = l_params->l_net;
-    l_ticker = l_params->l_ticker;
-    l_hash_out_type = l_params->l_hash_out_type;
+    l_signs_emission = l_params->signs_emission;
+    l_signs_total = l_params->signs_total;
+    l_total_supply = l_params->total_supply;
+    l_chain = l_params->chain;
+    l_net = l_params->net;
+    l_ticker = l_params->ticker;
+    l_hash_out_type = l_params->hash_out_type;
 
-    switch(l_params->l_type)
+    switch(l_params->type)
     {
         case DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL:
         case DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL:
         { // 256
-            dap_list_t *l_tsd_list = NULL;
-            size_t l_tsd_total_size = 0;
-            uint16_t l_flags = 0;
-            char ** l_str_flags = NULL;
-
-            if (l_params->ext.flags){   // Flags
-                 l_str_flags = dap_strsplit(l_params->ext.flags,",",0xffff );
-                 while (l_str_flags && *l_str_flags){
-                     uint16_t l_flag = dap_chain_datum_token_flag_from_str(*l_str_flags);
-                     if (l_flag == DAP_CHAIN_DATUM_TOKEN_FLAG_UNDEFINED ){
-                         dap_cli_server_cmd_set_reply_text(a_str_reply, "Flag can't be \"%s\"",*l_str_flags);
-                         return -20;
-                     }
-                     l_flags |= l_flag; // if we have multiple flags
-                     l_str_flags++;
-                }
-            }
-            if (l_params->ext.delegated_token_from) {
-                dap_chain_datum_token_t* l_delegated_token_from;
-                if (NULL == (l_delegated_token_from = dap_chain_ledger_token_ticker_check(l_net->pub.ledger, l_params->ext.delegated_token_from))) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "To create a delegated token %s, can't find token by ticket %s", l_ticker, l_params->ext.delegated_token_from);
-                    return -91;
-                }
-                dap_chain_datum_token_tsd_delegate_from_stake_lock_t l_tsd_section;
-                strcpy(l_tsd_section.ticker_token_from, l_params->ext.delegated_token_from);
-                //				l_tsd_section.token_from = dap_hash_fast();
-                l_tsd_section.emission_rate = dap_chain_coins_to_balance("1.0");//TODO: ???
-                dap_tsd_t* l_tsd = dap_tsd_create_scalar(
-                    DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DELEGATE_EMISSION_FROM_STAKE_LOCK, l_tsd_section);
-                l_tsd_list = dap_list_append(l_tsd_list, l_tsd);
-                l_tsd_total_size += dap_tsd_size(l_tsd);
-            }
-            if (l_params->ext.total_signs_valid){ // Signs valid
-                uint16_t l_param_value = (uint16_t)atoi(l_params->ext.total_signs_valid);
-                l_signs_total = l_param_value;
-                dap_tsd_t * l_tsd = dap_tsd_create_scalar(
-                                                        DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TOTAL_SIGNS_VALID, l_param_value);
-                l_tsd_list = dap_list_append(l_tsd_list, l_tsd);
-                l_tsd_total_size+= dap_tsd_size(l_tsd);
-            }
-            if (l_params->ext.datum_type_allowed){
-                dap_tsd_t * l_tsd = dap_tsd_create_string(
-                                                        DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DATUM_TYPE_ALLOWED_ADD, l_params->ext.datum_type_allowed);
-                l_tsd_list = dap_list_append(l_tsd_list, l_tsd);
-                l_tsd_total_size+= dap_tsd_size(l_tsd);
-            }
-            if (l_params->ext.datum_type_blocked){
-                dap_tsd_t * l_tsd = dap_tsd_create_string(
-                                                        DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DATUM_TYPE_BLOCKED_ADD, l_params->ext.datum_type_blocked);
-                l_tsd_list = dap_list_append(l_tsd_list, l_tsd);
-                l_tsd_total_size+= dap_tsd_size(l_tsd);
-            }
-            if (l_params->ext.tx_receiver_allowed)
-                l_tsd_list = s_parse_wallet_addresses(l_params->ext.tx_receiver_allowed, l_tsd_list, &l_tsd_total_size, DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_ALLOWED_ADD);
-
-            if (l_params->ext.tx_receiver_blocked)
-                l_tsd_list = s_parse_wallet_addresses(l_params->ext.tx_receiver_blocked, l_tsd_list, &l_tsd_total_size, DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_BLOCKED_ADD);
-
-            if (l_params->ext.tx_sender_allowed)
-                l_tsd_list = s_parse_wallet_addresses(l_params->ext.tx_sender_allowed, l_tsd_list, &l_tsd_total_size, DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_SENDER_ALLOWED_ADD);
-
-            if (l_params->ext.tx_sender_blocked)
-                l_tsd_list = s_parse_wallet_addresses(l_params->ext.tx_sender_blocked, l_tsd_list, &l_tsd_total_size, DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_SENDER_BLOCKED_ADD);
-
-
             // Create new datum token
-            l_datum_token = DAP_NEW_Z_SIZE(dap_chain_datum_token_t, sizeof(dap_chain_datum_token_t) + l_tsd_total_size) ;
-            l_datum_token->type = l_params->l_type;
-            if (l_params->l_type == DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL) {
-                log_it(L_DEBUG,"Prepared TSD sections for private token on %zd total size", l_tsd_total_size);
+            l_datum_token = DAP_NEW_Z_SIZE(dap_chain_datum_token_t, sizeof(dap_chain_datum_token_t) + l_params->ext.tsd_total_size) ;
+            l_datum_token->type = l_params->type;
+            if (l_params->type == DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL) {
+                log_it(L_DEBUG,"Prepared TSD sections for private token on %zd total size", l_params->ext.tsd_total_size);
                 dap_snprintf(l_datum_token->ticker, sizeof(l_datum_token->ticker), "%s", l_ticker);
-                l_datum_token->header_private_decl.flags = l_flags;
+                l_datum_token->header_private_decl.flags = l_params->ext.parsed_flags;
                 l_datum_token->total_supply = l_total_supply;
                 l_datum_token->signs_valid = l_signs_emission;
-                l_datum_token->header_private_decl.tsd_total_size = l_tsd_total_size;
-                l_datum_token->header_native_decl.decimals = atoi(l_params->l_decimals_str);
+                l_datum_token->header_private_decl.tsd_total_size = l_params->ext.tsd_total_size;
+                l_datum_token->header_private_decl.decimals = atoi(l_params->decimals_str);
             } else { //DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL
-                log_it(L_DEBUG,"Prepared TSD sections for CF20 token on %zd total size", l_tsd_total_size);
+                log_it(L_DEBUG,"Prepared TSD sections for CF20 token on %zd total size", l_params->ext.tsd_total_size);
                 dap_snprintf(l_datum_token->ticker, sizeof(l_datum_token->ticker), "%s", l_ticker);
-                l_datum_token->header_native_decl.flags = l_flags;
+                l_datum_token->header_native_decl.flags = l_params->ext.parsed_flags;
                 l_datum_token->total_supply = l_total_supply;
                 l_datum_token->signs_valid = l_signs_emission;
-                l_datum_token->header_native_decl.tsd_total_size = l_tsd_total_size;
-                l_datum_token->header_native_decl.decimals = atoi(l_params->l_decimals_str);
+                l_datum_token->header_native_decl.tsd_total_size = l_params->ext.tsd_total_size;
+                l_datum_token->header_native_decl.decimals = atoi(l_params->decimals_str);
             }
             // Add TSD sections in the end
-            for ( dap_list_t* l_iter=dap_list_first(l_tsd_list); l_iter; l_iter=l_iter->next){
-                dap_tsd_t * l_tsd = (dap_tsd_t *) l_iter->data;
-                if (l_tsd == NULL){
-                    log_it(L_ERROR, "NULL tsd in list!");
-                    continue;
-                }
-                switch (l_tsd->type){
-                    case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TOTAL_SIGNS_VALID:
-                        log_it(L_DEBUG,"== TOTAL_SIGNS_VALID: %u",
-                                dap_tsd_get_scalar(l_tsd,uint16_t) );
-                    break;
-                    case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DATUM_TYPE_ALLOWED_ADD:
-                        log_it(L_DEBUG,"== DATUM_TYPE_ALLOWED_ADD: %s",
-                               dap_tsd_get_string_const(l_tsd) );
-                    break;
-                    case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_SENDER_ALLOWED_ADD:
-                        log_it(L_DEBUG,"== TX_SENDER_ALLOWED_ADD: binary data");
-                    break;
-                    case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_SENDER_BLOCKED_ADD:
-                        log_it(L_DEBUG,"== TYPE_TX_SENDER_BLOCKED: binary data");
-                    break;
-                    case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_ALLOWED_ADD:
-                        log_it(L_DEBUG,"== TX_RECEIVER_ALLOWED_ADD: binary data");
-                    break;
-                    case DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_BLOCKED_ADD:
-                        log_it(L_DEBUG,"== TX_RECEIVER_BLOCKED_ADD: binary data");
-                    break;
-                    default: log_it(L_DEBUG, "== 0x%04X: binary data %u size ",l_tsd->type, l_tsd->size );
-                }
-                size_t l_tsd_size = dap_tsd_size(l_tsd);
-                memcpy(l_datum_token->data_n_tsd + l_datum_data_offset, l_tsd, l_tsd_size);
-                l_datum_data_offset += l_tsd_size;
+            if (l_params->ext.tsd_total_size) {
+                memcpy(l_datum_token->data_n_tsd, l_params->ext.parsed_tsd, l_params->ext.tsd_total_size);
+                DAP_DELETE(l_params->ext.parsed_tsd);
             }
-            log_it(L_DEBUG, "%s token declaration '%s' initialized", l_params->l_type == DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL ?
+            log_it(L_DEBUG, "%s token declaration '%s' initialized", l_params->type == DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL ?
                             "Private" : "CF20", l_datum_token->ticker);
         }break;//end
         case DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE: { // 256
@@ -3367,7 +3042,7 @@ int com_token_decl(int a_argc, char ** a_argv, char ** a_str_reply)
             dap_snprintf(l_datum_token->ticker, sizeof(l_datum_token->ticker), "%s", l_ticker);
             l_datum_token->total_supply = l_total_supply;
             l_datum_token->signs_valid = l_signs_emission;
-            l_datum_token->header_native_decl.decimals = atoi(l_params->l_decimals_str);
+            l_datum_token->header_simple.decimals = atoi(l_params->decimals_str);
         }break;
         default:
             dap_cli_server_cmd_set_reply_text(a_str_reply,
@@ -3431,7 +3106,201 @@ int com_token_decl(int a_argc, char ** a_argv, char ** a_str_reply)
     return l_ret;
 }
 
+/**
+ * @brief com_token_decl_update
+ * @param argc
+ * @param argv
+ * @param arg_func
+ * @param str_reply
+ * @return
+ * @details token_update -net <net name> -chain <chain_name> -token <token ticker> [-type private] -flags [<Flag 1>][,<Flag 2>]...[,<Flag N>]...  [-<Param name 1> <Param Value 1>] [-Param name 2> <Param Value 2>] ...[-<Param Name N> <Param Value N>]\n"
+ *  \t   Update token for <netname>:<chain name> with ticker <token ticker>, flags <Flag 1>,<Flag2>...<Flag N>"
+ *  \t   and custom parameters list <Param 1>, <Param 2>...<Param N>."
+ *  \n"
+ *  ==Flags=="
+ *  \t ALL_BLOCKED:\t Blocked all permissions, usefull add it first and then add allows what you want to allow\n"
+ *  \t ALL_ALLOWED:\t Allowed all permissions if not blocked them. Be careful with this mode\n"
+ *  \t ALL_FROZEN:\t All permissions are temprorary frozen\n"
+ *  \t ALL_UNFROZEN:\t Unfrozen permissions\n"
+ *  \t STATIC_ALL:\t No token manipulations after declarations at all. Token declares staticly and can't variabed after\n"
+ *  \t STATIC_FLAGS:\t No token manipulations after declarations with flags\n"
+ *  \t STATIC_PERMISSIONS_ALL:\t No all permissions lists manipulations after declarations\n"
+ *  \t STATIC_PERMISSIONS_DATUM_TYPE:\t No datum type permissions lists manipulations after declarations\n"
+ *  \t STATIC_PERMISSIONS_TX_SENDER:\t No tx sender permissions lists manipulations after declarations\n"
+ *  \t STATIC_PERMISSIONS_TX_RECEIVER:\t No tx receiver permissions lists manipulations after declarations\n"
+    "\n"
+    "==Params==\n"
+    "General:\n"
+    "\t -flags_set <value>:\t Set list of flags from <value> to token declaration\n"
+    "\t -flags_unset <value>:\t Unset list of flags from <value> from token declaration\n"
+    "\t -total_supply <value>:\t Set total supply - emission's maximum - to the <value>\n"
+    "\t -total_signs_valid <value>:\t Set valid signatures count's minimum\n"
+    "\t -total_signs_add <value>:\t Add signature's pkey fingerprint to the list of owners\n"
+    "\t -total_signs_remove <value>:\t Remove signature's pkey fingerprint from the owners\n"
+    "\nDatum type allowed/blocked updates:\n"
+    "\t -datum_type_allowed_add <value>:\t Add allowed datum type(s)\n"
+    "\t -datum_type_allowed_remove <value>:\t Remove datum type(s) from allowed\n"
+    "\t -datum_type_blocked_add <value>:\t Add blocked datum type(s)\n"
+    "\t -datum_type_blocked_remove <value>:\t Remove datum type(s) from blocked\n"
+    "\nTx receiver addresses allowed/blocked updates:\n"
+    "\t -tx_receiver_allowed_add <value>:\t Add allowed tx receiver(s)\n"
+    "\t -tx_receiver_allowed_remove <value>:\t Remove tx receiver(s) from allowed\n"
+    "\t -tx_receiver_blocked_add <value>:\t Add blocked tx receiver(s)\n"
+    "\t -tx_receiver_blocked_remove <value>:\t Remove tx receiver(s) from blocked\n"
+    "\n Tx sender addresses allowed/blocked updates:\n"
+    "\t -tx_sender_allowed_add <value>:\t Add allowed tx sender(s)\n"
+    "\t -tx_sender_allowed_remove <value>:\t Remove tx sender(s) from allowed\n"
+    "\t -tx_sender_blocked_add <value>:\t Add allowed tx sender(s)\n"
+    "\t -tx_sender_blocked_remove <value>:\t Remove tx sender(s) from blocked\n"
+    "\n"
+ */
+int com_token_update(int a_argc, char ** a_argv, char ** a_str_reply)
+{
+    const char * l_ticker = NULL;
+    uint256_t l_total_supply = {}; // 256
+    uint16_t l_signs_emission = 0;
+    uint16_t l_signs_total = 0;
+    dap_cert_t ** l_certs = NULL;
+    size_t l_certs_count = 0;
+
+    dap_chain_t * l_chain = NULL;
+    dap_chain_net_t * l_net = NULL;
+    const char * l_hash_out_type = NULL;
+
+    dap_sdk_cli_params* l_params = DAP_NEW_Z(dap_sdk_cli_params);
+
+    if (!l_params)
+        return -1;
+
+    l_params->type = DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE;
 
+    int l_parse_params = s_token_decl_check_params(a_argc,a_argv,a_str_reply,l_params, true);
+    if (l_parse_params)
+        return l_parse_params;
+
+    dap_chain_datum_token_t * l_datum_token = NULL;
+    size_t l_datum_data_offset = 0;
+
+    // Load certs lists
+    dap_cert_parse_str_list(l_params->certs_str, &l_certs, &l_certs_count);
+    if(!l_certs_count){
+        dap_cli_server_cmd_set_reply_text(a_str_reply,
+                                          "com_token_update command requres at least one valid certificate to sign token");
+        return -10;
+    }
+
+    l_signs_emission = l_params->signs_emission;
+    l_signs_total = l_params->signs_total;
+    l_total_supply = l_params->total_supply;
+    l_chain = l_params->chain;
+    l_net = l_params->net;
+    l_ticker = l_params->ticker;
+    l_hash_out_type = l_params->hash_out_type;
+
+    switch(l_params->type)
+    {
+        case DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE:
+        case DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_UPDATE:
+        { // 256
+            // Create new datum token
+            l_datum_token = DAP_NEW_Z_SIZE(dap_chain_datum_token_t, sizeof(dap_chain_datum_token_t) + l_params->ext.tsd_total_size) ;
+            l_datum_token->type = l_params->type;
+            if (l_params->type == DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_UPDATE) {
+                log_it(L_DEBUG,"Prepared TSD sections for CF20 token on %zd total size", l_params->ext.tsd_total_size);
+                dap_snprintf(l_datum_token->ticker, sizeof(l_datum_token->ticker), "%s", l_ticker);
+                l_datum_token->header_native_update.flags = l_params->ext.parsed_flags;
+                l_datum_token->total_supply = l_total_supply;
+                l_datum_token->signs_valid = l_signs_emission;
+                l_datum_token->header_native_update.tsd_total_size = l_params->ext.tsd_total_size;
+                l_datum_token->header_native_update.decimals = atoi(l_params->decimals_str);
+            } else { // if (l_params->type == DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE) {
+                log_it(L_DEBUG,"Prepared TSD sections for private token on %zd total size", l_params->ext.tsd_total_size);
+                dap_snprintf(l_datum_token->ticker, sizeof(l_datum_token->ticker), "%s", l_ticker);
+                l_datum_token->header_private_update.flags = l_params->ext.parsed_flags;
+                l_datum_token->total_supply = l_total_supply;
+                l_datum_token->signs_valid = l_signs_emission;
+                l_datum_token->header_private_update.tsd_total_size = l_params->ext.tsd_total_size;
+                l_datum_token->header_private_update.decimals = atoi(l_params->decimals_str);
+            }
+            // Add TSD sections in the end
+            // Add TSD sections in the end
+            if (l_params->ext.tsd_total_size) {
+                memcpy(l_datum_token->data_n_tsd, l_params->ext.parsed_tsd, l_params->ext.tsd_total_size);
+                DAP_DELETE(l_params->ext.parsed_tsd);
+            }
+            log_it(L_DEBUG, "%s token declaration update '%s' initialized", (	l_params->type == DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL
+                                                                          ||	l_params->type == DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE)	?
+                                                                     "Private" : "CF20", l_datum_token->ticker);
+        }break;//end
+        case DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE: { // 256
+            l_datum_token = DAP_NEW_Z_SIZE(dap_chain_datum_token_t, sizeof(dap_chain_datum_token_t));
+            l_datum_token->type = DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE; // 256
+            dap_snprintf(l_datum_token->ticker, sizeof(l_datum_token->ticker), "%s", l_ticker);
+            l_datum_token->total_supply = l_total_supply;
+            l_datum_token->signs_valid = l_signs_emission;
+            if (l_params->decimals_str)
+                l_datum_token->header_simple.decimals = atoi(l_params->decimals_str);
+        }break;
+        default:
+            dap_cli_server_cmd_set_reply_text(a_str_reply,
+                                              "Unknown token type");
+            return -8;
+    }
+    // If we have more certs than we need signs - use only first part of the list
+    if(l_certs_count > l_signs_total)
+        l_certs_count = l_signs_total;
+    // Sign header with all certificates in the list and add signs to the end of TSD cetions
+    uint16_t l_sign_counter = 0;
+    l_datum_token = s_sign_cert_in_cycle(l_certs, l_datum_token, l_certs_count, &l_datum_data_offset, &l_sign_counter);
+    l_datum_token->signs_total = l_sign_counter;
+
+    // We skip datum creation opeartion, if count of signed certificates in s_sign_cert_in_cycle is 0.
+    // Usually it happen, when certificate in token_decl or token_update command doesn't contain private data or broken
+    if (!l_datum_token || l_datum_token->signs_total == 0){
+        dap_cli_server_cmd_set_reply_text(a_str_reply,
+                                          "Token declaration update failed. Successful count of certificate signing is 0");
+        return -9;
+    }
+
+    dap_chain_datum_t * l_datum = dap_chain_datum_create(DAP_CHAIN_DATUM_TOKEN_DECL,
+                                                         l_datum_token,
+                                                         sizeof(*l_datum_token) + l_datum_data_offset);
+    DAP_DELETE(l_datum_token);
+    size_t l_datum_size = dap_chain_datum_size(l_datum);
+
+    // Calc datum's hash
+    dap_chain_hash_fast_t l_key_hash;
+    dap_hash_fast(l_datum, l_datum_size, &l_key_hash);
+    char * l_key_str = dap_chain_hash_fast_to_str_new(&l_key_hash);
+    char * l_key_str_out = dap_strcmp(l_hash_out_type, "hex") ?
+                           dap_enc_base58_encode_hash_to_str(&l_key_hash) : l_key_str;
+
+    // Add datum to mempool with datum_token hash as a key
+    char * l_gdb_group_mempool;
+    if (!l_chain)
+        dap_chain_net_get_default_chain_by_chain_type(l_net, CHAIN_TYPE_TOKEN);
+    l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(l_chain);
+    if (!l_gdb_group_mempool) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "No suitable chain for placing token datum found");
+        DAP_DELETE(l_datum);
+        return -10;
+    }
+    int l_ret = 0;
+    bool l_placed = dap_global_db_set_sync(l_gdb_group_mempool, l_key_str, (uint8_t *)l_datum, l_datum_size, false);
+    dap_cli_server_cmd_set_reply_text(a_str_reply, "Datum %s with 256bit token %s is%s placed in datum pool",
+                                      l_key_str_out, l_ticker, l_placed ? "" : " not");
+    //additional checking for incorrect key format
+    if (l_key_str_out != l_key_str)
+        DAP_DELETE(l_key_str);
+    else
+        DAP_DELETE(l_key_str);
+    DAP_DELETE(l_datum);
+    DAP_DELETE(l_params);
+    if (!l_placed) {
+        l_ret = -2;
+    }
+    return l_ret;
+}
 
 /**
  * @brief com_token_emit
@@ -3546,8 +3415,8 @@ int com_token_emit(int a_argc, char ** a_argv, char ** a_str_reply)
         if(l_chain_emission_str) {
             if((l_chain_emission = dap_chain_net_get_chain_by_name(l_net, l_chain_emission_str)) == NULL) { // Can't find such chain
                 dap_cli_server_cmd_set_reply_text(a_str_reply,
-                        "token_create requires parameter '-chain_emission' to be valid chain name in chain net %s or set default datum type in chain configuration file",
-                        l_net->pub.name);
+                                      "token_emit requires parameter '-chain_base_tx' to be valid chain name in chain net %s or set default datum type in chain configuration file "
+                                      "but, if you need create emission has no base transaction, use flag '-no_base_tx'", l_net->pub.name);
                 return -45;
             }
         }
@@ -3580,21 +3449,21 @@ int com_token_emit(int a_argc, char ** a_argv, char ** a_str_reply)
 			DAP_DEL_Z(l_addr);
             return -47;
         }
-		goto CheckTicker;	// --->>
     } else if (no_base_tx < 0) {
 		if((l_chain_base_tx = dap_chain_net_get_default_chain_by_chain_type(l_net, CHAIN_TYPE_TX)) == NULL) { // Can't find such chain
 			dap_cli_server_cmd_set_reply_text(a_str_reply,
-						"token_create requires parameter '-chain_base_tx' to be valid chain name in chain net %s or set default datum type in chain configuration file", l_net->pub.name);
+                                      "token_emit requires parameter '-chain_base_tx' to be valid chain name in chain net %s or set default datum type in chain configuration file "
+                                      "but, if you need create emission has no base transaction, use flag '-no_base_tx'", l_net->pub.name);
+
 			DAP_DEL_Z(l_addr);
 			return -47;
 		}
-		CheckTicker:		// <<---
-		if(!l_ticker) {
-			dap_cli_server_cmd_set_reply_text(a_str_reply, "token_emit requires parameter '-token'");
-			DAP_DEL_Z(l_addr);
-			return -3;
-		}
-	}
+    }
+    if(!l_ticker) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "token_emit requires parameter '-token'");
+        DAP_DEL_Z(l_addr);
+        return -3;
+    }
 
     if (!l_add_sign) {
         if (!l_chain_emission) {
@@ -4593,15 +4462,23 @@ int com_tx_create(int argc, char ** argv, char **str_reply)
 
     if(l_tx_num_str)
         l_tx_num = strtoul(l_tx_num_str, NULL, 10);
-    if(dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &str_tmp)) {
-        l_value_fee = dap_chain_balance_scan(str_tmp);
-    } else {
-        l_value_fee = dap_chain_coins_to_balance("0.1");
-    }
 
-    if(dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &str_tmp)) {
+    if(dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-value", &str_tmp))
         l_value = dap_chain_balance_scan(str_tmp);
+    if(IS_ZERO_256(l_value)) {
+        dap_cli_server_cmd_set_reply_text(str_reply, "tx_create requires parameter '-value' to be valid uint256 value");
+        return -4;
     }
+
+    // Validator's fee
+    if(dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "-fee", &str_tmp))
+        l_value_fee = dap_chain_balance_scan(str_tmp);
+    if (IS_ZERO_256(l_value_fee)) {
+        dap_cli_server_cmd_set_reply_text(str_reply,
+                "tx_create requires parameter '-fee' to be valid uint256");
+        return -5;
+    }
+
     if(!l_from_wallet_name && !l_emission_hash_str) {
         dap_cli_server_cmd_set_reply_text(str_reply, "tx_create requires one of parameters '-from_wallet' or '-from_emission'");
         return -1;
@@ -4655,15 +4532,6 @@ int com_tx_create(int argc, char ** argv, char **str_reply)
             return -5;
         }
     }
-    if(IS_ZERO_256(l_value)) {
-        dap_cli_server_cmd_set_reply_text(str_reply, "tx_create requires parameter '-value' to be valid uint256 value");
-        return -4;
-    }
-    if (IS_ZERO_256(l_value_fee)) {
-        dap_cli_server_cmd_set_reply_text(str_reply,
-                "tx_create requires parameter '-value_fee' to be valid uint256");
-        return -5;
-    }
 
     dap_chain_t *l_chain = NULL;
 	if (l_chain_name) {
@@ -5236,6 +5104,141 @@ int cmd_gdb_import(int argc, char ** argv, char ** a_str_reply)
     return 0;
 }
 
+dap_list_t *s_go_all_nets_offline()
+{
+    dap_list_t *l_net_returns = NULL;
+    uint16_t l_net_count;
+    dap_chain_net_t **l_net_list = dap_chain_net_list(&l_net_count);
+    for (uint16_t i = 0; i < l_net_count; i++) {    // Shutdown all networks
+        if (dap_chain_net_stop(l_net_list[i]))
+            l_net_returns = dap_list_append(l_net_returns, l_net_list[i]);
+    }
+    sleep(2);   // waiting for networks to go offline
+    return l_net_returns;
+}
+
+int cmd_remove(int argc, char ** argv, char ** a_str_reply)
+{
+    //default init
+    const char		*return_message	=	NULL;
+    const char		*l_gdb_path		=	NULL;
+    const char		*l_chains_path	=	NULL;
+    const char		*l_net_str		=	NULL;
+    dap_chain_net_t	*l_net			=	NULL;
+    int 			all				=	0;
+
+    //for enum
+    uint8_t			error			=	0;
+    uint8_t			successful		=	0;
+
+    //enum for errors
+    enum {
+        GDB_FAIL_PATH				=	0x00000001,
+        CHAINS_FAIL_PATH			=	0x00000002,
+        COMMAND_NOT_CORRECT			=	0x00000004,
+        NET_NOT_VALID				=	0x00000008
+    };
+
+    //enum for successful
+    enum {
+        REMOVED_GDB					=	0x00000001,
+        REMOVED_CHAINS				=	0x00000002
+    };
+
+    //check path's from config file
+    if (dap_cli_server_cmd_check_option(argv, 1, argc, "-gdb") >= 0
+    &&	(NULL == (l_gdb_path = dap_config_get_item_str(g_config, "resources", "dap_global_db_path")))){
+        error |= GDB_FAIL_PATH;
+    }
+    if (dap_cli_server_cmd_check_option(argv, 1, argc, "-chains") >= 0
+    &&	(NULL == (l_chains_path = dap_config_get_item_str(g_config, "resources", "dap_chains_path")))) {
+        error |= CHAINS_FAIL_PATH;
+    }
+
+    dap_list_t *l_net_returns = NULL;
+    //perform deletion according to the specified parameters, if the path is specified
+    if (l_gdb_path) {
+        l_net_returns = s_go_all_nets_offline();
+        char *l_gdb_rm_path = dap_strdup_printf("%s/gdb-%s", l_gdb_path,
+                                                dap_config_get_item_str_default(g_config, "resources", "global_db_driver", "mdbx"));
+        dap_rm_rf(l_gdb_rm_path);
+        DAP_DELETE(l_gdb_rm_path);
+        if (!error)
+            successful |= REMOVED_GDB;
+    }
+
+    if (l_chains_path) {
+        dap_cli_server_cmd_find_option_val(argv, 1, argc, "-net", &l_net_str);
+        all = dap_cli_server_cmd_check_option(argv, 1, argc, "-all");
+
+        if	(NULL == l_net_str && all >= 0) {
+            if (NULL == l_gdb_path)
+                l_net_returns = s_go_all_nets_offline();
+            uint16_t l_net_count;
+            dap_chain_net_t **l_net_list = dap_chain_net_list(&l_net_count);
+            for (uint16_t i = 0; i < l_net_count; i++) {
+                char *l_chains_rm_path = dap_strdup_printf("%s/%s", l_chains_path,
+                                                           l_net_list[i]->pub.gdb_groups_prefix);
+                dap_rm_rf(l_chains_rm_path);
+                DAP_DELETE(l_chains_rm_path);
+            }
+            if (!error)
+                successful |= REMOVED_CHAINS;
+
+        } else if	(NULL != l_net_str && all < 0) {
+            if (NULL != (l_net = dap_chain_net_by_name(l_net_str))) {
+                if (NULL == l_gdb_path && dap_chain_net_stop(l_net))
+                    l_net_returns = dap_list_append(l_net_returns, l_net);
+            } else {
+                error |= NET_NOT_VALID;
+            }
+            sleep(1);
+            char *l_chains_rm_path = dap_strdup_printf("%s/%s", l_chains_path, l_net->pub.gdb_groups_prefix);
+            dap_rm_rf(l_chains_rm_path);
+            DAP_DELETE(l_chains_rm_path);
+            if (!error)
+                successful |= REMOVED_CHAINS;
+
+        } else {
+            error |= COMMAND_NOT_CORRECT;
+        }
+    }
+
+    //handling errors
+    if (error & GDB_FAIL_PATH
+    ||	error & CHAINS_FAIL_PATH) {
+        return_message = "The node configuration file does not specify the path to the database and/or chains.\n"
+                         "Please check the cellframe-node.cfg file in the [resources] item for subitems:\n"
+                         "dap_global_db_path=<PATH>\n"
+                         "dap_chains_path=<PATH>";
+    } else if (error & COMMAND_NOT_CORRECT) {
+        return_message = "You need to make a decision whether to remove all chains or a chain from a specific network.\n"
+                         "You cannot use two keys '-net' and '-all' at the same time.\n"
+                         "Be careful, the '-all' option will delete ALL CHAINS and won't ask you for permission!";
+    } else if (error & NET_NOT_VALID) {
+        return_message = "The specified network was not found.\n"
+                         "The list of available networks can be viewed using the command:"
+                         "'net list'";
+    }
+
+    if (error) {
+       dap_cli_server_cmd_set_reply_text(a_str_reply, "Error when deleting, because:\n%s", return_message);
+    }
+    else if (successful) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Successful removal: %s %s", successful & REMOVED_GDB ? "gdb" : "-", successful & REMOVED_CHAINS ? "chains" : "-");
+    } else {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Nothing to delete. Check if the command is correct.\nUse flags: -gdb or/and -chains [-net <net_name> | -all]\n"
+                                                       "Be careful, the '-all' option will delete ALL CHAINS and won't ask you for permission!");
+    }
+
+    for (dap_list_t *it = l_net_returns; it; it = it->next)
+        dap_chain_net_start((dap_chain_net_t *)it->data);
+    dap_list_free(l_net_returns);
+
+    return error;
+}
+
+
 /*
  * block code signer
  */
@@ -5256,8 +5259,6 @@ static int s_sign_file(const char *a_filename, dap_sign_signer_file_t a_flags, c
                        dap_sign_t **a_signed, dap_chain_hash_fast_t *a_hash);
 static int s_signer_cmd(int a_arg_index, int a_argc, char **a_argv, char **a_str_reply);
 static int s_check_cmd(int a_arg_index, int a_argc, char **a_argv, char **a_str_reply);
-static uint8_t *s_byte_to_hex(const char *a_line, size_t *a_size);
-static uint8_t s_get_num(uint8_t a_byte, int a_pp);
 struct opts {
     char *name;
     uint32_t cmd;
@@ -5351,7 +5352,6 @@ static int s_check_cmd(int a_arg_index, int a_argc, char **a_argv, char **a_str_
 
     dap_sign_t *l_sign = NULL;
     dap_chain_datum_t *l_datum = NULL;
-    dap_global_db_obj_t *l_objs = NULL;
     char *l_gdb_group = NULL;
 
     l_gdb_group = dap_chain_net_get_gdb_group_mempool_new(l_chain);
@@ -5385,12 +5385,9 @@ static int s_check_cmd(int a_arg_index, int a_argc, char **a_argv, char **a_str_
         dap_hash_fast(l_datum->data, l_datum->header.data_size, &l_hash_tmp);
     }
 
-
-    dap_chain_cell_id_t l_cell_id = {0};
     dap_chain_atom_iter_t *l_iter = NULL;
     dap_chain_cell_t *l_cell_tmp = NULL;
     dap_chain_cell_t *l_cell = NULL;
-    dap_chain_datum_t *l_datum_tmp = NULL;
     size_t l_size = 0;
 
     HASH_ITER(hh, l_chain->cells, l_cell, l_cell_tmp) {
@@ -5511,7 +5508,6 @@ static int s_signer_cmd(int a_arg_index, int a_argc, char **a_argv, char **a_str
     int l_ret = 0;
     dap_sign_t *l_sign = NULL;
     dap_chain_datum_t *l_datum = NULL;
-    dap_global_db_obj_t *l_objs = NULL;
 
     l_ret = s_get_key_from_file(l_opts_sign[OPT_FILE], l_opts_sign[OPT_MIME], l_opts_sign[OPT_CERT], &l_sign);
     if (!l_ret) {
@@ -5529,9 +5525,6 @@ static int s_signer_cmd(int a_arg_index, int a_argc, char **a_argv, char **a_str
         goto end;
     }
 
-
-    dap_chain_cell_id_t l_cell_id = {0};
-    dap_chain_cell_create_fill(l_chain, l_cell_id);
     l_ret = l_chain->callback_add_datums(l_chain, &l_datum, 1);
 
     dap_hash_fast_t l_hash;
diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c
index b266e418d6cb6f1c0256465617813cb289c0094e..0beb7fc6e02b570bdd0d5e348a68e9e0d480224d 100644
--- a/modules/net/dap_chain_node_cli_cmd_tx.c
+++ b/modules/net/dap_chain_node_cli_cmd_tx.c
@@ -40,6 +40,7 @@
 #include "dap_chain_datum_tx_items.h"
 #include "dap_chain_node_cli.h"
 #include "dap_chain_node_cli_cmd_tx.h"
+#include "dap_chain_net_tx.h"
 
 #define LOG_TAG "chain_node_cli_cmd_tx"
 
@@ -61,17 +62,15 @@ typedef struct dap_chain_tx_hash_processed_ht{
 }dap_chain_tx_hash_processed_ht_t;
 
 /**
- * @brief _dap_chain_tx_hash_processed_ht_free
+ * @brief s_chain_tx_hash_processed_ht_free
  * free l_current_hash->hash, l_current_hash, l_hash_processed
  * @param l_hash_processed dap_chain_tx_hash_processed_ht_t
  */
-void _dap_chain_tx_hash_processed_ht_free(dap_chain_tx_hash_processed_ht_t *l_hash_processed){
-    dap_chain_tx_hash_processed_ht_t *l_tmp;
-    dap_chain_tx_hash_processed_ht_t *l_current_hash;
-    HASH_ITER(hh, l_hash_processed, l_current_hash, l_tmp){
+static void s_dap_chain_tx_hash_processed_ht_free(dap_chain_tx_hash_processed_ht_t *l_hash_processed)
+{
+    dap_chain_tx_hash_processed_ht_t *l_tmp, *l_current_hash;
+    HASH_ITER(hh, l_hash_processed, l_current_hash, l_tmp)
         DAP_FREE(l_current_hash);
-    }
-    DAP_FREE(l_hash_processed);
 }
 
 /**
@@ -382,6 +381,44 @@ char* dap_db_history_tx(dap_chain_hash_fast_t* a_tx_hash, dap_chain_t * a_chain,
     return l_ret_str;
 }
 
+static void s_tx_header_print(dap_string_t *a_str_out, dap_chain_tx_hash_processed_ht_t *a_tx_data_ht,
+                              dap_chain_datum_tx_t *a_tx, dap_chain_atom_iter_t *a_atom_iter,
+                              const char *a_hash_out_type, dap_ledger_t *a_ledger,
+                              dap_chain_hash_fast_t *a_tx_hash)
+{
+    bool l_declined = false;
+    // transaction time
+    char l_time_str[32] = "unknown";                                /* Prefill string */
+    if (a_tx->header.ts_created) {
+        uint64_t l_ts = a_tx->header.ts_created;
+        dap_ctime_r(&l_ts, l_time_str);                             /* Convert ts to  Sat May 17 01:17:08 2014 */
+    }
+    dap_hash_fast(a_tx, dap_chain_datum_tx_get_size(a_tx), a_tx_hash);
+    dap_chain_tx_hash_processed_ht_t *l_tx_data = NULL;
+    HASH_FIND(hh, a_tx_data_ht, a_tx_hash, sizeof(*a_tx_hash), l_tx_data);
+    if (l_tx_data)  // this tx already present in ledger (double)
+        l_declined = true;
+    else {
+        l_tx_data = DAP_NEW_Z(dap_chain_tx_hash_processed_ht_t);
+        l_tx_data->hash = *a_tx_hash;
+        HASH_ADD(hh, a_tx_data_ht, hash, sizeof(*a_tx_hash), l_tx_data);
+        const char *l_token_ticker = dap_chain_ledger_tx_get_token_ticker_by_hash(a_ledger, a_tx_hash);
+        if (!l_token_ticker)
+            l_declined = true;
+    }
+    char *l_tx_hash_str, *l_atom_hash_str;
+    if (!dap_strcmp(a_hash_out_type, "hex")) {
+        l_tx_hash_str = dap_chain_hash_fast_to_str_new(a_tx_hash);
+        l_atom_hash_str = dap_chain_hash_fast_to_str_new(a_atom_iter->cur_hash);
+    } else {
+        l_tx_hash_str = dap_enc_base58_encode_hash_to_str(a_tx_hash);
+        l_atom_hash_str = dap_enc_base58_encode_hash_to_str(a_atom_iter->cur_hash);
+    }
+    dap_string_append_printf(a_str_out, "%s TX hash %s (atom %s) \n\t%s", l_declined ? "DECLINED" : "ACCEPTED",
+                                                                          l_tx_hash_str, l_atom_hash_str, l_time_str);
+    DAP_DELETE(l_tx_hash_str);
+    DAP_DELETE(l_atom_hash_str);
+}
 
 /**
  * @brief dap_db_history_addr
@@ -393,12 +430,10 @@ char* dap_db_history_tx(dap_chain_hash_fast_t* a_tx_hash, dap_chain_t * a_chain,
  * @param a_hash_out_type
  * @return char*
  */
-char* dap_db_history_addr(dap_chain_addr_t * a_addr, 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)
 {
-    char l_time_str[32] = {0};
     dap_string_t *l_str_out = dap_string_new(NULL);
-
-    dap_tx_data_t *l_tx_data_hash = NULL;
+    dap_chain_tx_hash_processed_ht_t *l_tx_data_ht = NULL;
     // load transactions
     dap_chain_atom_iter_t *l_atom_iter = a_chain->callback_atom_iter_create(a_chain, a_chain->cells->id, 0);
     size_t l_atom_size=0;
@@ -406,129 +441,144 @@ char* dap_db_history_addr(dap_chain_addr_t * a_addr, dap_chain_t * a_chain, cons
     if (!l_atom) {
         return NULL;
     }
+    if (!a_chain->callback_atom_get_datums) {
+        log_it(L_WARNING, "Not defined callback_atom_get_datums for chain \"%s\"", a_chain->name);
+        return NULL;
+    }
+    dap_ledger_t *l_ledger = dap_chain_net_by_id(a_chain->net_id)->pub.ledger;
 
     while (l_atom && l_atom_size) {
         size_t l_datums_count = 0;
-        dap_chain_datum_t **l_datums = a_chain->callback_atom_get_datums ? 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);
-            break;
-        }
-
+        dap_chain_datum_t **l_datums = a_chain->callback_atom_get_datums(l_atom, l_atom_size, &l_datums_count);
         for (size_t d = 0; d < l_datums_count; d++) {
-            dap_chain_datum_t *l_datum = l_datums && l_datums_count ? l_datums[d] : NULL;
+            dap_chain_datum_t *l_datum = l_datums ? l_datums[d] : NULL;
             if (!l_datum || l_datum->header.type_id != DAP_CHAIN_DATUM_TX) {
-                // go to next transaction
+                // go to next datum
                 continue;
             }
-            dap_tx_data_t *l_tx_data = DAP_NEW_Z(dap_tx_data_t);
-            // transaction
+            // it's a transaction
+            dap_hash_fast_t l_tx_hash;
             dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_datum->data;
-
-            // find Token items - present in base transaction
-            dap_list_t *l_list_tx_token = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_TOKEN, NULL);
-            // save token name
-            if (l_list_tx_token) {
-                strcpy(l_tx_data->token_ticker,
-                       ((dap_chain_tx_token_t *)l_list_tx_token->data)->header.ticker);
-                dap_list_free(l_list_tx_token);
-            }
-
-            dap_list_t *l_list_in_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN, NULL);
-            if (!l_list_in_items) {         // a bad tx
-                DAP_DELETE(l_tx_data);
+            dap_list_t *l_list_in_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN_ALL, NULL);
+            if (!l_list_in_items) { // a bad tx
                 continue;
             }
             // all in items should be from the same address
-            dap_chain_tx_in_t *l_tx_in = (dap_chain_tx_in_t *)l_list_in_items->data;
-            dap_chain_hash_fast_t *l_tx_prev_hash = &l_tx_in->header.tx_prev_hash;
             dap_chain_addr_t *l_src_addr = NULL;
-            char *l_src_addr_str = NULL;
-            if (!dap_hash_fast_is_blank(l_tx_prev_hash)) {
-                dap_tx_data_t *l_tx_data_prev = NULL;
-                HASH_FIND(hh, l_tx_data_hash, l_tx_prev_hash, sizeof(dap_chain_hash_fast_t), l_tx_data_prev);
-                if (!l_tx_data_prev) {      // prev tx not found - no info for history
-                    dap_list_free(l_list_in_items);
-                    DAP_DELETE(l_tx_data);
-                    continue;
+            bool l_base_tx = false;
+            const char *l_src_token = NULL;
+            int l_src_subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_UNDEFINED;
+            for (dap_list_t *it = l_list_in_items; it; it = it->next) {
+                dap_chain_hash_fast_t *l_tx_prev_hash;
+                int l_tx_prev_out_idx;
+                dap_chain_datum_tx_t *l_tx_prev = NULL;
+                if (*(byte_t *)l_list_in_items->data == TX_ITEM_TYPE_IN) {
+                    dap_chain_tx_in_t *l_tx_in = (dap_chain_tx_in_t *)l_list_in_items->data;
+                    l_tx_prev_hash = &l_tx_in->header.tx_prev_hash;
+                    l_tx_prev_out_idx = l_tx_in->header.tx_out_prev_idx;
+                } else { // TX_ITEM_TYPE_IN_COND
+                    dap_chain_tx_in_cond_t *l_tx_in_cond = (dap_chain_tx_in_cond_t *)l_list_in_items->data;
+                    l_tx_prev_hash = &l_tx_in_cond->header.tx_prev_hash;
+                    l_tx_prev_out_idx = l_tx_in_cond->header.tx_out_prev_idx;
                 }
-
-                strncpy(l_tx_data->token_ticker, l_tx_data_prev->token_ticker, DAP_CHAIN_TICKER_SIZE_MAX);
-
-                dap_chain_datum_tx_t *l_tx_prev;
-                dap_list_t *l_list_prev_out_items = NULL, *l_list_out_prev_item;
-
-                if ( (l_tx_prev = (dap_chain_datum_tx_t *)l_tx_data_prev->datum->data) )
-                    if ( (l_list_prev_out_items = dap_chain_datum_tx_items_get(l_tx_prev, TX_ITEM_TYPE_OUT, NULL)) )
-                        if ( (l_list_out_prev_item = dap_list_nth(l_list_prev_out_items, l_tx_in->header.tx_out_prev_idx)) )
-                            {
-                            l_src_addr = &((dap_chain_tx_out_t *)l_list_out_prev_item->data)->addr;
-                            l_src_addr_str = dap_chain_addr_to_str(l_src_addr);
-                            }
-
-                dap_list_free(l_list_prev_out_items);
+                if (dap_hash_fast_is_blank(l_tx_prev_hash)) {
+                    l_base_tx = true;
+                    dap_chain_tx_token_t *l_token = (dap_chain_tx_token_t *)dap_chain_datum_tx_item_get(
+                                                                            l_tx, NULL, TX_ITEM_TYPE_TOKEN, NULL);
+                    if (l_token)
+                        l_src_token = l_token->header.ticker;
+                    break;
+                }
+                l_tx_prev = a_chain->callback_tx_find_by_hash(a_chain, l_tx_prev_hash);
+                if (l_tx_prev) {
+                    uint8_t *l_prev_out_union = dap_chain_datum_tx_item_get_nth(l_tx_prev, TX_ITEM_TYPE_OUT_ALL, l_tx_prev_out_idx);
+                    if (!l_prev_out_union)
+                        continue;
+                    switch (*l_prev_out_union) {
+                    case TX_ITEM_TYPE_OUT:
+                        l_src_addr = &((dap_chain_tx_out_t *)l_prev_out_union)->addr;
+                        break;
+                    case TX_ITEM_TYPE_OUT_EXT:
+                        l_src_addr = &((dap_chain_tx_out_ext_t *)l_prev_out_union)->addr;
+                        l_src_token = (const char *)(((dap_chain_tx_out_ext_t *)l_prev_out_union)->token);
+                        break;
+                    case TX_ITEM_TYPE_OUT_COND:
+                        l_src_subtype = ((dap_chain_tx_out_cond_t *)l_prev_out_union)->header.subtype;
+                    default:
+                        break;
+                    }
+                }
+                if (!l_src_token)
+                    l_src_token = dap_chain_ledger_tx_get_token_ticker_by_hash(l_ledger, l_tx_prev_hash);
+                if (l_src_addr && memcmp(l_src_addr, a_addr, sizeof(dap_chain_addr_t)))
+                    break;  //it's not our addr
             }
             dap_list_free(l_list_in_items);
 
-            dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_tx_data->tx_hash);
-
-            // transaction time
-            l_time_str[0] = ' ', l_time_str[1] = '\0';                      /* Prefill string with the space */
-
-            if ( l_tx->header.ts_created) {
-                uint64_t l_ts = l_tx->header.ts_created;
-                dap_ctime_r(&l_ts, l_time_str);                             /* Convert ts to  Sat May 17 01:17:08 2014 */
-            }
-
-            char *l_tx_hash_str;
-            if (!dap_strcmp(a_hash_out_type, "hex"))
-                l_tx_hash_str = dap_hash_fast_to_str_new(&l_tx_data->tx_hash);
-            else
-                l_tx_hash_str = dap_enc_base58_encode_to_str(&l_tx_data->tx_hash_str, sizeof(dap_chain_hash_fast_t));
-
             // find OUT items
             bool l_header_printed = false;
-            dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT, NULL);
+            dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT_ALL, NULL);
             for (dap_list_t *l_list_out = l_list_out_items; l_list_out; l_list_out = dap_list_next(l_list_out)) {
-                dap_chain_tx_out_t *l_tx_out = (dap_chain_tx_out_t *)l_list_out->data;
-                if (l_src_addr && !memcmp(&l_tx_out->addr, l_src_addr, sizeof(dap_chain_addr_t)))
+                dap_chain_addr_t *l_dst_addr = NULL;
+                uint8_t l_type = *(uint8_t *)l_list_out->data;
+                uint256_t l_value;
+                switch (l_type) {
+                case TX_ITEM_TYPE_OUT:
+                    l_dst_addr = &((dap_chain_tx_out_t *)l_list_out->data)->addr;
+                    l_value = ((dap_chain_tx_out_t *)l_list_out->data)->header.value;
+                    break;
+                case TX_ITEM_TYPE_OUT_EXT:
+                    l_dst_addr = &((dap_chain_tx_out_ext_t *)l_list_out->data)->addr;
+                    l_value = ((dap_chain_tx_out_ext_t *)l_list_out->data)->header.value;
+                    break;
+                case TX_ITEM_TYPE_OUT_COND:
+                    l_value = ((dap_chain_tx_out_cond_t *)l_list_out->data)->header.value;
+                default:
+                    break;
+                }
+                if (l_src_addr && l_dst_addr && !memcmp(l_dst_addr, l_src_addr, sizeof(dap_chain_addr_t)))
                     continue;   // send to self
                 if (l_src_addr && !memcmp(l_src_addr, a_addr, sizeof(dap_chain_addr_t))) {
                     if (!l_header_printed) {
-                        dap_string_append_printf(l_str_out, "TX hash %s\n\t%s", l_tx_hash_str, l_time_str);
+                        s_tx_header_print(l_str_out, l_tx_data_ht, l_tx, l_atom_iter, a_hash_out_type, l_ledger, &l_tx_hash);
                         l_header_printed = true;
                     }
-                    char *l_dst_addr_str = dap_chain_addr_to_str(&l_tx_out->addr);
-                    char *l_value_str = dap_chain_balance_print(l_tx_out->header.value);
+                    //const char *l_token_ticker = dap_chain_ledger_tx_get_token_ticker_by_hash(l_ledger, &l_tx_hash);
+                    const char *l_dst_addr_str = l_dst_addr ? dap_chain_addr_to_str(l_dst_addr)
+                                                            : dap_chain_tx_out_cond_subtype_to_str(
+                                                                  ((dap_chain_tx_out_cond_t *)l_list_out->data)->header.subtype);
+                    char *l_value_str = dap_chain_balance_print(l_value);
                     dap_string_append_printf(l_str_out, "\tsend %s %s to %s\n",
                                              l_value_str,
-                                             l_tx_data->token_ticker,
+                                             l_src_token ? l_src_token : "UNKNOWN",
                                              l_dst_addr_str);
-                    DAP_DELETE(l_dst_addr_str);
+                    if (l_dst_addr)
+                        DAP_DELETE(l_dst_addr_str);
                     DAP_DELETE(l_value_str);
                 }
-                if (!memcmp(&l_tx_out->addr, a_addr, sizeof(dap_chain_addr_t))) {
+                if (l_dst_addr && !memcmp(l_dst_addr, a_addr, sizeof(dap_chain_addr_t))) {
                     if (!l_header_printed) {
-                        dap_string_append_printf(l_str_out, "TX hash %s\n\t%s", l_tx_hash_str, l_time_str);
+                        s_tx_header_print(l_str_out, l_tx_data_ht, l_tx, l_atom_iter, a_hash_out_type, l_ledger, &l_tx_hash);
                         l_header_printed = true;
                     }
-                    char *l_value_str = dap_chain_balance_print(l_tx_out->header.value);
+                    const char *l_dst_token = (l_type == TX_ITEM_TYPE_OUT_EXT) ?
+                                (const char *)(((dap_chain_tx_out_ext_t *)l_list_out->data)->token) : NULL;
+                    const char *l_src_addr_str = l_base_tx ? "emission"
+                                                           : (l_src_addr ? dap_chain_addr_to_str(l_src_addr)
+                                                                         : dap_chain_tx_out_cond_subtype_to_str(
+                                                                               l_src_subtype));
+                    char *l_value_str = dap_chain_balance_print(l_value);
                     dap_string_append_printf(l_str_out, "\trecv %s %s from %s\n",
                                              l_value_str,
-                                             l_tx_data->token_ticker,
-                                             l_src_addr ? l_src_addr_str : "emission");
+                                             l_dst_token ? l_dst_token :
+                                                           (l_src_token ? l_src_token : "UNKNOWN"),
+                                             l_src_addr_str);
+                    if (l_src_addr)
+                        DAP_DELETE(l_src_addr_str);
                     DAP_DELETE(l_value_str);
                 }
             }
             dap_list_free(l_list_out_items);
-            DAP_DELETE(l_src_addr_str);
-            DAP_DELETE(l_tx_hash_str);
-
-            size_t l_datum_size = dap_chain_datum_tx_get_size(l_tx) + sizeof(dap_chain_datum_t);
-            l_tx_data->datum = DAP_NEW_SIZE(dap_chain_datum_t, l_datum_size);
-            memcpy(l_tx_data->datum, l_datum, l_datum_size);        // for GDB chains with data replace with each itreation
-            HASH_ADD(hh, l_tx_data_hash, tx_hash, sizeof(dap_chain_hash_fast_t), l_tx_data);
         }
         DAP_DELETE(l_datums);
         // go to next atom (event or block)
@@ -536,13 +586,7 @@ char* dap_db_history_addr(dap_chain_addr_t * a_addr, dap_chain_t * a_chain, cons
     }
 
     // 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 struct
-        DAP_DELETE(l_iter_current->datum);
-        DAP_DELETE(l_iter_current);
-    }
+    s_dap_chain_tx_hash_processed_ht_free(l_tx_data_ht);
     // if no history
     if(!l_str_out->len)
         dap_string_append(l_str_out, "\tempty");
@@ -561,6 +605,10 @@ char* dap_db_history_addr(dap_chain_addr_t * a_addr, dap_chain_t * a_chain, cons
  */
 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)
 {
+    if (!a_chain->callback_atom_get_datums) {
+        log_it(L_WARNING, "Not defined callback_atom_get_datums for chain \"%s\"", a_chain->name);
+        return NULL;
+    }
     dap_string_t *l_str_out = dap_string_new(NULL);
     *a_token_num  = 0;
     size_t l_atom_size = 0;
@@ -572,7 +620,7 @@ static char* dap_db_history_token_list(dap_chain_t * a_chain, const char *a_toke
             return NULL ;
         }
         for (dap_chain_atom_ptr_t l_atom = a_chain->callback_atom_iter_get_first(l_atom_iter, &l_atom_size);
-            l_atom && l_atom_size; l_atom = a_chain->callback_atom_iter_get_next(l_atom_iter, &l_atom_size)) {
+                l_atom && l_atom_size; l_atom = a_chain->callback_atom_iter_get_next(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, &l_datums_count);
             for(size_t l_datum_n = 0; l_datum_n < l_datums_count; l_datum_n++) {
@@ -612,6 +660,10 @@ static char* dap_db_history_token_list(dap_chain_t * a_chain, const char *a_toke
  */
 static char* dap_db_history_filter(dap_chain_t * a_chain, dap_ledger_t *a_ledger, 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_chain_tx_hash_processed_ht_t *a_tx_hash_processed)
 {
+    if (!a_chain->callback_atom_get_datums) {
+        log_it(L_WARNING, "Not defined callback_atom_get_datums for chain \"%s\"", a_chain->name);
+        return NULL;
+    }
     dap_string_t *l_str_out = dap_string_new(NULL);
     // list all transactions
     dap_tx_data_t *l_tx_data_hash = NULL;
@@ -620,36 +672,28 @@ static char* dap_db_history_filter(dap_chain_t * a_chain, dap_ledger_t *a_ledger
         // load transactions
         size_t l_atom_size = 0;
         dap_chain_atom_iter_t *l_atom_iter = a_chain->callback_atom_iter_create(a_chain, l_cell->id, 0);
-        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) {
+        for (dap_chain_atom_ptr_t l_atom = a_chain->callback_atom_iter_get_first(l_atom_iter, &l_atom_size);
+                l_atom && l_atom_size; l_atom = a_chain->callback_atom_iter_get_next(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 ;
-            }
+            dap_chain_datum_t **l_datums = a_chain->callback_atom_get_datums(l_atom, l_atom_size, &l_datums_count);
+            if (!l_datums || !l_datums_count)
+                continue;
             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) {
+                if(!l_datum)
                     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) {
-
+                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;
-                    }
-
+                    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
@@ -708,16 +752,14 @@ static char* dap_db_history_filter(dap_chain_t * a_chain, dap_ledger_t *a_ledger
                     l_tx_num++;
                 } break;
 
-                default:
-                    dap_string_append_printf(l_str_out, "unknown datum type=%d\n", l_datum->header.type_id);
-                    break;
+                default: {
+                    const char *l_type_str;
+                    DAP_DATUM_TYPE_STR(l_datum->header.type_id, l_type_str);
+                    dap_string_append_printf(l_str_out, "datum type %s\n", l_type_str);
+                    } 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
@@ -866,15 +908,14 @@ int com_ledger(int a_argc, char ** a_argv, char **a_str_reply)
         }
         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)
+        if (l_chain)
             l_chain_cur = l_chain;
         // all chain
         else
-            l_chain_cur = dap_chain_enum(&l_chain_tmp);
-        while(l_chain_cur) {
+            l_chain_cur = l_net->pub.chains;
+        while (l_chain_cur) {
             // only selected net
             if(l_net->pub.id.uint64 == l_chain_cur->net_id.uint64) {
                 // separator between chains
@@ -910,11 +951,10 @@ int com_ledger(int a_argc, char ** a_argv, char **a_str_reply)
             // only one chain use
             if(l_chain)
                 break;
-            dap_chain_enum_unlock();
-            l_chain_cur = dap_chain_enum(&l_chain_tmp);
+            l_chain_cur = l_chain_cur->next;
         }
         DAP_DELETE(l_addr);
-        _dap_chain_tx_hash_processed_ht_free(l_list_tx_hash_processd);
+        s_dap_chain_tx_hash_processed_ht_free(l_list_tx_hash_processd);
         // all chain
         if(!l_chain)
             dap_chain_enum_unlock();
@@ -1218,7 +1258,7 @@ int com_token(int a_argc, char ** a_argv, char **a_str_reply)
                 l_chain_cur = dap_chain_enum(&l_chain_tmp);
             }
             dap_chain_enum_unlock();
-            _dap_chain_tx_hash_processed_ht_free(l_list_tx_hash_processd);
+            s_dap_chain_tx_hash_processed_ht_free(l_list_tx_hash_processd);
             dap_cli_server_cmd_set_reply_text(a_str_reply, l_str_out->str);
             dap_string_free(l_str_out, true);
             return 0;
diff --git a/modules/net/dap_chain_node_client.c b/modules/net/dap_chain_node_client.c
index 056da9cba38412bfe56a29478016856fe4a7e92d..74acc571aa544b61af1353f8141034d468bd56a4 100644
--- a/modules/net/dap_chain_node_client.c
+++ b/modules/net/dap_chain_node_client.c
@@ -136,6 +136,31 @@ static void s_stage_status_callback(dap_client_t *a_client, void *a_arg)
     //printf("* stage_status_callback client=%x data=%x\n", a_client, a_arg);
 }
 
+static bool s_timer_node_reconnect(void *a_arg)
+{
+    dap_events_socket_uuid_t *l_uuid = (dap_events_socket_uuid_t *)a_arg;
+    assert(l_uuid);
+    dap_chain_node_client_handle_t *l_client_found = NULL;
+    HASH_FIND(hh, s_clients, l_uuid, sizeof(*l_uuid), l_client_found);
+    if(l_client_found) {
+        dap_chain_node_client_t *l_me = l_client_found->client;
+        if (l_me->keep_connection && l_me->state == NODE_CLIENT_STATE_DISCONNECTED) {
+            if (dap_client_pvt_find(l_me->client->pvt_uuid)) {
+                if (dap_client_get_stage(l_me->client) == STAGE_BEGIN) {
+                    log_it(L_INFO, "Reconnecting node client with peer "NODE_ADDR_FP_STR, NODE_ADDR_FP_ARGS_S(l_me->remote_node_addr));
+                    l_me->state = NODE_CLIENT_STATE_CONNECTING ;
+                    dap_client_go_stage(l_me->client, STAGE_STREAM_STREAMING, s_stage_connected_callback);
+                } else {
+                    dap_chain_node_client_close(*l_uuid);
+                }
+            } else
+                dap_chain_node_client_close(*l_uuid);
+        }
+    }
+    DAP_DELETE(l_uuid);
+    return false;
+}
+
 /**
  * @brief s_stage_status_error_callback
  * @param a_client
@@ -167,20 +192,13 @@ static void s_stage_status_error_callback(dap_client_t *a_client, void *a_arg)
             l_node_client->callbacks.disconnected(l_node_client, l_node_client->callbacks_arg);
         }
         if (l_node_client->keep_connection) {
-            dap_events_socket_uuid_t *l_uuid = DAP_DUP(&l_node_client->uuid);
-            if(l_node_client->stream_worker){
-                l_node_client->sync_timer = dap_timerfd_start_on_worker(  l_node_client->stream_worker->worker
-                                                                      ,  s_timer_update_states * 1000,
-                                                                    s_timer_update_states_callback,
-                                                                    l_uuid);
-            }else{
-                log_it(L_ERROR,"After NODE_CLIENT_STATE_DISCONNECTED: Node client has no worker, too dangerous to run update states in alien context");
-            }
-        }
-        return;
-    }
-    // TODO make different error codes
-    if(l_node_client->callbacks.error)
+            if (dap_client_get_stage(l_node_client->client) != STAGE_BEGIN)
+                dap_client_go_stage(l_node_client->client, STAGE_BEGIN, NULL);
+            dap_timerfd_start(45 * 1000, s_timer_node_reconnect, DAP_DUP(&l_node_client->uuid));
+        } else
+            dap_chain_node_client_close(l_node_client->uuid);
+
+    } else if(l_node_client->callbacks.error) // TODO make different error codes
         l_node_client->callbacks.error(l_node_client, EINVAL, l_node_client->callbacks_arg);
 }
 
@@ -284,19 +302,18 @@ static bool s_timer_update_states_callback(void *a_arg)
                         dap_client_go_stage(l_me->client, STAGE_BEGIN, NULL);
                         return true;
                     }
-                    if (l_me->callbacks.disconnected) {
+                    if (l_me->is_connected && l_me->callbacks.disconnected)
                         l_me->callbacks.disconnected(l_me, l_me->callbacks_arg);
-                    }
                     if (l_me->keep_connection) {
                         log_it(L_INFO, "Reconnecting node client with peer "NODE_ADDR_FP_STR, NODE_ADDR_FP_ARGS_S(l_me->remote_node_addr));
                         l_me->state = NODE_CLIENT_STATE_CONNECTING ;
                         dap_client_go_stage(l_me->client, STAGE_STREAM_STREAMING, s_stage_connected_callback);
                         return true;
                     } else {
-                        dap_chain_node_client_close(l_me);
+                        dap_chain_node_client_close(*l_uuid);
                     }
                 } else
-                    dap_chain_node_client_close(l_me);
+                    dap_chain_node_client_close(*l_uuid);
             }
         }
         DAP_DELETE(l_uuid);
@@ -582,7 +599,7 @@ static void s_ch_chain_callback_notify_packet_out(dap_stream_ch_chain_t* a_ch_ch
             }
         } break;
         case DAP_STREAM_CH_CHAIN_PKT_TYPE_DELETE: {
-            dap_chain_node_client_close(l_node_client);
+            dap_chain_node_client_close(l_node_client->uuid);
         } break;
         default: {
         }
@@ -813,7 +830,7 @@ static bool dap_chain_node_client_connect_internal(dap_chain_node_client_t *a_no
     }
     // address not defined
     if(!strcmp(host, "::")) {
-        dap_chain_node_client_close(a_node_client);
+        dap_chain_node_client_close(a_node_client->uuid);
         return false;
     }
     dap_client_set_uplink_unsafe(a_node_client->client, host, a_node_client->info->hdr.ext_port);
@@ -848,62 +865,64 @@ void dap_chain_node_client_reset(dap_chain_node_client_t *a_client)
     }
 }
 
+dap_chain_node_client_t *dap_chain_node_client_find(dap_events_socket_uuid_t a_uuid)
+{
+    dap_chain_node_client_handle_t * l_client_found = NULL;
+    HASH_FIND(hh,s_clients, &a_uuid, sizeof(a_uuid), l_client_found);
+    return l_client_found ? l_client_found->client : NULL;
+}
 
 /**
  * @brief dap_chain_node_client_close
  * Close connection to server, delete chain_node_client_t *client
  * @param a_client dap_chain_node_client_t
  */
-void dap_chain_node_client_close(dap_chain_node_client_t *a_client)
+void dap_chain_node_client_close(dap_events_socket_uuid_t a_uuid)
 {
-    if (!a_client)
-        return;
     dap_chain_node_client_handle_t * l_client_found = NULL;
-    HASH_FIND(hh,s_clients,&a_client->uuid,sizeof(a_client->uuid),l_client_found);
+    HASH_FIND(hh, s_clients, &a_uuid, sizeof(a_uuid), l_client_found);
     if (l_client_found) {
-
-        if (l_client_found->client->sync_timer) {
-            // Free memory callback_arg=uuid
-            DAP_DELETE(l_client_found->client->sync_timer->callback_arg);
-            dap_timerfd_delete(l_client_found->client->sync_timer);
+        dap_chain_node_client_t *l_client = l_client_found->client;
+        if (l_client->sync_timer) {
+            DAP_DELETE(l_client->sync_timer->callback_arg);
+            dap_timerfd_delete(l_client->sync_timer);
         }
-
         HASH_DEL(s_clients,l_client_found);
         DAP_DELETE(l_client_found);
-        if (a_client->callbacks.delete)
-            a_client->callbacks.delete(a_client, a_client->net);
+        if (l_client->callbacks.delete)
+            l_client->callbacks.delete(l_client, l_client->net);
         char l_node_addr_str[INET_ADDRSTRLEN] = {};
-        inet_ntop(AF_INET, &a_client->info->hdr.ext_addr_v4, l_node_addr_str, INET_ADDRSTRLEN);
-        log_it(L_INFO, "Closing node client to uplink %s:%d", l_node_addr_str, a_client->info->hdr.ext_port);
-        if (a_client->stream_worker) {
-            dap_stream_ch_t *l_ch = dap_stream_ch_find_by_uuid_unsafe(a_client->stream_worker, a_client->ch_chain_uuid);
+        inet_ntop(AF_INET, &l_client->info->hdr.ext_addr_v4, l_node_addr_str, INET_ADDRSTRLEN);
+        log_it(L_INFO, "Closing node client to uplink %s:%d", l_node_addr_str, l_client->info->hdr.ext_port);
+        if (l_client->stream_worker) {
+            dap_stream_ch_t *l_ch = dap_stream_ch_find_by_uuid_unsafe(l_client->stream_worker, l_client->ch_chain_uuid);
             if (l_ch) {
                 dap_stream_ch_chain_t *l_ch_chain = DAP_STREAM_CH_CHAIN(l_ch);
                 l_ch_chain->callback_notify_packet_in = NULL;
                 l_ch_chain->callback_notify_packet_out = NULL;
             }
-            l_ch = dap_stream_ch_find_by_uuid_unsafe(a_client->stream_worker, a_client->ch_chain_net_uuid);
+            l_ch = dap_stream_ch_find_by_uuid_unsafe(l_client->stream_worker, l_client->ch_chain_net_uuid);
             if (l_ch) {
                 dap_stream_ch_chain_net_t *l_ch_chain_net = DAP_STREAM_CH_CHAIN_NET(l_ch);
                 l_ch_chain_net->notify_callback = NULL;
             }
         }
         // clean client
-        dap_client_pvt_t *l_client_pvt = dap_client_pvt_find(a_client->client->pvt_uuid);
+        dap_client_pvt_t *l_client_pvt = dap_client_pvt_find(l_client->client->pvt_uuid);
         if (l_client_pvt) {
-            dap_client_delete_mt(a_client->client);
-            a_client->client->_inheritor = NULL;
+            dap_client_delete_mt(l_client->client);
+            l_client->client->_inheritor = NULL;
         }
 #ifndef _WIN32
-        pthread_cond_destroy(&a_client->wait_cond);
+        pthread_cond_destroy(&l_client->wait_cond);
 #else
-        CloseHandle( a_client->wait_cond );
+        CloseHandle( l_client->wait_cond );
 #endif
-        pthread_mutex_destroy(&a_client->wait_mutex);
-        a_client->client = NULL;
-        if (a_client->info)
-            DAP_DELETE(a_client->info);
-        DAP_DELETE(a_client);
+        pthread_mutex_destroy(&l_client->wait_mutex);
+        l_client->client = NULL;
+        if (l_client->info)
+            DAP_DELETE(l_client->info);
+        DAP_DELETE(l_client);
     } else {
         log_it(L_WARNING, "Chain node client was removed from hash table before for some reasons");
     }
diff --git a/modules/net/dap_chain_node_remote.c b/modules/net/dap_chain_node_remote.c
deleted file mode 100644
index cabf4dd34e4b5e07bcf67b93169b5a38f6a54636..0000000000000000000000000000000000000000
--- a/modules/net/dap_chain_node_remote.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Authors:
- * Dmitriy A. Gearasimov <naeper@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
-
- This file is part of DAP (Deus Applications Prototypes) the open source project
-
- DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- DAP is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <time.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <pthread.h>
-
-#ifdef WIN32
-#include <winsock2.h>
-#include <windows.h>
-#include <mswsock.h>
-#include <ws2tcpip.h>
-#include <io.h>
-#endif
-
-#include "uthash.h"
-#include "dap_common.h"
-#include "dap_chain_node_remote.h"
-
-typedef struct dap_chain_node_link_item {
-    dap_chain_node_addr_t address;
-    dap_chain_node_client_t *client;
-    UT_hash_handle hh;
-} dap_chain_node_link_item_t;
-
-// List of connections
-static dap_chain_node_link_item_t *conn_list = NULL;
-
-// for separate access to connect_list
-static pthread_mutex_t connect_list_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-
-/**
- * Add new established connection to the list
- *
- * return 0 OK, -1 error, -2 already present
- */
-int dap_chain_node_client_list_add(dap_chain_node_addr_t *a_address, dap_chain_node_client_t *a_client)
-{
-    int l_ret = 0;
-    if(!a_address || !a_client)
-        return -1;
-    dap_chain_node_link_item_t *item_tmp = NULL;
-    pthread_mutex_lock(&connect_list_mutex);
-    HASH_FIND(hh, conn_list, a_address, sizeof(dap_chain_node_addr_t), item_tmp); // address already in the hash?
-    if(item_tmp == NULL) {
-        item_tmp = DAP_NEW(dap_chain_node_link_item_t);
-        item_tmp->address.uint64 = a_address->uint64;
-        item_tmp->client = a_client;
-        HASH_ADD(hh, conn_list, address, sizeof(dap_chain_node_addr_t), item_tmp); // address: name of key field
-        l_ret = 0;
-    }
-    // connection already present
-    else
-        l_ret = -2;
-    //connect_list = g_list_append(connect_list, client);
-    pthread_mutex_unlock(&connect_list_mutex);
-    return l_ret;
-}
-
-/**
- * Delete established connection from the list
- *
- * return 0 OK, -1 error, -2 address not found
- */
-int chain_node_client_list_del(dap_chain_node_addr_t *address)
-{
-    int ret = -1;
-    if(!address)
-        return -1;
-    dap_chain_node_link_item_t *item_tmp;
-    pthread_mutex_lock(&connect_list_mutex);
-    HASH_FIND(hh, conn_list, address, sizeof(dap_chain_node_addr_t), item_tmp);
-    if(item_tmp != NULL) {
-        HASH_DEL(conn_list, item_tmp);
-        ret = 0;
-    }
-    else
-        // address not found in the hash
-        ret = -2;
-    pthread_mutex_unlock(&connect_list_mutex);
-    if(!ret) {
-        // close connection
-        dap_chain_node_client_close(item_tmp->client);
-        // del struct for hash
-        DAP_DELETE(item_tmp);
-    }
-    return ret;
-}
-
-/**
- * Delete all established connection from the list
- */
-void chain_node_client_list_del_all(void)
-{
-    int ret = -1;
-    dap_chain_node_link_item_t *iter_current, *item_tmp;
-    pthread_mutex_lock(&connect_list_mutex);
-    HASH_ITER(hh, conn_list , iter_current, item_tmp) {
-        // close connection
-        dap_chain_node_client_close(iter_current->client);
-        // del struct for hash
-        HASH_DEL(conn_list, iter_current);
-    }
-    pthread_mutex_unlock(&connect_list_mutex);
-}
-
-/**
- * Get present established connection by address
- *
- * return client, or NULL if the connection not found in the list
- */
-const dap_chain_node_client_t* chain_node_client_find(dap_chain_node_addr_t *address)
-{
-    int ret = 0;
-    if(!address)
-        return NULL;
-    dap_chain_node_client_t *client_ret = NULL;
-    dap_chain_node_link_item_t *item_tmp;
-    pthread_mutex_lock(&connect_list_mutex);
-    HASH_FIND(hh, conn_list, address, sizeof(dap_chain_node_addr_t), item_tmp); // address already in the hash?
-    if(item_tmp != NULL) {
-        client_ret = item_tmp->client;
-    }
-    pthread_mutex_unlock(&connect_list_mutex);
-    return client_ret;
-}
diff --git a/modules/net/include/dap_chain_net.h b/modules/net/include/dap_chain_net.h
index 5dee1800032bb6a3f0c21ba8b11df3e2316b63cd..a1fd95757fcc9999c582f5de3964fdeb9074352b 100644
--- a/modules/net/include/dap_chain_net.h
+++ b/modules/net/include/dap_chain_net.h
@@ -81,12 +81,14 @@ typedef struct dap_chain_net{
         bool mempool_autoproc;
 
         dap_chain_t * chains; // double-linked list of chains
-        dap_chain_t * default_chain;
+        const char *native_ticker;
         dap_ledger_t  *ledger;
     } pub;
     uint8_t pvt[];
 } dap_chain_net_t;
 
+typedef bool (dap_chain_datum_filter_func_t)(dap_chain_datum_t *a_datum, dap_chain_t * a_chain, void *a_filter_func_param);
+
 int dap_chain_net_init(void);
 void dap_chain_net_deinit(void);
 
@@ -94,15 +96,24 @@ void dap_chain_net_load_all();
 
 int dap_chain_net_state_go_to(dap_chain_net_t * a_net, dap_chain_net_state_t a_new_state);
 dap_chain_net_state_t dap_chain_net_get_target_state(dap_chain_net_t *a_net);
+void dap_chain_net_set_state ( dap_chain_net_t * l_net, dap_chain_net_state_t a_state);
+dap_chain_net_state_t dap_chain_net_get_state ( dap_chain_net_t * l_net);
 
 inline static int dap_chain_net_start(dap_chain_net_t * a_net){ return dap_chain_net_state_go_to(a_net,NET_STATE_ONLINE); }
-inline static int dap_chain_net_stop(dap_chain_net_t * a_net) { return dap_chain_net_state_go_to(a_net,NET_STATE_OFFLINE); }
+inline static int dap_chain_net_stop(dap_chain_net_t *a_net)
+{
+    if (dap_chain_net_get_target_state(a_net) == NET_STATE_ONLINE) {
+        dap_chain_net_state_go_to(a_net, NET_STATE_OFFLINE);
+        return true;
+    }
+    if (dap_chain_net_get_state(a_net) != NET_STATE_OFFLINE)
+        dap_chain_net_state_go_to(a_net, NET_STATE_OFFLINE);
+    return false;
+}
 inline static int dap_chain_net_links_establish(dap_chain_net_t * a_net) { return dap_chain_net_state_go_to(a_net,NET_STATE_LINKS_ESTABLISHED); }
 inline static int dap_chain_net_sync_gdb(dap_chain_net_t * a_net) { return dap_chain_net_state_go_to(a_net,NET_STATE_SYNC_GDB); }
 inline static int dap_chain_net_sync_chains(dap_chain_net_t * a_net) { return dap_chain_net_state_go_to(a_net,NET_STATE_SYNC_CHAINS); }
 inline static int dap_chain_net_sync_all(dap_chain_net_t * a_net) { return dap_chain_net_state_go_to(a_net,NET_STATE_SYNC_CHAINS); }
-void dap_chain_net_set_state ( dap_chain_net_t * l_net, dap_chain_net_state_t a_state);
-dap_chain_net_state_t dap_chain_net_get_state ( dap_chain_net_t * l_net);
 
 /**
  * @brief dap_chain_net_state_to_str
@@ -127,7 +138,7 @@ bool dap_chain_net_sync_trylock_nolock(dap_chain_net_t* a_net, dap_chain_node_cl
 
 dap_chain_net_t * dap_chain_net_by_name( const char * a_name);
 dap_chain_net_t * dap_chain_net_by_id( dap_chain_net_id_t a_id);
-uint16_t dap_chain_net_acl_idx_by_id(dap_chain_net_id_t a_id);
+uint16_t dap_chain_net_get_acl_idx(dap_chain_net_t *a_net);
 dap_chain_net_id_t dap_chain_net_id_by_name( const char * a_name);
 dap_ledger_t * dap_chain_ledger_by_net_name( const char * a_net_name);
 dap_string_t* dap_cli_list_net();
@@ -141,55 +152,6 @@ const char* dap_chain_net_get_type(dap_chain_t *l_chain);
 
 dap_list_t* dap_chain_net_get_link_node_list(dap_chain_net_t * l_net, bool a_is_only_cur_cell);
 dap_list_t* dap_chain_net_get_node_list(dap_chain_net_t * l_net);
-
-typedef enum dap_chain_net_tx_search_type {
-    /// Search local, in memory, possible load data from drive to memory
-    TX_SEARCH_TYPE_LOCAL,
-    /// Do the request to the network if its not full node, search inside shard
-    TX_SEARCH_TYPE_CELL,
-    /// Do the request for unspent txs in cell
-    TX_SEARCH_TYPE_CELL_UNSPENT,
-    /// Do the search in whole network and request tx from others cells if need
-    TX_SEARCH_TYPE_NET,
-    /// Do the search in whole network but search only unspent
-    TX_SEARCH_TYPE_NET_UNSPENT,
-    /// Do the request for spent txs in cell
-    TX_SEARCH_TYPE_CELL_SPENT,
-    /// Do the search in whole
-    TX_SEARCH_TYPE_NET_SPENT
-}dap_chain_net_tx_search_type_t;
-
-dap_chain_datum_tx_t * dap_chain_net_get_tx_by_hash(dap_chain_net_t * a_net, dap_chain_hash_fast_t * a_tx_hash,
-                                                     dap_chain_net_tx_search_type_t a_search_type);
-
-uint256_t dap_chain_net_get_tx_total_value(dap_chain_net_t * a_net, dap_chain_datum_tx_t * a_tx);
-
-dap_list_t * dap_chain_net_get_tx_cond_all_by_srv_uid(dap_chain_net_t * a_net, const dap_chain_net_srv_uid_t a_srv_uid,
-                                                      const dap_time_t a_time_from, const dap_time_t a_time_to,
-                                                     const dap_chain_net_tx_search_type_t a_search_type);
-
-typedef struct dap_chain_datum_tx_spends_item {
-    dap_chain_datum_tx_t* tx;
-    dap_hash_fast_t tx_hash;
-
-    dap_chain_tx_out_cond_t* out_cond;
-    dap_chain_tx_in_cond_t* in_cond;
-
-    dap_chain_datum_tx_t* tx_next;
-    UT_hash_handle hh;
-}dap_chain_datum_tx_spends_item_t;
-
-typedef struct dap_chain_datum_tx_spends_items {
-    dap_chain_datum_tx_spends_item_t* tx_outs;
-    dap_chain_datum_tx_spends_item_t* tx_ins;
-} dap_chain_datum_tx_spends_items_t;
-
-dap_chain_datum_tx_spends_items_t* dap_chain_net_get_tx_cond_all_with_spends_by_srv_uid(dap_chain_net_t* a_net, const dap_chain_net_srv_uid_t a_srv_uid,
-    const dap_time_t a_time_from, const dap_time_t a_time_to,
-    const dap_chain_net_tx_search_type_t a_search_type);
-void dap_chain_datum_tx_spends_item_free(dap_chain_datum_tx_spends_item_t* a_items);
-void dap_chain_datum_tx_spends_items_free(dap_chain_datum_tx_spends_items_t* a_items);
-
 dap_chain_node_role_t dap_chain_net_get_role(dap_chain_net_t * a_net);
 
 /**
@@ -197,34 +159,30 @@ dap_chain_node_role_t dap_chain_net_get_role(dap_chain_net_t * a_net);
  * @param l_chain
  * @return
  */
-DAP_STATIC_INLINE char * dap_chain_net_get_gdb_group_mempool_new(dap_chain_t * l_chain)
+DAP_STATIC_INLINE char *dap_chain_net_get_gdb_group_mempool_new(dap_chain_t *a_chain)
 {
-    dap_chain_net_t * l_net = l_chain ? dap_chain_net_by_id(l_chain->net_id) : NULL;
-    if ( l_net ) {
-        const char c_mempool_group_str[]="mempool";
-		return dap_strdup_printf("%s.chain-%s.%s",l_net->pub.gdb_groups_prefix,l_chain->name,c_mempool_group_str);
-    }
+    dap_chain_net_t *l_net = a_chain ? dap_chain_net_by_id(a_chain->net_id) : NULL;
+    if ( l_net )
+        return dap_strdup_printf("%s.chain-%s.mempool", l_net->pub.gdb_groups_prefix,a_chain->name);
     return NULL;
 }
 
-DAP_STATIC_INLINE char * dap_chain_net_get_gdb_group_from_chain_new(dap_chain_t * l_chain)
+DAP_STATIC_INLINE char *dap_chain_net_get_gdb_group_from_chain_new(dap_chain_t *a_chain)
 {
-    dap_chain_net_t * l_net = l_chain ? dap_chain_net_by_id(l_chain->net_id) : NULL;
+    dap_chain_net_t *l_net = a_chain ? dap_chain_net_by_id(a_chain->net_id) : NULL;
     if ( l_net )
-		return dap_strdup_printf( "chain-gdb.%s.chain-%016llX",l_net->pub.name, l_chain->id.uint64);
-
+        return dap_strdup_printf("chain-gdb.%s.chain-%016llX",l_net->pub.name, a_chain->id.uint64);
     return NULL;
 }
 
-dap_chain_t * dap_chain_net_get_chain_by_chain_type(dap_chain_net_t * l_net, dap_chain_type_t a_datum_type);
-dap_chain_t * dap_chain_net_get_default_chain_by_chain_type(dap_chain_net_t * l_net, dap_chain_type_t a_datum_type);
-char * dap_chain_net_get_gdb_group_mempool_by_chain_type(dap_chain_net_t * l_net, dap_chain_type_t a_datum_type);
+dap_chain_t *dap_chain_net_get_chain_by_chain_type(dap_chain_net_t *a_net, dap_chain_type_t a_datum_type);
+dap_chain_t *dap_chain_net_get_default_chain_by_chain_type(dap_chain_net_t *a_net, dap_chain_type_t a_datum_type);
+char *dap_chain_net_get_gdb_group_mempool_by_chain_type(dap_chain_net_t *a_net, dap_chain_type_t a_datum_type);
 dap_chain_net_t **dap_chain_net_list(uint16_t *a_size);
 bool dap_chain_net_get_extra_gdb_group(dap_chain_net_t *a_net, dap_chain_node_addr_t a_node_addr);
 
 int dap_chain_net_verify_datum_for_add(dap_chain_net_t *a_net, dap_chain_datum_t * a_datum );
-void dap_chain_net_dump_datum(dap_string_t *a_str_out, dap_chain_datum_t *a_datum, const char *a_hash_out_type);
-int dap_chain_net_add_downlink(dap_chain_net_t *a_net, dap_stream_worker_t *a_worker, dap_stream_ch_uuid_t a_ch_uuid);
+int dap_chain_net_add_downlink(dap_chain_net_t *a_net, dap_stream_worker_t *a_worker, dap_stream_ch_uuid_t a_ch_uuid, dap_events_socket_uuid_t a_esocket_uuid);
 void dap_chain_net_add_gdb_notify_callback(dap_chain_net_t *a_net, dap_global_db_obj_callback_notify_t a_callback, void *a_cb_arg);
 void dap_chain_net_sync_gdb_broadcast(void *a_arg, const char a_op_code, const char *a_group,
                                       const char *a_key, const void *a_value, const size_t a_value_len);
@@ -233,7 +191,6 @@ struct dap_chain_node_client * dap_chain_net_client_create_n_connect( dap_chain_
 struct dap_chain_node_client * dap_chain_net_client_create_n_connect_channels( dap_chain_net_t * a_net,struct dap_chain_node_info *a_link_info,
                                                                                const char * a_channels);
 
-typedef bool (datum_filter_func_t)(dap_chain_datum_t *a_datum, dap_chain_t * a_chain, void *a_filter_func_param);
 /**
  * @brief dap_chain_datum_list
  * Get datum list by filter
@@ -242,6 +199,6 @@ typedef bool (datum_filter_func_t)(dap_chain_datum_t *a_datum, dap_chain_t * a_c
  * @param a_filter_func
  * @param a_filter_func_param
  */
-dap_list_t* dap_chain_datum_list(dap_chain_net_t *a_net, dap_chain_t *a_chain, datum_filter_func_t *a_filter_func, void *a_filter_func_param);
+dap_list_t *dap_chain_datum_list(dap_chain_net_t *a_net, dap_chain_t *a_chain, dap_chain_datum_filter_func_t *a_filter_func, void *a_filter_func_param);
 
-int dap_chain_datum_add(dap_chain_t* a_chain, dap_chain_datum_t* a_datum, size_t a_datum_size);
+int dap_chain_datum_add(dap_chain_t * a_chain, dap_chain_datum_t *a_datum, size_t a_datum_size, dap_hash_fast_t *a_tx_hash);
diff --git a/modules/net/include/dap_chain_net_tx.h b/modules/net/include/dap_chain_net_tx.h
new file mode 100644
index 0000000000000000000000000000000000000000..2c59bf7165ba7f4289221b2891d9cf12d43cbfd9
--- /dev/null
+++ b/modules/net/include/dap_chain_net_tx.h
@@ -0,0 +1,90 @@
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * Cellframe Network https://cellframe.net
+ * Copyright  (c) 2022
+ * All rights reserved.
+
+ This file is part of DAP (Deus Applications Prototypes) the open source project
+
+    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    DAP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include "dap_chain_net.h"
+
+typedef enum dap_chain_net_tx_search_type {
+    /// Search local, in memory, possible load data from drive to memory
+    TX_SEARCH_TYPE_LOCAL,
+    /// Do the request to the network if its not full node, search inside shard
+    TX_SEARCH_TYPE_CELL,
+    /// Do the request for unspent txs in cell
+    TX_SEARCH_TYPE_CELL_UNSPENT,
+    /// Do the search in whole network and request tx from others cells if need
+    TX_SEARCH_TYPE_NET,
+    /// Do the search in whole network but search only unspent
+    TX_SEARCH_TYPE_NET_UNSPENT,
+    /// Do the request for spent txs in cell
+    TX_SEARCH_TYPE_CELL_SPENT,
+    /// Do the search in whole
+    TX_SEARCH_TYPE_NET_SPENT
+}dap_chain_net_tx_search_type_t;
+
+typedef struct dap_chain_datum_tx_spends_item{
+    dap_chain_datum_tx_t * tx;
+    dap_hash_fast_t tx_hash;
+
+    dap_chain_tx_out_cond_t *out_cond;
+    dap_chain_tx_in_cond_t *in_cond;
+
+    dap_chain_datum_tx_t * tx_next;
+    UT_hash_handle hh;
+}dap_chain_datum_tx_spends_item_t;
+
+typedef struct dap_chain_datum_tx_spends_items{
+    dap_chain_datum_tx_spends_item_t * tx_outs;
+    dap_chain_datum_tx_spends_item_t * tx_ins;
+} dap_chain_datum_tx_spends_items_t;
+typedef void (dap_chain_net_tx_hash_callback_t)(dap_chain_net_t* a_net, dap_chain_datum_tx_t *a_tx, void *a_arg);
+
+
+// TX functions
+dap_chain_datum_tx_t * dap_chain_net_get_tx_by_hash(dap_chain_net_t * a_net, dap_chain_hash_fast_t * a_tx_hash,
+                                                     dap_chain_net_tx_search_type_t a_search_type);
+
+dap_list_t * dap_chain_net_get_tx_cond_chain(dap_chain_net_t * a_net, dap_hash_fast_t * a_tx_hash, dap_chain_net_srv_uid_t a_srv_uid);
+
+uint256_t dap_chain_net_get_tx_total_value(dap_chain_net_t * a_net, dap_chain_datum_tx_t * a_tx );
+
+void dap_chain_net_get_tx_all(dap_chain_net_t * a_net, dap_chain_net_tx_search_type_t a_search_type ,dap_chain_net_tx_hash_callback_t a_tx_callback, void * a_arg);
+
+
+dap_list_t * dap_chain_net_get_tx_cond_all_by_srv_uid(dap_chain_net_t * a_net, const dap_chain_net_srv_uid_t a_srv_uid,
+                                                      const dap_time_t a_time_from, const dap_time_t a_time_to,
+                                                     const dap_chain_net_tx_search_type_t a_search_type);
+dap_list_t * dap_chain_net_get_tx_cond_all_for_addr(dap_chain_net_t * a_net, dap_chain_addr_t * a_addr, dap_chain_net_srv_uid_t a_srv_uid);
+
+dap_list_t * dap_chain_net_get_tx_all_from_tx(dap_chain_net_t * a_net, dap_hash_fast_t * l_tx_hash);
+
+
+
+
+dap_chain_datum_tx_spends_items_t * dap_chain_net_get_tx_cond_all_with_spends_by_srv_uid(dap_chain_net_t * a_net, const dap_chain_net_srv_uid_t a_srv_uid,
+                                                      const dap_time_t a_time_from, const dap_time_t a_time_to,
+                                                     const dap_chain_net_tx_search_type_t a_search_type);
+void dap_chain_datum_tx_spends_item_free(dap_chain_datum_tx_spends_item_t * a_items);
+void dap_chain_datum_tx_spends_items_free(dap_chain_datum_tx_spends_items_t * a_items);
+
+bool dap_chain_net_tx_get_fee(dap_chain_net_id_t a_net_id, uint256_t *a_value, dap_chain_addr_t *a_addr);
diff --git a/modules/net/include/dap_chain_node.h b/modules/net/include/dap_chain_node.h
index ea796943cd098277b8e1d2d9ba555d4baf9640b1..99327817e476d3f6506d0ee3a338388b9c1f8366 100644
--- a/modules/net/include/dap_chain_node.h
+++ b/modules/net/include/dap_chain_node.h
@@ -164,7 +164,9 @@ inline static char* dap_chain_node_addr_to_hash_str(dap_chain_node_addr_t *addre
     return a_key;
 }
 
-int dap_chain_node_mempool_process(dap_chain_t *a_chain, dap_chain_datum_t *a_datum);
+bool dap_chain_node_mempool_need_process(dap_chain_t *a_chain, dap_chain_datum_t *a_datum);
+bool dap_chain_node_mempool_process(dap_chain_t *a_chain, dap_chain_datum_t *a_datum);
+void dap_chain_node_mempool_process_all(dap_chain_t *a_chain);
 bool dap_chain_node_mempool_autoproc_init();
 void dap_chain_node_mempool_autoproc_deinit();
 
diff --git a/modules/net/include/dap_chain_node_cli_cmd.h b/modules/net/include/dap_chain_node_cli_cmd.h
index 36b75456e6410b1813eb64b89054924c75081896..bf07fa891ccdc2ff08650e7882ac0f30cc5c4cd8 100644
--- a/modules/net/include/dap_chain_node_cli_cmd.h
+++ b/modules/net/include/dap_chain_node_cli_cmd.h
@@ -141,6 +141,7 @@ int cmd_gdb_export(int argc, char ** argv, char ** a_str_reply);
 int com_mempool_delete(int argc, char ** argv, char ** a_str_reply);
 int com_mempool_list(int argc, char ** argv, char ** a_str_reply);
 int com_mempool_proc(int argc, char ** argv, char ** a_str_reply);
+int com_mempool_check(int argc, char ** argv, char ** a_str_reply);
 /**
  * Place public CA into the mempool
  */
@@ -148,3 +149,5 @@ int com_mempool_add_ca( int a_argc,  char ** a_argv, char ** a_str_reply);
 int com_chain_ca_pub( int a_argc,  char ** a_argv, char ** a_str_reply);
 int com_chain_ca_copy( int a_argc,  char ** a_argv, char ** a_str_reply);
 int com_signer(int a_argc, char **a_argv, char **a_str_reply);
+//remove func
+int cmd_remove(int argc, char ** argv, char ** a_str_reply);
diff --git a/modules/net/include/dap_chain_node_client.h b/modules/net/include/dap_chain_node_client.h
index 14a0cbb542e9a22cb80339bc559be024060b0c1e..6dc818ca336d84bc805b9416e3fe125c3e282835 100644
--- a/modules/net/include/dap_chain_node_client.h
+++ b/modules/net/include/dap_chain_node_client.h
@@ -145,7 +145,6 @@ int dap_chain_node_client_init(void);
 
 void dap_chain_node_client_deinit(void);
 
-
 dap_chain_node_client_t* dap_chain_node_client_create_n_connect(dap_chain_net_t * a_net, dap_chain_node_info_t *a_node_info,
                                                                 const char *a_active_channels,dap_chain_node_client_callbacks_t *a_callbacks,
                                                                 void * a_callback_arg );
@@ -159,15 +158,16 @@ dap_chain_node_client_t* dap_chain_node_client_connect_channels(dap_chain_net_t
  */
 dap_chain_node_client_t* dap_chain_node_client_connect(dap_chain_net_t * a_net, dap_chain_node_info_t *node_info);
 
+dap_chain_node_client_t *dap_chain_node_client_find(dap_events_socket_uuid_t a_uuid);
 
 /**
  * Reset client state to connected state if it is connected
  */
 void dap_chain_node_client_reset(dap_chain_node_client_t *a_client);
 /**
- * Close connection to server, delete chain_node_client_t *client
+ * Close connection to server, delete chain_node_client_t with specified UUID
  */
-void dap_chain_node_client_close(dap_chain_node_client_t *client);
+void dap_chain_node_client_close(dap_events_socket_uuid_t a_uuid);
 
 /**
  * Send stream request to server
diff --git a/modules/net/include/dap_chain_node_remote.h b/modules/net/include/dap_chain_node_remote.h
deleted file mode 100644
index ce8aedc93262ac6e2a2bf67cb27529d78726d50c..0000000000000000000000000000000000000000
--- a/modules/net/include/dap_chain_node_remote.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Authors:
- * Dmitriy A. Gearasimov <naeper@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
-
- This file is part of DAP (Deus Applications Prototypes) the open source project
-
- DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- DAP is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-#include <stdbool.h>
-
-#include "dap_chain_node.h"
-#include "dap_chain_node_client.h"
-
-/**
- * Add new established connection to the list
- *
- * return 0 OK, -1 error, -2 already present
- */
-int dap_chain_node_client_list_add(dap_chain_node_addr_t *address, dap_chain_node_client_t *client);
-
-/**
- * Delete established connection from the list
- *
- * return 0 OK, -1 error, -2 address not found
- */
-int chain_node_client_list_del(dap_chain_node_addr_t *address);
-
-/**
- * Delete all established connection from the list
- */
-void chain_node_client_list_del_all(void);
-
-/**
- * Get present established connection by address
- *
- * return client, or NULL if the connection not found in the list
- */
-const dap_chain_node_client_t* chain_node_client_find(dap_chain_node_addr_t *address);
diff --git a/modules/net/srv/CMakeLists.txt b/modules/net/srv/CMakeLists.txt
index aaa29abbe4d1fd6080ef7ac917095b819e1f9c9c..87b8572e9f7b3cb16bcfe73fe0e870f6bdd2e7d6 100644
--- a/modules/net/srv/CMakeLists.txt
+++ b/modules/net/srv/CMakeLists.txt
@@ -1,19 +1,18 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.13)
 project (dap_chain_net_srv)
 
-file(GLOB DAP_CHAIN_NET_SRV_SRCS *.c libmaxminddb/*.c)
-
-file(GLOB DAP_CHAIN_NET_SRV_HEADERS include/*.h libmaxminddb/*.h)
-
+file(GLOB DAP_CHAIN_NET_SRV_SRCS *.c)
+file(GLOB DAP_CHAIN_NET_SRV_HEADERS *.h)
 add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_NET_SRV_SRCS} ${DAP_CHAIN_NET_SRV_HEADERS})
 
-set(NET_SRV_LIBS dap_chain_net_srv dap_core dap_crypto dap_chain dap_chain_net dap_chain_wallet)
+add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/libmaxminddb ${CMAKE_CURRENT_BINARY_DIR}/../../../3rdparty/libmaxminddb)
 
+set(NET_SRV_LIBS maxminddb dap_core dap_crypto dap_chain dap_chain_net dap_chain_wallet)
 if (CELLFRAME_MODULES MATCHES "modules-dynamic")
     set(NET_SRV_LIBS ${NET_SRV_LIBS} dap_modules_dynamic_cdb)
 endif()
+target_link_libraries(${PROJECT_NAME} ${NET_SRV_LIBS})
 
-target_link_libraries(${NET_SRV_LIBS})
 target_include_directories(${PROJECT_NAME} INTERFACE .)
 target_include_directories(${PROJECT_NAME} PUBLIC include)
 target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/uthash/src)
diff --git a/modules/net/srv/dap_chain_net_srv.c b/modules/net/srv/dap_chain_net_srv.c
index 321120b7cf724a979f329d660cf4a7d9281693db..b1d852de4630718ea17d88301707ef6e14c101f9 100644
--- a/modules/net/srv/dap_chain_net_srv.c
+++ b/modules/net/srv/dap_chain_net_srv.c
@@ -29,34 +29,25 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#ifdef WIN32
-#include <winsock2.h>
-#include <windows.h>
-#include <mswsock.h>
-#include <ws2tcpip.h>
-#include <io.h>
-#endif
-
 #ifdef DAP_OS_LINUX
 #include <dlfcn.h>
 #endif
 #include <json-c/json.h>
 #include <json-c/json_object.h>
-
 #include <pthread.h>
 #include <dirent.h>
-
 #include "uthash.h"
 #include "utlist.h"
+
+#include "dap_chain_net.h"
+#include "dap_hash.h"
 #include "dap_common.h"
 #include "dap_enc_base58.h"
 #include "dap_list.h"
 #include "dap_string.h"
 #include "dap_file_utils.h"
-
 #include "dap_chain.h"
 #include "dap_chain_common.h"
-#include "dap_chain_net.h"
 #include "dap_chain_net_srv.h"
 #include "dap_chain_net_srv_order.h"
 #include "dap_chain_net_srv_stream_session.h"
@@ -88,12 +79,19 @@ static int s_cli_net_srv(int argc, char **argv, char **a_str_reply);
 static void s_load(const char * a_path);
 static void s_load_all(void);
 
+static bool s_pay_verificator_callback(dap_ledger_t * a_ledger,dap_hash_fast_t *a_tx_out_hash, dap_chain_tx_out_cond_t *a_cond,
+                                       dap_chain_datum_tx_t *a_tx_in, bool a_owner);
+static bool s_fee_verificator_callback(dap_ledger_t * a_ledger, dap_hash_fast_t *a_tx_out_hash,dap_chain_tx_out_cond_t *a_cond,
+                                       dap_chain_datum_tx_t *a_tx_in, bool a_owner);
+
 /**
  * @brief dap_chain_net_srv_init
  * @return
  */
 int dap_chain_net_srv_init()
-{    
+{
+    dap_chain_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY, s_pay_verificator_callback, NULL);
+    dap_chain_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE, s_fee_verificator_callback, NULL);
     dap_stream_ch_chain_net_srv_init();
     m_uid = NULL;
     m_uid_count = 0;
@@ -597,13 +595,39 @@ static int s_cli_net_srv( int argc, char **argv, char **a_str_reply)
     return ret;
 }
 
-bool dap_chain_net_srv_pay_verificator(dap_ledger_t* a_ledger, dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner)
+/**
+ * @brief s_fee_verificator_callback
+ * @param a_ledger
+ * @param a_tx_out_hash
+ * @param a_cond
+ * @param a_tx_in
+ * @param a_owner
+ * @return
+ */
+static bool s_fee_verificator_callback(dap_ledger_t * a_ledger, dap_hash_fast_t *a_tx_out_hash,dap_chain_tx_out_cond_t *a_cond,
+                                       dap_chain_datum_tx_t *a_tx_in, bool a_owner)
+{
+    return false;
+}
+
+/**
+ * @brief s_pay_verificator_callback
+ * @param a_ledger
+ * @param a_tx_out
+ * @param a_cond
+ * @param a_tx_in
+ * @param a_owner
+ * @return
+ */
+static bool s_pay_verificator_callback(dap_ledger_t * a_ledger,dap_hash_fast_t *a_tx_out_hash, dap_chain_tx_out_cond_t *a_cond,
+                                       dap_chain_datum_tx_t *a_tx_in, bool a_owner)
 {
     UNUSED(a_ledger);
+    UNUSED(a_tx_out_hash);
     if (!a_owner)
         return false;
     dap_chain_datum_tx_receipt_t *l_receipt = (dap_chain_datum_tx_receipt_t *)
-                                               dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_RECEIPT, NULL);
+                                               dap_chain_datum_tx_item_get(a_tx_in, NULL, TX_ITEM_TYPE_RECEIPT, NULL);
     if (!l_receipt)
         return false;
     dap_sign_t *l_sign = dap_chain_datum_tx_receipt_sign_get(l_receipt, l_receipt->size, 1);
diff --git a/modules/net/srv/dap_chain_net_srv_geoip.c b/modules/net/srv/dap_chain_net_srv_geoip.c
index 90ec027e29d2ec278dd004426f9937a76edd2bbc..ab1f044b7276dce7e8501a6499fecb15137fe7b5 100644
--- a/modules/net/srv/dap_chain_net_srv_geoip.c
+++ b/modules/net/srv/dap_chain_net_srv_geoip.c
@@ -32,7 +32,7 @@
 #include "dap_enc_key.h"
 #include "dap_enc_base64.h"
 #include "dap_chain_net_srv_geoip.h"
-#include "libmaxminddb/maxminddb.h"
+#include "maxminddb.h"
 
 #define LOG_TAG "chain_net_srv_geoip"
 #define LOCALE_DEFAULT  "en"
diff --git a/modules/net/srv/dap_chain_net_srv_order.c b/modules/net/srv/dap_chain_net_srv_order.c
index 8619797b6a0175093e82d93ad1029c3c6c651942..23bec9c32f4b37b6f0fc23c22726dde8ea9ded58 100644
--- a/modules/net/srv/dap_chain_net_srv_order.c
+++ b/modules/net/srv/dap_chain_net_srv_order.c
@@ -589,10 +589,8 @@ void dap_chain_net_srv_order_dump_to_string(dap_chain_net_srv_order_t *a_order,d
 static void s_srv_order_callback_notify(void *a_arg, const char a_op_code, const char *a_group,
                                    const char *a_key, const void *a_value, const size_t a_value_len)
 {
-    UNUSED(a_value_len);
-    if (!a_arg || !a_key) {
+    if (!a_arg || !a_key)
         return;
-    }
     dap_chain_net_t *l_net = (dap_chain_net_t *)a_arg;
     dap_global_db_context_t * l_gdb_context = dap_global_db_context_current();
     assert(l_net);
@@ -616,9 +614,10 @@ static void s_srv_order_callback_notify(void *a_arg, const char a_op_code, const
                 dap_global_db_del_unsafe(l_gdb_context, a_group, a_key);
             } else {
                 dap_sign_t *l_sign = (dap_sign_t *)(l_order->ext_n_sign + l_order->ext_size);
-                if (!dap_sign_verify_size(l_sign, a_value_len) ||
-                        dap_sign_verify(l_sign, l_order,
-                                        sizeof(dap_chain_net_srv_order_t) + l_order->ext_size) != 1) {
+                size_t l_max_size = a_value_len - sizeof(dap_chain_net_srv_order_t) - l_order->ext_size;
+                int l_verify = dap_sign_verify_all(l_sign, l_max_size, l_order, sizeof(dap_chain_net_srv_order_t) + l_order->ext_size);
+                if (l_verify) {
+                    log_it(L_ERROR, "Order unverified, err %d", l_verify);
                     dap_global_db_del_unsafe(l_gdb_context, a_group, a_key);
                 }
                 /*dap_chain_hash_fast_t l_pkey_hash;
diff --git a/modules/net/srv/include/dap_chain_net_srv.h b/modules/net/srv/include/dap_chain_net_srv.h
index b747dc4e6a696969aa2e602faaae9d4b544d03ae..c621b8df2b0f19f6a9297406353dc4ea0c06ebc3 100755
--- a/modules/net/srv/include/dap_chain_net_srv.h
+++ b/modules/net/srv/include/dap_chain_net_srv.h
@@ -257,9 +257,32 @@ typedef struct dap_chain_net_srv
     void *_internal;
 } dap_chain_net_srv_t;
 
+// Fees section
+typedef enum dap_chain_net_srv_fee_tsd_type {
+    TSD_FEE = 0x0001,
+    TSD_FEE_TYPE,
+    TSD_FEE_ADDR
+} dap_chain_net_srv_fee_tsd_type_t;
+
+typedef enum dap_chain_net_srv_fee_type {
+    SERVICE_FEE_OWN_FIXED = 0x1,
+    SERVICE_FEE_OWN_PERCENT,
+    SERVICE_FEE_NATIVE_FIXED,
+    SERIVCE_FEE_NATIVE_PERCENT
+} dap_chain_net_srv_fee_type_t;
+
+typedef struct dap_chain_net_srv_fee_item {
+    dap_chain_net_id_t net_id;
+    // Sevice fee
+    uint16_t fee_type;
+    uint256_t fee;
+    dap_chain_addr_t fee_addr; // Addr collector
+
+    UT_hash_handle hh;
+} dap_chain_net_srv_fee_item_t;
+
 int dap_chain_net_srv_init();
 void dap_chain_net_srv_deinit(void);
-bool dap_chain_net_srv_pay_verificator(dap_ledger_t* a_ledger, dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner);
 dap_chain_net_srv_t* dap_chain_net_srv_add(dap_chain_net_srv_uid_t a_uid,
                                            const char *a_config_section,
                                            dap_chain_net_srv_callbacks_t* a_callbacks);
diff --git a/modules/service/stake_lock/dap_chain_net_srv_stake_lock.c b/modules/service/stake_lock/dap_chain_net_srv_stake_lock.c
index 9e5d0bb98834c138babab5e01c166255eb9403d3..1a16a57dd5be146346330a3b25634fa9235a4868 100644
--- a/modules/service/stake_lock/dap_chain_net_srv_stake_lock.c
+++ b/modules/service/stake_lock/dap_chain_net_srv_stake_lock.c
@@ -28,6 +28,7 @@
 #include "dap_chain_node_cli.h"
 #include "dap_chain_mempool.h"
 #include "dap_chain_wallet.h"
+#include "dap_chain_ledger.h"
 #include "dap_common.h"
 #include "dap_hash.h"
 #include "dap_time.h"
@@ -35,60 +36,48 @@
 static bool s_debug_more = false;
 
 enum error_code {
-    STAKE_NO_ERROR              = 0,
-    NET_ARG_ERROR               = 1,
-    NET_ERROR                   = 2,
-    TOKEN_ARG_ERROR             = 3,
-    TOKEN_ERROR                 = 4,
-    COINS_ARG_ERROR             = 5,
-    COINS_FORMAT_ERROR          = 6,
-    ADDR_ARG_ERROR              = 7,
-    ADDR_FORMAT_ERROR           = 8,
-    CERT_ARG_ERROR              = 9,
-    CERT_LOAD_ERROR             = 10,
-    CHAIN_ERROR                 = 11,
-    CHAIN_EMISSION_ERROR        = 12,
-    TIME_ERROR                  = 13,
-    NO_MONEY_ERROR              = 14,
-    WALLET_ARG_ERROR            = 15,
-    WALLET_OPEN_ERROR           = 16,
-    CERT_KEY_ERROR              = 17,
-    WALLET_ADDR_ERROR           = 18,
-    STAKE_ERROR                 = 19,
-    TX_ARG_ERROR                = 20,
-    HASH_IS_BLANK_ERROR         = 21,
-    NO_TX_ERROR                 = 22,
-    CREATE_LOCK_TX_ERROR        = 23,
-    TX_TICKER_ERROR             = 24,
-    NO_DELEGATE_TOKEN_ERROR     = 25,
-    NO_VALID_SUBTYPE_ERROR      = 26,
-    IS_USED_OUT_ERROR           = 27,
-    OWNER_KEY_ERROR             = 28,
-    CREATE_TX_ERROR             = 29,
-    CREATE_BURNING_TX_ERROR     = 31,
-    CREATE_RECEIPT_ERROR        = 32,
-    SIGN_ERROR                  = 33,
-    CREATE_DATUM_ERROR          = 34,
-    ADD_DATUM_BURNING_TX_ERROR  = 35,
-    ADD_DATUM_TX_TAKE_ERROR     = 36,
-    BASE_TX_CREATE_ERROR        = 37,
-    WRONG_PARAM_SIZE            = 38,
-    NOT_ENOUGH_TIME             = 39,
-    REINVEST_ARG_ERROR          = 40
+    STAKE_NO_ERROR 				= 0,
+    NET_ARG_ERROR				= 1,
+    NET_ERROR					= 2,
+    TOKEN_ARG_ERROR 			= 3,
+    TOKEN_ERROR					= 4,
+    COINS_ARG_ERROR				= 5,
+    COINS_FORMAT_ERROR			= 6,
+    ADDR_ARG_ERROR				= 7,
+    ADDR_FORMAT_ERROR			= 8,
+    CERT_ARG_ERROR				= 9,
+    CERT_LOAD_ERROR				= 10,
+    CHAIN_ERROR					= 11,
+    CHAIN_EMISSION_ERROR		= 12,
+    TIME_ERROR					= 13,
+    NO_MONEY_ERROR				= 14,
+    WALLET_ARG_ERROR			= 15,
+    WALLET_OPEN_ERROR			= 16,
+    CERT_KEY_ERROR				= 17,
+    WALLET_ADDR_ERROR			= 18,
+    STAKE_ERROR  				= 19,
+    TX_ARG_ERROR				= 20,
+    HASH_IS_BLANK_ERROR			= 21,
+    NO_TX_ERROR					= 22,
+    CREATE_LOCK_TX_ERROR		= 23,
+    TX_TICKER_ERROR				= 24,
+    NO_DELEGATE_TOKEN_ERROR		= 25,
+    NO_VALID_SUBTYPE_ERROR		= 26,
+    IS_USED_OUT_ERROR			= 27,
+    OWNER_KEY_ERROR				= 28,
+    CREATE_TX_ERROR				= 29,
+    CREATE_BURNING_TX_ERROR		= 31,
+    CREATE_RECEIPT_ERROR		= 32,
+    SIGN_ERROR					= 33,
+    CREATE_DATUM_ERROR			= 34,
+    ADD_DATUM_BURNING_TX_ERROR	= 35,
+    ADD_DATUM_TX_TAKE_ERROR		= 36,
+    BASE_TX_CREATE_ERROR		= 37,
+    WRONG_PARAM_SIZE			= 38,
+    NOT_ENOUGH_TIME				= 39,
+    REINVEST_ARG_ERROR			= 40
 };
 
-/**
- * @brief The cond_params struct thats placed in tx_cond->params[] section
- */
-typedef struct cond_params {
-    dap_time_t		time_unlock;
-    uint32_t		flags;
-    uint8_t			reinvest;
-    uint8_t			padding[7];
-    dap_hash_fast_t	token_delegated; // Delegate token
-    dap_hash_fast_t	pkey_delegated; // Delegate public key
-} DAP_ALIGN_PACKED	cond_params_t;
-
 typedef struct dap_chain_ledger_token_emission_for_stake_lock_item {
     dap_chain_hash_fast_t	datum_token_emission_for_stake_lock_hash;
     dap_chain_hash_fast_t	tx_used_out;
@@ -100,31 +89,47 @@ typedef struct dap_chain_ledger_token_emission_for_stake_lock_item {
 #define MONTH_INDEX	8
 #define YEAR_INDEX	12
 
-static int s_cli_stake_lock(int a_argc, char** a_argv, char** a_str_reply);
-// Verificator callbacks
-static void s_callback_decree(dap_chain_net_srv_t* a_srv, dap_chain_net_t* a_net, dap_chain_t* a_chain, dap_chain_datum_decree_t* a_decree, size_t a_decree_size);
-dap_chain_ledger_token_emission_for_stake_lock_item_t *s_emission_for_stake_lock_item_add(dap_ledger_t *a_ledger, const dap_chain_hash_fast_t *a_token_emission_hash);
-
+static int												s_cli_stake_lock(int a_argc, char **a_argv, char **a_str_reply);
+static dap_chain_hash_fast_t							*dap_chain_mempool_base_tx_for_stake_lock_create(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_emission_hash,
+                                                                              dap_chain_id_t a_emission_chain_id, uint256_t a_emission_value, const char *a_ticker,
+                                                                              dap_chain_addr_t *a_addr_to, dap_enc_key_t *a_key_from);
+// Callbacks
+static void												s_callback_decree (dap_chain_net_srv_t * a_srv, dap_chain_net_t *a_net, dap_chain_t * a_chain,
+                                                                              dap_chain_datum_decree_t * a_decree, size_t a_decree_size);
+static bool s_stake_lock_callback_verificator_added(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_tx_out_cond_t *a_tx_item);
+static bool s_stake_lock_callback_verificator(dap_ledger_t *a_ledger, dap_hash_fast_t *a_tx_out_hash, dap_chain_tx_out_cond_t *a_cond,
+                                   dap_chain_datum_tx_t *a_tx_in, bool a_owner);
 /**
  * @brief dap_chain_net_srv_external_stake_init
  * @return
  */
 int dap_chain_net_srv_stake_lock_init()
 {
+    dap_chain_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK, s_stake_lock_callback_verificator, s_stake_lock_callback_verificator_added);
     dap_cli_server_cmd_add("stake_lock", s_cli_stake_lock, "Stake lock service commands",
-        "stake_lock hold -net <net_name> -wallet <wallet_name> -time_staking <in YYMMDD>\n"
-        "\t-token <token_ticker> -coins <value> -reinvest <percentage from 1 to 100 (not necessary)>\n"
-        "\t-cert <priv_cert_name> -chain <chain (not necessary)> -chain_emission <chain (not necessary)>\n"
-        "stake_lock take -net <net_name> -tx <transaction_hash> -wallet <wallet_name>\n"
-        "\t-chain <chain (not necessary)>\n"
+       "Command:"
+                "stake_lock hold\n"
+                "Required parameters:\n"
+                "-net <net name> -wallet <wallet name> -time_staking <in YYMMDD>\n"
+                "-token <ticker> -coins <value>\n"
+                "Optional parameters:\n"
+                "-cert <name> -chain <chain> -reinvest <percentage from 1 to 100>\n"
+                "-no_base_tx(flag to create a transaction without base transaction)\n"
+                "Command:"
+                "stake_lock take\n"
+                "Required parameters:\n"
+                "-net <net name> -wallet <wallet name> -tx <transaction hash>\n"
+                "Optional parameters:\n"
+                "-chain <chain>\n"
     );
+
     s_debug_more = dap_config_get_item_bool_default(g_config,"ledger","debug_more",false);
 
     dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID };
     dap_chain_net_srv_callbacks_t l_srv_callbacks = {};
     l_srv_callbacks.decree = s_callback_decree;
 
-    dap_chain_net_srv_t* l_srv = dap_chain_net_srv_add(l_uid, "stake_lock", &l_srv_callbacks);
+    dap_chain_net_srv_t *l_srv = dap_chain_net_srv_add(l_uid, "stake_lock", &l_srv_callbacks);
     return 0;
 }
 
@@ -144,7 +149,7 @@ void dap_chain_net_srv_stake_lock_deinit()
  * @param a_decree
  * @param a_decree_size
  */
-static void s_callback_decree(dap_chain_net_srv_t* a_srv, dap_chain_net_t* a_net, dap_chain_t* a_chain, dap_chain_datum_decree_t* a_decree, size_t a_decree_size)
+static void s_callback_decree (dap_chain_net_srv_t * a_srv, dap_chain_net_t *a_net, dap_chain_t * a_chain, dap_chain_datum_decree_t * a_decree, size_t a_decree_size)
 {
 
 }
@@ -156,18 +161,18 @@ static void s_callback_decree(dap_chain_net_srv_t* a_srv, dap_chain_net_t* a_net
  * @param datoshi_burned
  * @return
  */
-static dap_chain_datum_tx_receipt_t* s_receipt_create(dap_hash_fast_t* hash_burning_transaction, const char* token, uint256_t datoshi_burned)
+static dap_chain_datum_tx_receipt_t *s_receipt_create(dap_hash_fast_t *hash_burning_transaction, const char *token, uint256_t datoshi_burned)
 {
-    uint32_t l_ext_size = sizeof(dap_hash_fast_t) + dap_strlen(token) + 1;
-    uint8_t* l_ext = DAP_NEW_STACK_SIZE(uint8_t, l_ext_size);
+    uint32_t l_ext_size	= sizeof(dap_hash_fast_t) + dap_strlen(token) + 1;
+    uint8_t *l_ext		= DAP_NEW_STACK_SIZE(uint8_t, l_ext_size);
 
     memcpy(l_ext, hash_burning_transaction, sizeof(dap_hash_fast_t));
-    strcpy((char*)&l_ext[sizeof(dap_hash_fast_t)], token);
+    strcpy((char *)&l_ext[sizeof(dap_hash_fast_t)], token);
 
-    dap_chain_net_srv_price_unit_uid_t l_unit = { .uint32 = SERV_UNIT_UNDEFINED };
-    dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID };
-    dap_chain_datum_tx_receipt_t* l_receipt = dap_chain_datum_tx_receipt_create(l_uid, l_unit, 0, datoshi_burned,
-        l_ext, l_ext_size);
+    dap_chain_net_srv_price_unit_uid_t l_unit	= { .uint32 = SERV_UNIT_UNDEFINED};
+    dap_chain_net_srv_uid_t l_uid				= { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID };
+    dap_chain_datum_tx_receipt_t *l_receipt		= dap_chain_datum_tx_receipt_create(l_uid, l_unit, 0, datoshi_burned,
+                                                                                 l_ext, l_ext_size);
     return l_receipt;
 }
 
@@ -179,29 +184,30 @@ static dap_chain_datum_tx_receipt_t* s_receipt_create(dap_hash_fast_t* hash_burn
  * @param output_line
  * @return
  */
-static enum error_code s_cli_hold(int a_argc, char** a_argv, int a_arg_index, dap_string_t* output_line)
+static enum error_code s_cli_hold(int a_argc, char **a_argv, int a_arg_index, dap_string_t *output_line)
 {
-    const char *l_net_str, *l_ticker_str, *l_coins_str, *l_wallet_str, *l_cert_str, *l_chain_str, *l_chain_emission_str, *l_time_staking_str, *l_reinvest_percent_str;
-    l_net_str = l_ticker_str = l_coins_str = l_wallet_str = l_cert_str = l_chain_str = l_chain_emission_str = l_time_staking_str = l_reinvest_percent_str = NULL;
+    const char *l_net_str, *l_ticker_str, *l_coins_str, *l_wallet_str, *l_cert_str, *l_chain_str, /* *l_chain_emission_str,*/ *l_time_staking_str, *l_reinvest_percent_str;
+    l_net_str = l_ticker_str = l_coins_str = l_wallet_str = l_cert_str = l_chain_str = /*l_chain_emission_str =*/ l_time_staking_str = l_reinvest_percent_str = NULL;
     const char *l_wallets_path								=	dap_chain_wallet_get_path(g_config);
     char 	delegate_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] 	=	{[0] = 'm'};
     dap_chain_net_t						*l_net				=	NULL;
     dap_chain_t							*l_chain			=	NULL;
-    dap_chain_t							*l_chain_emission	=	NULL;
+//	dap_chain_t							*l_chain_emission	=	NULL;
+    dap_cert_t							*l_cert				=	NULL;
+    dap_pkey_t							*l_key_cond			=	NULL;
+    dap_hash_fast_t 					*l_base_tx_hash		=	NULL;
     dap_chain_net_srv_uid_t				l_uid				=	{ .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID };
     dap_time_t              			l_time_staking		=	0;
-    uint8_t								l_reinvest_percent	=	0;
+    uint256_t						    l_reinvest_percent	=	{};
     uint256_t							l_value_delegated	=	{};
+    bool								create_base_tx		=	true;
     uint256_t 							l_value;
     dap_ledger_t						*l_ledger;
     char								*l_hash_str;
     dap_hash_fast_t						*l_tx_cond_hash;
-    dap_hash_fast_t 					*l_base_tx_hash;
     dap_enc_key_t						*l_key_from;
-    dap_pkey_t							*l_key_cond;
     dap_chain_wallet_t					*l_wallet;
     dap_chain_addr_t					*l_addr_holder;
-    dap_cert_t							*l_cert;
     dap_chain_datum_token_t 			*delegate_token;
     dap_tsd_t							*l_tsd;
     dap_chain_datum_token_tsd_delegate_from_stake_lock_t l_tsd_section;
@@ -209,7 +215,7 @@ static enum error_code s_cli_hold(int a_argc, char** a_argv, int a_arg_index, da
     dap_string_append_printf(output_line, "---> HOLD <---\n");
 
     if (!dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-net", &l_net_str)
-        || NULL == l_net_str)
+    ||	NULL == l_net_str)
         return NET_ARG_ERROR;
 
     if (NULL == (l_net = dap_chain_net_by_name(l_net_str))) {
@@ -218,95 +224,109 @@ static enum error_code s_cli_hold(int a_argc, char** a_argv, int a_arg_index, da
     }
 
     if (!dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-token", &l_ticker_str)
-        || NULL == l_ticker_str
-        || dap_strlen(l_ticker_str) > 8) // for 'm' delegated
+    || NULL == l_ticker_str
+    || dap_strlen(l_ticker_str) > 8) // for 'm' delegated
         return TOKEN_ARG_ERROR;
 
     l_ledger = l_net->pub.ledger;
+
     if (NULL == dap_chain_ledger_token_ticker_check(l_ledger, l_ticker_str)) {
         dap_string_append_printf(output_line, "'%s'", l_ticker_str);
         return TOKEN_ERROR;
     }
 
-    strcpy(delegate_ticker_str + 1, l_ticker_str);
+    if (dap_cli_server_cmd_check_option(a_argv, a_arg_index, a_argc, "-no_base_tx") >= 0)
+        create_base_tx = false;
 
-    if (NULL == (delegate_token = dap_chain_ledger_token_ticker_check(l_ledger, delegate_ticker_str))
-    ||	delegate_token->type != DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL
-    ||	!delegate_token->header_native_decl.tsd_total_size
-    ||	NULL == (l_tsd = dap_tsd_find(delegate_token->data_n_tsd, delegate_token->header_native_decl.tsd_total_size, DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DELEGATE_EMISSION_FROM_STAKE_LOCK))) {
-        dap_string_append_printf(output_line, "'%s'", delegate_ticker_str);
-        return NO_DELEGATE_TOKEN_ERROR;
-    }
+    if (create_base_tx) {
+        strcpy(delegate_ticker_str + 1, l_ticker_str);
 
-    l_tsd_section = dap_tsd_get_scalar(l_tsd, dap_chain_datum_token_tsd_delegate_from_stake_lock_t);
-    if (strcmp(l_ticker_str, l_tsd_section.ticker_token_from))
-        return TOKEN_ERROR;
+        if (NULL == (delegate_token = dap_chain_ledger_token_ticker_check(l_ledger, delegate_ticker_str))
+        ||	(delegate_token->type != DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL && delegate_token->type != DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_UPDATE)
+        ||	!delegate_token->header_native_decl.tsd_total_size
+        ||	NULL == (l_tsd = dap_tsd_find(delegate_token->data_n_tsd, delegate_token->header_native_decl.tsd_total_size, DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DELEGATE_EMISSION_FROM_STAKE_LOCK))) {
+            dap_string_append_printf(output_line, "'%s'", delegate_ticker_str);
+            return NO_DELEGATE_TOKEN_ERROR;
+        }
+
+        l_tsd_section = dap_tsd_get_scalar(l_tsd, dap_chain_datum_token_tsd_delegate_from_stake_lock_t);
+        if (strcmp(l_ticker_str, l_tsd_section.ticker_token_from))
+            return TOKEN_ERROR;
+    }
 
     if (!dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-coins", &l_coins_str)
-        || NULL == l_coins_str)
+    ||	NULL == l_coins_str)
         return COINS_ARG_ERROR;
 
-    if (IS_ZERO_256((l_value = dap_chain_balance_scan(l_coins_str))))
+    if (IS_ZERO_256( (l_value = dap_chain_balance_scan(l_coins_str)) ))
         return COINS_FORMAT_ERROR;
 
-    if (!IS_ZERO_256(l_tsd_section.emission_rate)) {
+    if (create_base_tx
+    &&	!IS_ZERO_256(l_tsd_section.emission_rate)) {
         MULT_256_COIN(l_value, l_tsd_section.emission_rate, &l_value_delegated);
         if (IS_ZERO_256(l_value_delegated))
             return COINS_FORMAT_ERROR;
-    } else {
+    } else
         l_value_delegated = l_value;
-    }
 
-    if (!dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-cert", &l_cert_str)
-        || NULL == l_cert_str)
-        return CERT_ARG_ERROR;
+    dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-cert", &l_cert_str);
 
-    if (NULL == (l_cert = dap_cert_find_by_name(l_cert_str))) {
+    if (NULL != l_cert_str
+    &&	NULL == (l_cert = dap_cert_find_by_name(l_cert_str))) {
         dap_string_append_printf(output_line, "'%s'", l_cert_str);
         return CERT_LOAD_ERROR;
     }
 
     if (dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-chain", &l_chain_str)
-        && l_chain_str)
+    &&	l_chain_str)
         l_chain = dap_chain_net_get_chain_by_name(l_net, l_chain_str);
     else
         l_chain = dap_chain_net_get_default_chain_by_chain_type(l_net, CHAIN_TYPE_TX);
-    if (!l_chain)
+    if(!l_chain)
         return CHAIN_ERROR;
 
-    if (dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-chain_emission", &l_chain_emission_str)
-        && l_chain_emission_str)
+/*	if (dap_chain_node_cli_find_option_val(a_argv, a_arg_index, a_argc, "-chain_emission", &l_chain_emission_str)
+    &&	l_chain_emission_str)
         l_chain_emission = dap_chain_net_get_chain_by_name(l_net, l_chain_str);
     else
         l_chain_emission = dap_chain_net_get_default_chain_by_chain_type(l_net, CHAIN_TYPE_EMISSION);
-    if (!l_chain_emission)
-        return CHAIN_EMISSION_ERROR;
+    if(!l_chain_emission)
+        return CHAIN_EMISSION_ERROR;*/
 
     if (!dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-wallet", &l_wallet_str)
-        || NULL == l_wallet_str)
+    ||	NULL == l_wallet_str)
         return WALLET_ARG_ERROR;
 
     // Read time staking
     if (!dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-time_staking", &l_time_staking_str)
-        || NULL == l_time_staking_str)
+    ||	NULL == l_time_staking_str)
         return TIME_ERROR;
 
-    if (0 == (l_time_staking = dap_time_from_str_simplified(l_time_staking_str))
-        || (time_t)(l_time_staking - dap_time_now()) <= 0)
+    l_time_staking = dap_time_from_str_simplified(l_time_staking_str);
+    if (0 == l_time_staking)
         return TIME_ERROR;
+    dap_time_t l_time_now = dap_time_now();
+    if (l_time_staking < l_time_now)
+        return TIME_ERROR;
+    l_time_staking  -= l_time_now;
 
-    l_time_staking -= dap_time_now();
-
-    if (dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-l_reinvest_percent", &l_reinvest_percent_str)
-    &&	NULL != l_reinvest_percent_str) {
-        if ((l_reinvest_percent  = atoi(l_reinvest_percent_str)) > 100
-        ||	l_reinvest_percent <= 0)
+    if (dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-reinvest", &l_reinvest_percent_str)
+    && NULL != l_reinvest_percent_str) {
+        l_reinvest_percent = dap_chain_coins_to_balance(l_reinvest_percent_str);
+        if (compare256(l_reinvest_percent, dap_chain_coins_to_balance("100.0")) == 1)
             return REINVEST_ARG_ERROR;
+        if (IS_ZERO_256(l_reinvest_percent)) {
+            int l_reinvest_percent_int = atoi(l_reinvest_percent_str);
+            if (l_reinvest_percent_int <= 0 || l_reinvest_percent_int > 100)
+                return REINVEST_ARG_ERROR;
+            l_reinvest_percent = dap_chain_uint256_from(l_reinvest_percent_int);
+            MULT_256_256(l_reinvest_percent, GET_256_FROM_64(1000000000000000000ULL), &l_reinvest_percent);
+        }
     }
 
-    /*________________________________________________________________________________________________________________*/
+/*________________________________________________________________________________________________________________*/
 
-    if (NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallets_path))) {
+    if(NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallets_path))) {
         dap_string_append_printf(output_line, "'%s'", l_wallet_str);
         return WALLET_OPEN_ERROR;
     }
@@ -323,7 +343,9 @@ static enum error_code s_cli_hold(int a_argc, char** a_argv, int a_arg_index, da
     }
 
     l_key_from = dap_chain_wallet_get_key(l_wallet, 0);
-    if (NULL == (l_key_cond = dap_pkey_from_enc_key(l_cert->enc_key))) {
+
+    if (NULL != l_cert
+    &&	NULL == (l_key_cond = dap_pkey_from_enc_key(l_cert->enc_key))) {
         dap_chain_wallet_close(l_wallet);
         DAP_DEL_Z(l_addr_holder);
         dap_string_append_printf(output_line, "'%s'", l_cert_str);
@@ -331,10 +353,10 @@ static enum error_code s_cli_hold(int a_argc, char** a_argv, int a_arg_index, da
     }
 
     l_tx_cond_hash = dap_chain_net_srv_stake_lock_mempool_create(l_net, l_key_from, l_key_cond,
-                                                                 l_ticker_str, l_value, l_uid,
-                                                                 l_addr_holder, l_time_staking, l_reinvest_percent);
+                                                                 l_ticker_str,l_value, l_uid,
+                                                                 l_addr_holder, l_chain, l_time_staking,
+                                                                 l_reinvest_percent, create_base_tx);
 
-    dap_chain_wallet_close(l_wallet);
     DAP_DEL_Z(l_key_cond);
 
     l_hash_str = (l_tx_cond_hash) ? dap_chain_hash_fast_to_str_new(l_tx_cond_hash) : NULL;
@@ -342,25 +364,30 @@ static enum error_code s_cli_hold(int a_argc, char** a_argv, int a_arg_index, da
     if (l_hash_str)
         dap_string_append_printf(output_line, "TX STAKE LOCK CREATED\nSuccessfully hash=%s\nSave to take!\n", l_hash_str);
     else {
+        dap_chain_wallet_close(l_wallet);
         DAP_DEL_Z(l_addr_holder);
         return CREATE_LOCK_TX_ERROR;
     }
 
     DAP_DEL_Z(l_hash_str);
 
-    l_base_tx_hash = dap_chain_mempool_base_tx_create(l_chain_emission, l_tx_cond_hash, l_chain_emission->id,
-                                                      l_value_delegated, delegate_ticker_str, l_addr_holder,
-                                                      &l_cert, 1);
+    if (create_base_tx) {
+        l_base_tx_hash = dap_chain_mempool_base_tx_for_stake_lock_create(l_chain, l_tx_cond_hash, l_chain->id,
+                                                      l_value_delegated, delegate_ticker_str, l_addr_holder, l_key_from);
+    }
 
+    dap_chain_wallet_close(l_wallet);
 
-    l_hash_str = (l_base_tx_hash) ? dap_chain_hash_fast_to_str_new(l_base_tx_hash) : NULL;
+    if (create_base_tx) {
+        l_hash_str = (l_base_tx_hash) ? dap_chain_hash_fast_to_str_new(l_base_tx_hash) : NULL;
 
-    if (l_hash_str)
-        dap_string_append_printf(output_line, "BASE_TX_DATUM_HASH=%s\n", l_hash_str);
-    else {
-        DAP_DEL_Z(l_addr_holder);
-        DAP_DEL_Z(l_tx_cond_hash);
-        return BASE_TX_CREATE_ERROR;
+        if (l_hash_str)
+            dap_string_append_printf(output_line, "BASE_TX_DATUM_HASH=%s\n", l_hash_str);
+        else {
+            DAP_DEL_Z(l_addr_holder);
+            DAP_DEL_Z(l_tx_cond_hash);
+            return BASE_TX_CREATE_ERROR;
+        }
     }
 
     DAP_DEL_Z(l_addr_holder);
@@ -371,31 +398,30 @@ static enum error_code s_cli_hold(int a_argc, char** a_argv, int a_arg_index, da
     return STAKE_NO_ERROR;
 }
 
-static enum error_code s_cli_take(int a_argc, char** a_argv, int a_arg_index, dap_string_t* output_line)
+static enum error_code s_cli_take(int a_argc, char **a_argv, int a_arg_index, dap_string_t *output_line)
 {
     const char *l_net_str, *l_ticker_str, *l_wallet_str, *l_tx_str, *l_tx_burning_str, *l_chain_str;
     l_net_str = l_ticker_str = l_wallet_str = l_tx_str = l_tx_burning_str = l_chain_str = NULL;
-    dap_chain_net_t* l_net = NULL;
-    const char* l_wallets_path = dap_chain_wallet_get_path(g_config);
+    dap_chain_net_t						*l_net				=	NULL;
+    dap_chain_datum_t					*l_datum_burning_tx	=	NULL;
+    const char							*l_wallets_path		=	dap_chain_wallet_get_path(g_config);
     char 	delegate_ticker_str[DAP_CHAIN_TICKER_SIZE_MAX] 	=	{[0] = 'm'};
-    int									l_prev_cond_idx     =   0;
+    int									l_prev_cond_idx		=	0;
     uint256_t							l_value_delegated	= 	{};
-    cond_params_t                       *l_params;
-    char                                *l_datum_hash_str;
-    dap_ledger_t                        *l_ledger;
-    dap_chain_wallet_t                  *l_wallet;
+    char 								*l_datum_hash_str;
+    dap_ledger_t						*l_ledger;
+    dap_chain_wallet_t					*l_wallet;
     dap_hash_fast_t						l_tx_hash;
     dap_hash_fast_t 					l_tx_burning_hash;
-    dap_chain_datum_t                   *l_datum_burning_tx;
-    dap_chain_datum_tx_receipt_t        *l_receipt;
-    dap_chain_datum_tx_t                *l_tx;
-    dap_chain_datum_tx_t                *l_cond_tx;
-    dap_chain_tx_out_cond_t             *l_tx_out_cond;
-    dap_chain_addr_t                    *l_owner_addr;
-    dap_enc_key_t                       *l_owner_key;
+    dap_chain_datum_tx_receipt_t		*l_receipt;
+    dap_chain_datum_tx_t				*l_tx;
+    dap_chain_datum_tx_t				*l_cond_tx;
+    dap_chain_tx_out_cond_t				*l_tx_out_cond;
+    dap_chain_addr_t					*l_owner_addr;
+    dap_enc_key_t						*l_owner_key;
     size_t								l_tx_size;
-    dap_chain_datum_t                   *l_datum;
-    dap_chain_t                         *l_chain;
+    dap_chain_datum_t					*l_datum;
+    dap_chain_t							*l_chain;
     dap_chain_datum_token_t				*delegate_token;
     dap_tsd_t							*l_tsd;
     dap_chain_datum_token_tsd_delegate_from_stake_lock_t l_tsd_section;
@@ -403,7 +429,7 @@ static enum error_code s_cli_take(int a_argc, char** a_argv, int a_arg_index, da
     dap_string_append_printf(output_line, "---> TAKE <---\n");
 
     if (!dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-net", &l_net_str)
-        || NULL == l_net_str)
+    ||	NULL == l_net_str)
         return NET_ARG_ERROR;
 
     if (NULL == (l_net = dap_chain_net_by_name(l_net_str))) {
@@ -412,15 +438,15 @@ static enum error_code s_cli_take(int a_argc, char** a_argv, int a_arg_index, da
     }
 
     if (dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-chain", &l_chain_str)
-        && l_chain_str)
+        &&	l_chain_str)
         l_chain = dap_chain_net_get_chain_by_name(l_net, l_chain_str);
     else
         l_chain = dap_chain_net_get_default_chain_by_chain_type(l_net, CHAIN_TYPE_TX);
-    if (!l_chain)
+    if(!l_chain)
         return CHAIN_ERROR;
 
     if (!dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-tx", &l_tx_str)
-        || NULL == l_tx_str)
+    ||	NULL == l_tx_str)
         return TX_ARG_ERROR;
 
     dap_chain_hash_fast_from_hex_str(l_tx_str, &l_tx_hash);
@@ -430,28 +456,10 @@ static enum error_code s_cli_take(int a_argc, char** a_argv, int a_arg_index, da
 
     l_ledger = l_net->pub.ledger;
 
-    if (NULL == (l_ticker_str = dap_chain_ledger_tx_get_token_ticker_by_hash(l_ledger, &l_tx_hash)))
-        return TX_TICKER_ERROR;
-
-
-    strcpy(delegate_ticker_str  + 1, l_ticker_str);
-
-    if (NULL == (delegate_token = dap_chain_ledger_token_ticker_check(l_ledger, delegate_ticker_str))
-        ||	delegate_token->type != DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL
-        ||	!delegate_token->header_native_decl.tsd_total_size
-        ||	NULL == (l_tsd = dap_tsd_find(delegate_token->data_n_tsd, delegate_token->header_native_decl.tsd_total_size, DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DELEGATE_EMISSION_FROM_STAKE_LOCK))) {
-        dap_string_append_printf(output_line, "'%s'", delegate_ticker_str);
-        return NO_DELEGATE_TOKEN_ERROR;
-    }
-
-    l_tsd_section = dap_tsd_get_scalar(l_tsd, dap_chain_datum_token_tsd_delegate_from_stake_lock_t);
-    if (strcmp(l_ticker_str, l_tsd_section.ticker_token_from)) {
-        return TOKEN_ERROR;
-    }
-
     l_cond_tx = dap_chain_ledger_tx_find_by_hash(l_ledger, &l_tx_hash);
 
-    if (NULL == (l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_cond_tx, &l_prev_cond_idx)))
+    if (NULL == (l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_cond_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK,
+                                                                 &l_prev_cond_idx)))
         return NO_TX_ERROR;
 
     if (l_tx_out_cond->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK)
@@ -461,34 +469,49 @@ static enum error_code s_cli_take(int a_argc, char** a_argv, int a_arg_index, da
         return IS_USED_OUT_ERROR;
     }
 
-    if (l_tx_out_cond->params_size != sizeof(*l_params))// Wrong params size
-        return WRONG_PARAM_SIZE;
-    l_params = (cond_params_t*)l_tx_out_cond->params;
-
-    if (l_params->flags & DAP_CHAIN_NET_SRV_STAKE_LOCK_FLAG_BY_TIME) {
-        if (l_params->time_unlock > dap_time_now())
+    if (l_tx_out_cond->subtype.srv_stake_lock.flags & DAP_CHAIN_NET_SRV_STAKE_LOCK_FLAG_BY_TIME) {
+        if (l_tx_out_cond->subtype.srv_stake_lock.time_unlock > dap_time_now())
             return NOT_ENOUGH_TIME;
     }
 
-    if (!IS_ZERO_256(l_tsd_section.emission_rate)) {
+    if (NULL == (l_ticker_str = dap_chain_ledger_tx_get_token_ticker_by_hash(l_ledger, &l_tx_hash)))
+        return TX_TICKER_ERROR;
+
+    if (l_tx_out_cond->subtype.srv_stake_lock.flags & DAP_CHAIN_NET_SRV_STAKE_LOCK_FLAG_CREATE_BASE_TX) {
+        strcpy(delegate_ticker_str + 1, l_ticker_str);
+
+        if (NULL == (delegate_token = dap_chain_ledger_token_ticker_check(l_ledger, delegate_ticker_str))
+            ||	(delegate_token->type != DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL && delegate_token->type != DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_UPDATE)
+            ||	!delegate_token->header_native_decl.tsd_total_size
+            ||	NULL == (l_tsd = dap_tsd_find(delegate_token->data_n_tsd, delegate_token->header_native_decl.tsd_total_size, DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DELEGATE_EMISSION_FROM_STAKE_LOCK))) {
+            dap_string_append_printf(output_line, "'%s'", delegate_ticker_str);
+            return NO_DELEGATE_TOKEN_ERROR;
+        }
+
+        l_tsd_section = dap_tsd_get_scalar(l_tsd, dap_chain_datum_token_tsd_delegate_from_stake_lock_t);
+        if (strcmp(l_ticker_str, l_tsd_section.ticker_token_from))
+            return TOKEN_ERROR;
+    }
+
+    if ((l_tx_out_cond->subtype.srv_stake_lock.flags & DAP_CHAIN_NET_SRV_STAKE_LOCK_FLAG_CREATE_BASE_TX)
+    &&	!IS_ZERO_256(l_tsd_section.emission_rate)) {
         MULT_256_COIN(l_tx_out_cond->header.value, l_tsd_section.emission_rate, &l_value_delegated);
         if (IS_ZERO_256(l_value_delegated))
             return COINS_FORMAT_ERROR;
-    } else {
+    } else
         l_value_delegated = l_tx_out_cond->header.value;
-    }
 
     if (!dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, a_argc, "-wallet", &l_wallet_str)
-        || NULL == l_wallet_str)
+    ||	NULL == l_wallet_str)
         return WALLET_ARG_ERROR;
 
     if (NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallets_path)))
         return WALLET_OPEN_ERROR;
 
-    if (NULL == (l_owner_addr = (dap_chain_addr_t*)dap_chain_wallet_get_addr(l_wallet, l_net->pub.id))) {
+    if (NULL == (l_owner_addr = (dap_chain_addr_t *)dap_chain_wallet_get_addr(l_wallet, l_net->pub.id))) {
         dap_chain_wallet_close(l_wallet);
         return WALLET_ADDR_ERROR;
-    }
+        }
 
     if (NULL == (l_owner_key = dap_chain_wallet_get_key(l_wallet, 0))) {
         dap_chain_wallet_close(l_wallet);
@@ -496,9 +519,9 @@ static enum error_code s_cli_take(int a_argc, char** a_argv, int a_arg_index, da
         return OWNER_KEY_ERROR;
     }
 
-    /*________________________________________________________________________________________________________________*/
+/*________________________________________________________________________________________________________________*/
 
-        //add tx
+    //add tx
     if (NULL == (l_tx = dap_chain_datum_tx_create())) {//malloc
         dap_chain_wallet_close(l_wallet);
         DAP_DEL_Z(l_owner_addr);
@@ -510,28 +533,30 @@ static enum error_code s_cli_take(int a_argc, char** a_argv, int a_arg_index, da
     dap_chain_datum_tx_add_out_item(&l_tx, l_owner_addr, l_tx_out_cond->header.value);
 
     //add burning tx
-    if (NULL == (l_datum_burning_tx = dap_chain_burning_tx_create(l_chain, l_owner_key, l_owner_addr, NULL,
-        delegate_ticker_str, l_value_delegated))) {//malloc
-        dap_chain_wallet_close(l_wallet);
-        DAP_DEL_Z(l_owner_addr);
-        dap_chain_datum_tx_delete(l_tx);
-        return CREATE_BURNING_TX_ERROR;
-    }
+    if (l_tx_out_cond->subtype.srv_stake_lock.flags & DAP_CHAIN_NET_SRV_STAKE_LOCK_FLAG_CREATE_BASE_TX) {
+        if (NULL == (l_datum_burning_tx = dap_chain_burning_tx_create(l_chain, l_owner_key, l_owner_addr, NULL,
+                                                                  delegate_ticker_str, l_value_delegated))) {//malloc
+            dap_chain_wallet_close(l_wallet);
+            DAP_DEL_Z(l_owner_addr);
+            dap_chain_datum_tx_delete(l_tx);
+            return CREATE_BURNING_TX_ERROR;
+        }
 
-    //get tx hash
-    dap_hash_fast(l_datum_burning_tx->data, l_datum_burning_tx->header.data_size, &l_tx_burning_hash);
+        //get tx hash
+        dap_hash_fast(l_datum_burning_tx->data, l_datum_burning_tx->header.data_size, &l_tx_burning_hash);
 
-    if (NULL == (l_receipt = s_receipt_create(&l_tx_burning_hash, delegate_ticker_str, l_value_delegated))) {
-        dap_chain_wallet_close(l_wallet);
-        DAP_DEL_Z(l_owner_addr);
-        dap_chain_datum_tx_delete(l_tx);
-        DAP_DEL_Z(l_datum_burning_tx);
-        return CREATE_RECEIPT_ERROR;
-    }
+        if (NULL == (l_receipt = s_receipt_create(&l_tx_burning_hash, delegate_ticker_str, l_value_delegated))) {
+            dap_chain_wallet_close(l_wallet);
+            DAP_DEL_Z(l_owner_addr);
+            dap_chain_datum_tx_delete(l_tx);
+            DAP_DEL_Z(l_datum_burning_tx);
+            return CREATE_RECEIPT_ERROR;
+        }
 
-    dap_chain_datum_tx_add_item(&l_tx, (byte_t*)l_receipt);
+        dap_chain_datum_tx_add_item(&l_tx, (byte_t *)l_receipt);
+    }
 
-    if (dap_chain_datum_tx_add_sign_item(&l_tx, l_owner_key) != 1) {
+    if(dap_chain_datum_tx_add_sign_item(&l_tx, l_owner_key) != 1) {
         dap_chain_wallet_close(l_wallet);
         DAP_DEL_Z(l_owner_addr);
         dap_chain_datum_tx_delete(l_tx);
@@ -553,16 +578,18 @@ static enum error_code s_cli_take(int a_argc, char** a_argv, int a_arg_index, da
 
     dap_chain_datum_tx_delete(l_tx);
 
-    if (NULL == (l_datum_hash_str = dap_chain_mempool_datum_add(l_datum_burning_tx, l_chain))) {
+    if (l_tx_out_cond->subtype.srv_stake_lock.flags & DAP_CHAIN_NET_SRV_STAKE_LOCK_FLAG_CREATE_BASE_TX) {
+        if (NULL == (l_datum_hash_str = dap_chain_mempool_datum_add(l_datum_burning_tx, l_chain))) {
+            DAP_DEL_Z(l_datum_burning_tx);
+            DAP_DEL_Z(l_datum);
+            return ADD_DATUM_BURNING_TX_ERROR;
+        }
+
+        dap_string_append_printf(output_line, "BURNING_TX_DATUM_HASH=%s\n", l_datum_hash_str);
         DAP_DEL_Z(l_datum_burning_tx);
-        DAP_DEL_Z(l_datum);
-        return ADD_DATUM_BURNING_TX_ERROR;
+        DAP_DEL_Z(l_datum_hash_str);
     }
 
-    dap_string_append_printf(output_line, "BURNING_TX_DATUM_HASH=%s\n", l_datum_hash_str);
-    DAP_DEL_Z(l_datum_burning_tx);
-    DAP_DEL_Z(l_datum_hash_str);
-
     // Processing will be made according to autoprocess policy
     if (NULL == (l_datum_hash_str = dap_chain_mempool_datum_add(l_datum, l_chain))) {
         DAP_DEL_Z(l_datum);
@@ -582,173 +609,173 @@ static enum error_code s_cli_take(int a_argc, char** a_argv, int a_arg_index, da
  * @param errorCode
  * @param output_line
  */
-static void s_error_handler(enum error_code errorCode, dap_string_t* output_line)
+static void s_error_handler(enum error_code errorCode, dap_string_t *output_line)
 {
     dap_string_append_printf(output_line, "ERROR!\n");
     switch (errorCode)
     {
-    case NET_ARG_ERROR: {
-        dap_string_append_printf(output_line, "stake_lock command required parameter -net");
-    } break;
-
-    case NET_ERROR: {
-        dap_string_append_printf(output_line, "^^^ network not found");
-    } break;
-
-    case TOKEN_ARG_ERROR: {
-        dap_string_append_printf(output_line, "stake_lock command required parameter -token");
-    } break;
-
-    case TOKEN_ERROR: {
-        dap_string_append_printf(output_line, "^^^ token ticker not found");
-    } break;
-
-    case COINS_ARG_ERROR: {
-        dap_string_append_printf(output_line, "stake_lock command required parameter -coins");
-    } break;
-
-    case COINS_FORMAT_ERROR: {
-        dap_string_append_printf(output_line, "Format -coins <256 bit integer>");
-    } break;
-
-    case ADDR_ARG_ERROR: {
-        dap_string_append_printf(output_line, "stake_lock command required parameter -addr_holder");
-    } break;
-
-    case ADDR_FORMAT_ERROR: {
-        dap_string_append_printf(output_line, "wrong address holder format");
-    } break;
-
-    case CERT_ARG_ERROR: {
-        dap_string_append_printf(output_line, "stake_lock command required parameter -cert");
-    } break;
-
-    case CERT_LOAD_ERROR: {
-        dap_string_append_printf(output_line, "^^^ can't load cert");
-    } break;
-
-    case CHAIN_ERROR: {
-        dap_string_append_printf(output_line, "stake_lock command requires parameter '-chain'.\n"
-            "you can set default datum type in chain configuration file");
-    } break;
-
-    case CHAIN_EMISSION_ERROR: {
-        dap_string_append_printf(output_line, "stake_lock command requires parameter '-chain_emission'.\n"
-            "you can set default datum type in chain configuration file");
-    } break;
-
-    case TIME_ERROR: {
-        dap_string_append_printf(output_line, "stake_ext command requires parameter '-time_staking' in simplified format YYMMDD\n"
-                                                                        "Example: \"220610\" == \"10 june 2022 00:00\"");
-    } break;
+        case NET_ARG_ERROR: {
+            dap_string_append_printf(output_line, "stake_lock command required parameter -net");
+            } break;
+
+        case NET_ERROR: {
+            dap_string_append_printf(output_line, " ^^^ network not found");
+            } break;
+
+        case TOKEN_ARG_ERROR: {
+            dap_string_append_printf(output_line, "stake_lock command required parameter -token");
+            } break;
+
+        case TOKEN_ERROR: {
+            dap_string_append_printf(output_line, " ^^^ token ticker not found");
+            } break;
+
+        case COINS_ARG_ERROR: {
+            dap_string_append_printf(output_line, "stake_lock command required parameter -coins");
+            } break;
+
+        case COINS_FORMAT_ERROR: {
+            dap_string_append_printf(output_line, "Format -coins <256 bit integer>");
+            } break;
+
+        case ADDR_ARG_ERROR: {
+            dap_string_append_printf(output_line, "stake_lock command required parameter -addr_holder");
+            } break;
+
+        case ADDR_FORMAT_ERROR: {
+            dap_string_append_printf(output_line, "wrong address holder format");
+            } break;
+
+        case CERT_ARG_ERROR: {
+            dap_string_append_printf(output_line, "stake_lock command required parameter -cert");
+            } break;
+
+        case CERT_LOAD_ERROR: {
+            dap_string_append_printf(output_line, " ^^^ can't load cert");
+            } break;
+
+        case CHAIN_ERROR: {
+            dap_string_append_printf(output_line, "stake_lock command requires parameter '-chain'.\n"
+                                                                        "you can set default datum type in chain configuration file");
+            } break;
+
+        case CHAIN_EMISSION_ERROR: {
+            dap_string_append_printf(output_line, "stake_lock command requires parameter '-chain_emission'.\n"
+                                                                        "you can set default datum type in chain configuration file");
+            } break;
+
+        case TIME_ERROR: {
+            dap_string_append_printf(output_line, "stake_lock command requires parameter '-time_staking' in simplified format YYMMDD\n"
+                                                                "Example: \"220610\" == \"10 june 2022 00:00\"");
+            } break;
 
-    case NO_MONEY_ERROR: {
-        dap_string_append_printf(output_line, "Not enough money");
-    } break;
+        case NO_MONEY_ERROR: {
+            dap_string_append_printf(output_line, "Not enough money");
+            } break;
 
-    case WALLET_ARG_ERROR: {
-        dap_string_append_printf(output_line, "stake_lock command required parameter -wallet");
-    } break;
-
-    case WALLET_OPEN_ERROR: {
-        dap_string_append_printf(output_line, "^^^ can't open wallet");
-    } break;
-
-    case CERT_KEY_ERROR: {
-        dap_string_append_printf(output_line, "^^^ cert doesn't contain a valid public key");
-    } break;
-
-    case WALLET_ADDR_ERROR: {
-        dap_string_append_printf(output_line, "^^^ failed to get wallet address");
-    } break;
-
-    case TX_ARG_ERROR: {
-        dap_string_append_printf(output_line, "stake_lock command required parameter -tx");
-    } break;
-
-    case HASH_IS_BLANK_ERROR: {
-        dap_string_append_printf(output_line, "tx hash is blank");
-    } break;
-
-    case NO_TX_ERROR: {
-        dap_string_append_printf(output_line, "^^^ could not find transaction");
-    } break;
-
-    case STAKE_ERROR: {
-        dap_string_append_printf(output_line, "STAKE ERROR");
-    } break;
-
-    case NOT_ENOUGH_TIME: {
-        dap_string_append_printf(output_line, "Not enough time has passed");
-    } break;
-
-    case TX_TICKER_ERROR: {
-        dap_string_append_printf(output_line, "ticker not found");
-    } break;
-
-    case NO_DELEGATE_TOKEN_ERROR: {
-        dap_string_append_printf(output_line, " ^^^ delegated token not found");
-    } break;
-
-    case NO_VALID_SUBTYPE_ERROR: {
-        dap_string_append_printf(output_line, "wrong subtype for transaction");
-    } break;
-
-    case IS_USED_OUT_ERROR: {
-        dap_string_append_printf(output_line, "tx hash is used out");
-    } break;
-
-    case OWNER_KEY_ERROR: {
-        dap_string_append_printf(output_line, "key retrieval error");
-    } break;
-
-    case CREATE_TX_ERROR: {
-        dap_string_append_printf(output_line, "memory allocation error when creating a transaction");
-    } break;
-
-    case CREATE_BURNING_TX_ERROR: {
-        dap_string_append_printf(output_line, "failed to create a transaction that burns funds");
-    } break;
-
-    case CREATE_RECEIPT_ERROR: {
-        dap_string_append_printf(output_line, "failed to create receipt");
-    } break;
-
-    case SIGN_ERROR: {
-        dap_string_append_printf(output_line, "failed to sign transaction");
-    } break;
-
-    case ADD_DATUM_BURNING_TX_ERROR: {
-        dap_string_append_printf(output_line, "failed to add datum with burning-transaction to mempool");
-    } break;
-
-    case ADD_DATUM_TX_TAKE_ERROR: {
-        dap_string_append_printf(output_line, "failed to add datum with take-transaction to mempool");
-    } break;
-
-    case BASE_TX_CREATE_ERROR: {
-        dap_string_append_printf(output_line, "failed to create the base transaction for emission");
-    } break;
-
-    case WRONG_PARAM_SIZE: {
-        dap_string_append_printf(output_line, "error while checking conditional transaction parameters");
-    } break;
-
-    case CREATE_LOCK_TX_ERROR: {
-        dap_string_append_printf(output_line, "error creating transaction");
-    } break;
-
-    case CREATE_DATUM_ERROR: {
-        dap_string_append_printf(output_line, "error while creating datum from transaction");
-    } break;
+        case WALLET_ARG_ERROR: {
+            dap_string_append_printf(output_line, "stake_lock command required parameter -wallet");
+            } break;
+
+        case WALLET_OPEN_ERROR: {
+            dap_string_append_printf(output_line, " ^^^ can't open wallet");
+            } break;
+
+        case CERT_KEY_ERROR: {
+            dap_string_append_printf(output_line, " ^^^ cert doesn't contain a valid public key");
+            } break;
+
+        case WALLET_ADDR_ERROR: {
+            dap_string_append_printf(output_line, " ^^^ failed to get wallet address");
+            } break;
+
+        case TX_ARG_ERROR: {
+            dap_string_append_printf(output_line, "stake_lock command required parameter -tx");
+            } break;
+
+        case HASH_IS_BLANK_ERROR: {
+            dap_string_append_printf(output_line, "tx hash is blank");
+            } break;
+
+        case NO_TX_ERROR: {
+            dap_string_append_printf(output_line, " ^^^ could not find transaction");
+            } break;
+
+        case STAKE_ERROR: {
+            dap_string_append_printf(output_line, "STAKE ERROR");
+            } break;
+
+        case NOT_ENOUGH_TIME: {
+            dap_string_append_printf(output_line, "Not enough time has passed");
+            } break;
+
+        case TX_TICKER_ERROR: {
+            dap_string_append_printf(output_line, "ticker not found");
+            } break;
+
+        case NO_DELEGATE_TOKEN_ERROR: {
+            dap_string_append_printf(output_line, " ^^^ delegated token not found");
+            } break;
+
+        case NO_VALID_SUBTYPE_ERROR: {
+            dap_string_append_printf(output_line, "wrong subtype for transaction");
+            } break;
+
+        case IS_USED_OUT_ERROR: {
+            dap_string_append_printf(output_line, "tx hash is used out");
+            } break;
+
+        case OWNER_KEY_ERROR: {
+            dap_string_append_printf(output_line, "key retrieval error");
+            } break;
+
+        case CREATE_TX_ERROR: {
+            dap_string_append_printf(output_line, "memory allocation error when creating a transaction");
+            } break;
+
+        case CREATE_BURNING_TX_ERROR: {
+            dap_string_append_printf(output_line, "failed to create a transaction that burns funds");
+            } break;
+
+        case CREATE_RECEIPT_ERROR: {
+            dap_string_append_printf(output_line, "failed to create receipt");
+            } break;
+
+        case SIGN_ERROR: {
+            dap_string_append_printf(output_line, "failed to sign transaction");
+            } break;
+
+        case ADD_DATUM_BURNING_TX_ERROR: {
+            dap_string_append_printf(output_line, "failed to add datum with burning-transaction to mempool");
+            } break;
+
+        case ADD_DATUM_TX_TAKE_ERROR: {
+            dap_string_append_printf(output_line, "failed to add datum with take-transaction to mempool");
+            } break;
+
+        case BASE_TX_CREATE_ERROR: {
+            dap_string_append_printf(output_line, "failed to create the base transaction for emission");
+            } break;
+
+        case WRONG_PARAM_SIZE: {
+            dap_string_append_printf(output_line, "error while checking conditional transaction parameters");
+            } break;
+
+        case CREATE_LOCK_TX_ERROR: {
+            dap_string_append_printf(output_line, "error creating transaction");
+            } break;
+
+        case CREATE_DATUM_ERROR: {
+            dap_string_append_printf(output_line, "error while creating datum from transaction");
+            } break;
 
-    case REINVEST_ARG_ERROR: {
-        dap_string_append_printf(output_line, "reinvestment is set as a percentage from 1 to 100");
-    } break;
+        case REINVEST_ARG_ERROR: {
+            dap_string_append_printf(output_line, "reinvestment is set as a percentage from 1 to 100");
+            } break;
 
-    default: {
-        dap_string_append_printf(output_line, "STAKE_LOCK: Unrecognized error");
-    } break;
+        default: {
+            dap_string_append_printf(output_line, "STAKE_LOCK: Unrecognized error");
+            } break;
     }
 }
 
@@ -759,16 +786,16 @@ static void s_error_handler(enum error_code errorCode, dap_string_t* output_line
  * @param a_str_reply
  * @return
  */
-static int s_cli_stake_lock(int a_argc, char** a_argv, char** a_str_reply)
+static int s_cli_stake_lock(int a_argc, char **a_argv, char **a_str_reply)
 {
-    enum {
+    enum{
         CMD_NONE, CMD_HOLD, CMD_TAKE
     };
 
     enum error_code	errorCode;
-    int				l_arg_index = 1;
-    int				l_cmd_num = CMD_NONE;
-    dap_string_t* output_line = dap_string_new(NULL);
+    int				l_arg_index		= 1;
+    int				l_cmd_num		= CMD_NONE;
+    dap_string_t	*output_line	= dap_string_new(NULL);
 
     if (dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "hold", NULL))
         l_cmd_num = CMD_HOLD;
@@ -777,18 +804,18 @@ static int s_cli_stake_lock(int a_argc, char** a_argv, char** a_str_reply)
 
     switch (l_cmd_num) {
 
-    case CMD_HOLD: {
-        errorCode = s_cli_hold(a_argc, a_argv, l_arg_index + 1, output_line);
-    } break;
+        case CMD_HOLD: {
+            errorCode = s_cli_hold(a_argc, a_argv, l_arg_index + 1, output_line);
+            } break;
 
-    case CMD_TAKE: {
-        errorCode = s_cli_take(a_argc, a_argv, l_arg_index + 1, output_line);
-    } break;
+        case CMD_TAKE: {
+            errorCode = s_cli_take(a_argc, a_argv, l_arg_index + 1, output_line);
+            } break;
 
-    default: {
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "Command %s not recognized", a_argv[l_arg_index]);
-        dap_string_free(output_line, false);
-    } return 1;
+        default: {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Command %s not recognized", a_argv[l_arg_index]);
+            dap_string_free(output_line, false);
+            } return 1;
     }
 
     if (STAKE_NO_ERROR != errorCode)
@@ -807,51 +834,51 @@ static int s_cli_stake_lock(int a_argc, char** a_argv, char** a_str_reply)
  * @param month_count
  * @return
  */
-static const char* s_give_month_str_from_month_count(uint8_t month_count)
+static const char *s_give_month_str_from_month_count(uint8_t month_count)
 {
 
     switch (month_count)
     {
-    case 1: {
-        return "Jan";
-    }
-    case 2: {
-        return "Feb";
-    }
-    case 3: {
-        return "Mar";
-    }
-    case 4: {
-        return "Apr";
-    }
-    case 5: {
-        return "May";
-    }
-    case 6: {
-        return "Jun";
-    }
-    case 7: {
-        return "Jul";
-    }
-    case 8: {
-        return "Aug";
-    }
-    case 9: {
-        return "Sep";
-    }
-    case 10: {
-        return "Oct";
-    }
-    case 11: {
-        return "Nov";
-    }
-    case 12: {
-        return "Dec";
-    }
+        case 1: {
+            return "Jan";
+        }
+        case 2: {
+            return "Feb";
+        }
+        case 3: {
+            return "Mar";
+        }
+        case 4: {
+            return "Apr";
+        }
+        case 5: {
+            return "May";
+        }
+        case 6: {
+            return "Jun";
+        }
+        case 7: {
+            return "Jul";
+        }
+        case 8: {
+            return "Aug";
+        }
+        case 9: {
+            return "Sep";
+        }
+        case 10: {
+            return "Oct";
+        }
+        case 11: {
+            return "Nov";
+        }
+        case 12: {
+            return "Dec";
+        }
 
-    default: {
-        return "";
-    }
+        default: {
+            return "";
+        }
     }
 }
 
@@ -860,7 +887,7 @@ static const char* s_give_month_str_from_month_count(uint8_t month_count)
  * @param time
  * @return
  */
-static uint8_t s_give_month_count_from_time_str(char* time)
+static uint8_t s_give_month_count_from_time_str(char *time)
 {
     const uint8_t len_month = 3;
 
@@ -898,20 +925,20 @@ static uint8_t s_give_month_count_from_time_str(char* time)
  * @param month_count
  * @return
  */
-static char* s_update_date_by_using_month_count(char* time, uint8_t month_count)
+static char *s_update_date_by_using_month_count(char *time, uint8_t month_count)
 {
     uint8_t		current_month;
     int			current_year;
-    const char* month_str;
-    const char* year_str;
+    const char 	*month_str;
+    const char 	*year_str;
 
     if (!time || !month_count)
         return NULL;
-    if ((current_month = s_give_month_count_from_time_str(time)) == 0)
+    if (	(current_month = s_give_month_count_from_time_str(time))	== 0	)
         return NULL;
-    if ((current_year = atoi(&time[YEAR_INDEX])) <= 0
-        || current_year < 22
-        || current_year 												> 99)
+    if (	(current_year = atoi(&time[YEAR_INDEX])) 					<= 0
+    ||		current_year 												< 22
+    ||		current_year 												> 99	)
         return NULL;
 
 
@@ -925,16 +952,15 @@ static char* s_update_date_by_using_month_count(char* time, uint8_t month_count)
             current_month++;
     }
 
-    month_str = s_give_month_str_from_month_count(current_month);
-    year_str = dap_itoa(current_year);
+    month_str	= s_give_month_str_from_month_count(current_month);
+    year_str	= dap_itoa(current_year);
 
     if (*month_str
-        && *year_str
-        && dap_strlen(year_str) == 2) {
-        memcpy(&time[MONTH_INDEX], month_str, 3);	// 3 == len month in time RFC822 format
-        memcpy(&time[YEAR_INDEX], year_str, 2);	// 2 == len year in time RFC822 format
-    }
-    else
+    &&	*year_str
+    &&	dap_strlen(year_str) == 2) {
+        memcpy(&time[MONTH_INDEX],	month_str,	3);	// 3 == len month in time RFC822 format
+        memcpy(&time[YEAR_INDEX],	year_str,	2);	// 2 == len year in time RFC822 format
+    } else
         return NULL;
 
     return time;
@@ -942,62 +968,62 @@ static char* s_update_date_by_using_month_count(char* time, uint8_t month_count)
 
 /**
  * @brief s_callback_verificator
+ * @param a_ledger
+ * @param a_tx_out_hash
  * @param a_cond
- * @param a_tx
+ * @param a_tx_in
  * @param a_owner
  * @return
  */
-bool s_callback_verificator(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner)
+static bool s_stake_lock_callback_verificator(dap_ledger_t *a_ledger, dap_hash_fast_t *a_tx_out_hash, dap_chain_tx_out_cond_t *a_cond,
+                                   dap_chain_datum_tx_t *a_tx_in, bool a_owner)
 {
+    UNUSED(a_tx_out_hash);
     dap_chain_datum_tx_t									*burning_tx					= NULL;
     dap_chain_tx_out_t										*burning_transaction_out	= NULL;
+    dap_chain_datum_tx_receipt_t							*l_receipt					= NULL;
     uint256_t												l_value_delegated			= {};
     dap_hash_fast_t											hash_burning_transaction;
     dap_chain_datum_token_tsd_delegate_from_stake_lock_t	l_tsd_section;
     dap_tsd_t												*l_tsd;
-    cond_params_t 											*l_params;
-    dap_chain_datum_tx_receipt_t							*l_receipt;
     dap_chain_tx_out_t										*l_tx_out;
     dap_chain_tx_in_cond_t									*l_tx_in_cond;
     const char												*l_tx_ticker;
     dap_chain_datum_token_t									*delegate_token;
+    char 													delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
 
     /*if (!a_owner) TODO: ???
     return false;*/
 
-    if (a_cond->params_size != sizeof(*l_params))// Wrong params size
-        return false;
-    l_params = (cond_params_t*)a_cond->params;
-
-    if (l_params->flags & DAP_CHAIN_NET_SRV_STAKE_LOCK_FLAG_BY_TIME) {
-        if (l_params->time_unlock > dap_time_now())
+    if (a_cond->subtype.srv_stake_lock.flags & DAP_CHAIN_NET_SRV_STAKE_LOCK_FLAG_BY_TIME) {
+        if (a_cond->subtype.srv_stake_lock.time_unlock > dap_time_now())
             return false;
     }
 
-    l_receipt = (dap_chain_datum_tx_receipt_t *)dap_chain_datum_tx_item_get(a_tx, 0, TX_ITEM_TYPE_RECEIPT, 0);
-    if (!l_receipt)
-        return false;
+    if (a_cond->subtype.srv_stake_lock.flags & DAP_CHAIN_NET_SRV_STAKE_LOCK_FLAG_CREATE_BASE_TX) {
+        l_receipt = (dap_chain_datum_tx_receipt_t *)dap_chain_datum_tx_item_get(a_tx_in, 0, TX_ITEM_TYPE_RECEIPT, 0);
+        if (!l_receipt)
+            return false;
 
 #if DAP_CHAIN_NET_SRV_UID_SIZE == 8
-    if (l_receipt->receipt_info.srv_uid.uint64 != DAP_CHAIN_NET_SRV_STAKE_LOCK_ID)
-        return false;
+        if (l_receipt->receipt_info.srv_uid.uint64 != DAP_CHAIN_NET_SRV_STAKE_LOCK_ID)
+            return false;
 #elif DAP_CHAIN_NET_SRV_UID_SIZE == 16
-    if (l_receipt->receipt_info.srv_uid.uint128 != DAP_CHAIN_NET_SRV_EXTERNAL_STAKE_ID)
-        return false;
+        if (l_receipt->receipt_info.srv_uid.uint128 != DAP_CHAIN_NET_SRV_EXTERNAL_STAKE_ID)
+            return false;
 #endif
 
-    char delegated_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
-    if (l_receipt->exts_size) {
-        hash_burning_transaction = *(dap_hash_fast_t*)l_receipt->exts_n_signs;
-        strcpy(delegated_ticker, (char *)&l_receipt->exts_n_signs[sizeof(dap_hash_fast_t)]);
-    } else {
-        return false;
-    }
+        if (l_receipt->exts_size) {
+            hash_burning_transaction = *(dap_hash_fast_t*)l_receipt->exts_n_signs;
+            strcpy(delegated_ticker, (char *)&l_receipt->exts_n_signs[sizeof(dap_hash_fast_t)]);
+        } else
+            return false;
 
-    if (dap_hash_fast_is_blank(&hash_burning_transaction))
-        return false;
+        if (dap_hash_fast_is_blank(&hash_burning_transaction))
+            return false;
+    }
 
-    l_tx_out = (dap_chain_tx_out_t *)dap_chain_datum_tx_item_get(a_tx, 0, TX_ITEM_TYPE_OUT,0);
+    l_tx_out = (dap_chain_tx_out_t *)dap_chain_datum_tx_item_get(a_tx_in, 0, TX_ITEM_TYPE_OUT, 0);
 
     if (!l_tx_out)
         return false;
@@ -1005,66 +1031,67 @@ bool s_callback_verificator(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_t *a_c
     if (!EQUAL_256(a_cond->header.value, l_tx_out->header.value))
         return false;
 
-    if (NULL == (delegate_token = dap_chain_ledger_token_ticker_check(a_ledger, delegated_ticker))
-        ||	delegate_token->type != DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL
-        ||	!delegate_token->header_native_decl.tsd_total_size
-        ||	NULL == (l_tsd = dap_tsd_find(delegate_token->data_n_tsd, delegate_token->header_native_decl.tsd_total_size, DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DELEGATE_EMISSION_FROM_STAKE_LOCK))) {
-        return false;
-    }
+    if (a_cond->subtype.srv_stake_lock.flags & DAP_CHAIN_NET_SRV_STAKE_LOCK_FLAG_CREATE_BASE_TX) {
+        if (NULL == (delegate_token = dap_chain_ledger_token_ticker_check(a_ledger, delegated_ticker))
+            ||	(delegate_token->type != DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_DECL && delegate_token->type != DAP_CHAIN_DATUM_TOKEN_TYPE_NATIVE_UPDATE)
+            ||	!delegate_token->header_native_decl.tsd_total_size
+            ||	NULL == (l_tsd = dap_tsd_find(delegate_token->data_n_tsd, delegate_token->header_native_decl.tsd_total_size, DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DELEGATE_EMISSION_FROM_STAKE_LOCK))) {
+            return false;
+        }
 
-    l_tsd_section = dap_tsd_get_scalar(l_tsd, dap_chain_datum_token_tsd_delegate_from_stake_lock_t);
+        l_tsd_section = dap_tsd_get_scalar(l_tsd, dap_chain_datum_token_tsd_delegate_from_stake_lock_t);
 
-    if (NULL == (l_tx_in_cond = (dap_chain_tx_in_cond_t *)dap_chain_datum_tx_item_get(a_tx, 0, TX_ITEM_TYPE_IN_COND, 0)))
-        return false;
-    if (dap_hash_fast_is_blank(&l_tx_in_cond->header.tx_prev_hash))
-        return false;
-    if (NULL == (l_tx_ticker = dap_chain_ledger_tx_get_token_ticker_by_hash(a_ledger, &l_tx_in_cond->header.tx_prev_hash)))
-        return false;
-    if (strcmp(l_tx_ticker, l_tsd_section.ticker_token_from))
-        return false;
-    if (NULL == (l_tx_ticker = dap_chain_ledger_tx_get_token_ticker_by_hash(a_ledger, &hash_burning_transaction)))
-        return false;
-    if (strcmp(l_tx_ticker, delegated_ticker)) {
-        return false;
-    }
+        if (NULL == (l_tx_in_cond = (dap_chain_tx_in_cond_t *)dap_chain_datum_tx_item_get(a_tx_in, 0, TX_ITEM_TYPE_IN_COND, 0)))
+            return false;
+        if (dap_hash_fast_is_blank(&l_tx_in_cond->header.tx_prev_hash))
+            return false;
+        if (NULL == (l_tx_ticker = dap_chain_ledger_tx_get_token_ticker_by_hash(a_ledger, &l_tx_in_cond->header.tx_prev_hash)))
+            return false;
+        if (strcmp(l_tx_ticker, l_tsd_section.ticker_token_from))
+            return false;
+        if (NULL == (l_tx_ticker = dap_chain_ledger_tx_get_token_ticker_by_hash(a_ledger, &hash_burning_transaction)))
+            return false;
+        if (strcmp(l_tx_ticker, delegated_ticker))
+            return false;
 
-    burning_tx = dap_chain_ledger_tx_find_by_hash(a_ledger, &hash_burning_transaction);
-    burning_transaction_out = (dap_chain_tx_out_t*)dap_chain_datum_tx_item_get(burning_tx, 0, TX_ITEM_TYPE_OUT, 0);
+        burning_tx = dap_chain_ledger_tx_find_by_hash(a_ledger, &hash_burning_transaction);
+        burning_transaction_out = (dap_chain_tx_out_t *)dap_chain_datum_tx_item_get(burning_tx, 0, TX_ITEM_TYPE_OUT,0);
 
-    if (!burning_transaction_out)
-        return false;
+        if (!burning_transaction_out)
+            return false;
+
+        if (!dap_hash_fast_is_blank(&burning_transaction_out->addr.data.hash_fast)) {
+            if (s_debug_more) {
+                const char *addr_srt = dap_chain_hash_fast_to_str_new(&burning_transaction_out->addr.data.hash_fast);
+                log_it(L_ERROR, "ADDR from burning NOT BLANK: %s", addr_srt);
+                DAP_DEL_Z(addr_srt);
+            }
+            return false;
+        }
+
+        if (!IS_ZERO_256(l_tsd_section.emission_rate)) {
+            MULT_256_COIN(l_tx_out->header.value, l_tsd_section.emission_rate, &l_value_delegated);
+            if (IS_ZERO_256(l_value_delegated))
+                return COINS_FORMAT_ERROR;
+        } else
+            l_value_delegated = l_tx_out->header.value;
 
-    if (!dap_hash_fast_is_blank(&burning_transaction_out->addr.data.hash_fast)) {
         if (s_debug_more) {
-            const char *addr_srt = dap_chain_hash_fast_to_str_new(&burning_transaction_out->addr.data.hash_fast);
-            log_it(L_ERROR, "ADDR from burning NOT BLANK: %s", addr_srt);
-            DAP_DEL_Z(addr_srt);
+            char *str1 = dap_chain_balance_print(burning_transaction_out->header.value);
+            char *str2 = dap_chain_balance_print(l_tx_out->header.value);
+            char *str3 = dap_chain_balance_print(l_value_delegated);
+            log_it(L_INFO, "burning_value: |%s|",	str1);
+            log_it(L_INFO, "hold/take_value: |%s|",	str2);
+            log_it(L_INFO, "delegated_value |%s|",	str3);
+            DAP_DEL_Z(str1);
+            DAP_DEL_Z(str2);
+            DAP_DEL_Z(str3);
         }
-        return false;
-    }
 
-    if (!IS_ZERO_256(l_tsd_section.emission_rate)) {
-        MULT_256_COIN(l_tx_out->header.value, l_tsd_section.emission_rate, &l_value_delegated);
-        if (IS_ZERO_256(l_value_delegated))
-            return COINS_FORMAT_ERROR;
-    } else
-        l_value_delegated = l_tx_out->header.value;
-
-    if (s_debug_more) {
-        char *str1 = dap_chain_balance_print(burning_transaction_out->header.value);
-        char *str2 = dap_chain_balance_print(l_tx_out->header.value);
-        char *str3 = dap_chain_balance_print(l_value_delegated);
-        log_it(L_INFO, "burning_value: |%s|",	str1);
-        log_it(L_INFO, "hold/take_value: |%s|",	str2);
-        log_it(L_INFO, "delegated_value |%s|",	str3);
-        DAP_DEL_Z(str1);
-        DAP_DEL_Z(str2);
-        DAP_DEL_Z(str3);
+        if (!EQUAL_256(burning_transaction_out->header.value, l_value_delegated))
+            return false;
     }
 
-    if (!EQUAL_256(burning_transaction_out->header.value, l_value_delegated))//MULT
-        return false;
-
     return true;
 }
 
@@ -1075,22 +1102,19 @@ bool s_callback_verificator(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_t *a_c
  * @param a_tx_item_idx
  * @return
  */
-bool	s_callback_verificator_added(dap_ledger_t * a_ledger,dap_chain_datum_tx_t* a_tx, dap_chain_tx_out_cond_t *a_tx_item)
+static bool s_stake_lock_callback_verificator_added(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_tx_out_cond_t *a_tx_item)
 {
-    dap_chain_hash_fast_t* l_key_hash = DAP_NEW_Z(dap_chain_hash_fast_t);
-    if (!l_key_hash)
-        return false;
-    size_t l_tx_size = dap_chain_datum_tx_get_size(a_tx);
-    dap_hash_fast(a_tx, l_tx_size, l_key_hash);
-    if (dap_hash_fast_is_blank(l_key_hash)) {
-        DAP_DEL_Z(l_key_hash);
-        return false;
+    if (a_tx_item)  // this is IN_COND tx
+        return true;
+    int l_out_num = 0;
+    dap_chain_tx_out_cond_t *l_cond = dap_chain_datum_tx_out_cond_get(a_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK, &l_out_num);
+    if (l_cond->subtype.srv_stake_lock.flags & DAP_CHAIN_NET_SRV_STAKE_LOCK_FLAG_CREATE_BASE_TX) {
+        dap_chain_hash_fast_t l_key_hash;
+        dap_hash_fast( a_tx, dap_chain_datum_tx_get_size(a_tx), &l_key_hash);
+        if (dap_hash_fast_is_blank(&l_key_hash))
+            return false;
+        dap_chain_ledger_emission_for_stake_lock_item_add(a_ledger, &l_key_hash);
     }
-
-    s_emission_for_stake_lock_item_add(a_ledger, l_key_hash);
-
-    DAP_DEL_Z(l_key_hash);
-
     return true;
 }
 
@@ -1106,15 +1130,16 @@ bool	s_callback_verificator_added(dap_ledger_t * a_ledger,dap_chain_datum_tx_t*
  * @param a_count_months
  * @return
  */
-static dap_chain_datum_t* s_mempool_create(dap_chain_net_t* a_net,
-    dap_enc_key_t* a_key_from, dap_pkey_t* a_key_cond,
-    const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
-    uint256_t a_value, dap_chain_net_srv_uid_t a_srv_uid,
-    dap_chain_addr_t* a_addr_holder, dap_time_t a_time_staking, uint8_t reinvest)
+static dap_chain_datum_t* s_mempool_create(dap_chain_net_t *a_net,
+                                                   dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond,
+                                                   const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
+                                                   uint256_t a_value, dap_chain_net_srv_uid_t a_srv_uid,
+                                                   dap_chain_addr_t *a_addr_holder, dap_time_t a_time_staking,
+                                                   uint256_t a_reinvest_percent, bool create_base_tx)
 {
-    dap_ledger_t* l_ledger = a_net ? dap_chain_ledger_by_net_name(a_net->pub.name) : NULL;
+    dap_ledger_t * l_ledger = a_net ? dap_chain_ledger_by_net_name( a_net->pub.name ) : NULL;
     // check valid param
-    if (!a_net || !l_ledger || !a_key_from || !a_key_cond ||
+    if (!a_net || !l_ledger || !a_key_from ||
         !a_key_from->priv_key_data || !a_key_from->priv_key_data_size || IS_ZERO_256(a_value))
         return NULL;
 
@@ -1126,15 +1151,15 @@ static dap_chain_datum_t* s_mempool_create(dap_chain_net_t* a_net,
     dap_chain_addr_t l_addr_from;
     dap_chain_addr_fill_from_key(&l_addr_from, a_key_from, a_net->pub.id);
     // list of transaction with 'out' items
-    dap_list_t* l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(l_ledger, a_token_ticker,
-        &l_addr_from, a_value, &l_value_transfer);
-    if (!l_list_used_out) {
-        log_it(L_ERROR, "Nothing to tranfer (not enough funds)");
+    dap_list_t *l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(l_ledger, a_token_ticker,
+                                                                             &l_addr_from, a_value, &l_value_transfer);
+    if(!l_list_used_out) {
+        log_it( L_ERROR, "Nothing to tranfer (not enough funds)");
         return NULL;
     }
 
     // create empty transaction
-    dap_chain_datum_tx_t* l_tx = dap_chain_datum_tx_create();
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
     // add 'in' items
     {
         uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
@@ -1144,37 +1169,37 @@ static dap_chain_datum_t* s_mempool_create(dap_chain_net_t* a_net,
     // add 'out_cond' and 'out' items
     {
         uint256_t l_value_pack = {}; // how much coin add to 'out' items
-        dap_chain_tx_out_cond_t* l_tx_out_cond = dap_chain_net_srv_stake_lock_create_cond_out(a_key_cond, a_srv_uid, a_value, a_time_staking, reinvest);
-        if (l_tx_out_cond) {
+        dap_chain_tx_out_cond_t* l_tx_out_cond = dap_chain_net_srv_stake_lock_create_cond_out(a_key_cond, a_srv_uid, a_value, a_time_staking, a_reinvest_percent, create_base_tx);
+        if(l_tx_out_cond) {
             SUM_256_256(l_value_pack, a_value, &l_value_pack);
-            dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*)l_tx_out_cond);
-            //			DAP_DEL_Z(l_tx_out_cond);
-                        // transaction fee
-            //			if (!IS_ZERO_256(a_value_fee)) {
-                            // TODO add condition with fee for mempool-as-service
-            //			}
+            dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out_cond);
+//			DAP_DEL_Z(l_tx_out_cond);
+            // transaction fee
+//			if (!IS_ZERO_256(a_value_fee)) {
+                // TODO add condition with fee for mempool-as-service
+//			}
         }//TODO: else return false;
         // coin back
         uint256_t l_value_back = {};
         SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
         if (!IS_ZERO_256(l_value_back)) {
-            if (dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_from, l_value_back) != 1) {
+            if(dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_from, l_value_back) != 1) {
                 dap_chain_datum_tx_delete(l_tx);
-                log_it(L_ERROR, "Cant add coin back output");
+                log_it( L_ERROR, "Cant add coin back output");
                 return NULL;
             }
         }
     }
 
     // add 'sign' items
-    if (dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from) != 1) {
+    if(dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from) != 1) {
         dap_chain_datum_tx_delete(l_tx);
-        log_it(L_ERROR, "Can't add sign output");
+        log_it( L_ERROR, "Can't add sign output");
         return NULL;
     }
 
-    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);
+    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 );
 
     return l_datum;
 }
@@ -1188,25 +1213,27 @@ static dap_chain_datum_t* s_mempool_create(dap_chain_net_t* a_net,
  * @param token
  * @return
  */
-dap_chain_tx_out_cond_t* dap_chain_net_srv_stake_lock_create_cond_out(dap_pkey_t* a_key, dap_chain_net_srv_uid_t a_srv_uid, uint256_t a_value,
-    uint64_t a_time_staking, uint8_t reinvest)
+dap_chain_tx_out_cond_t *dap_chain_net_srv_stake_lock_create_cond_out(dap_pkey_t *a_key, dap_chain_net_srv_uid_t a_srv_uid,
+                                                                      uint256_t a_value, uint64_t a_time_staking,
+                                                                      uint256_t a_reinvest_percent, bool create_base_tx)
 {
     if (IS_ZERO_256(a_value))
         return NULL;
-    dap_chain_tx_out_cond_t* l_item = DAP_NEW_Z_SIZE(dap_chain_tx_out_cond_t, sizeof(dap_chain_tx_out_cond_t) + sizeof(cond_params_t));
+    dap_chain_tx_out_cond_t *l_item = DAP_NEW_Z(dap_chain_tx_out_cond_t);
     l_item->header.item_type = TX_ITEM_TYPE_OUT_COND;
     l_item->header.value = a_value;
     l_item->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK;
     l_item->header.srv_uid = a_srv_uid;
-    l_item->params_size = sizeof(cond_params_t);
-    cond_params_t* l_params = (cond_params_t*)l_item->params;
-    l_params->reinvest = reinvest;
+    l_item->subtype.srv_stake_lock.reinvest_percent = a_reinvest_percent;
     if (a_time_staking) {
-        l_params->time_unlock = dap_time_now() + a_time_staking;
-        l_params->flags |= DAP_CHAIN_NET_SRV_STAKE_LOCK_FLAG_BY_TIME;
+//		l_item->header.ts_expires = dap_time_now() + a_time_staking;
+        l_item->subtype.srv_stake_lock.time_unlock = dap_time_now() + a_time_staking;
+        l_item->subtype.srv_stake_lock.flags |= DAP_CHAIN_NET_SRV_STAKE_LOCK_FLAG_BY_TIME;
     }
+    if (create_base_tx)
+        l_item->subtype.srv_stake_lock.flags |= DAP_CHAIN_NET_SRV_STAKE_LOCK_FLAG_CREATE_BASE_TX;
     if (a_key)
-        dap_hash_fast(a_key->pkey, a_key->header.size, &l_params->pkey_delegated);
+        dap_hash_fast(a_key->pkey, a_key->header.size, &l_item->subtype.srv_stake_lock.pkey_delegated);
 
     return l_item;
 }
@@ -1224,31 +1251,33 @@ dap_chain_tx_out_cond_t* dap_chain_net_srv_stake_lock_create_cond_out(dap_pkey_t
  * @param a_time_staking
  * @return
  */
-dap_chain_hash_fast_t* dap_chain_net_srv_stake_lock_mempool_create(dap_chain_net_t* a_net,
-    dap_enc_key_t* a_key_from, dap_pkey_t* a_key_cond,
-    const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
-    uint256_t a_value, dap_chain_net_srv_uid_t a_srv_uid,
-    dap_chain_addr_t* a_addr_holder, uint64_t a_time_staking, uint8_t reinvest)
+dap_chain_hash_fast_t* dap_chain_net_srv_stake_lock_mempool_create(dap_chain_net_t *a_net,
+                                                                       dap_enc_key_t *a_key_from, dap_pkey_t *a_key_cond,
+                                                                       const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
+                                                                       uint256_t a_value, dap_chain_net_srv_uid_t a_srv_uid,
+                                                                       dap_chain_addr_t *a_addr_holder, dap_chain_t *a_chain,
+                                                                       uint64_t a_time_staking, uint256_t a_reinvest_percent,
+                                                                       bool create_base_tx)
 {
     // Make transfer transaction
-    dap_chain_datum_t* l_datum = s_mempool_create(a_net, a_key_from, a_key_cond, a_token_ticker, a_value, a_srv_uid,
-        a_addr_holder, a_time_staking, reinvest);
+    dap_chain_datum_t *l_datum = s_mempool_create(a_net, a_key_from, a_key_cond, a_token_ticker, a_value, a_srv_uid,
+                                                  a_addr_holder, a_time_staking, a_reinvest_percent, create_base_tx);
 
-    if (!l_datum)
+    if(!l_datum)
         return NULL;
 
-    dap_chain_datum_tx_t* l_tx = (dap_chain_datum_tx_t*)&(l_datum->data);
+    dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t*)&(l_datum->data);
     size_t l_tx_size = l_datum->header.data_size;
 
-    dap_chain_hash_fast_t* l_key_hash = DAP_NEW_Z(dap_chain_hash_fast_t);
-    dap_hash_fast(l_tx, l_tx_size, l_key_hash);
+    dap_chain_hash_fast_t *l_key_hash = DAP_NEW_Z( dap_chain_hash_fast_t );
+    dap_hash_fast( l_tx, l_tx_size, l_key_hash);
 
-    char* l_key_str = dap_chain_hash_fast_to_str_new(l_key_hash);
-    char* l_gdb_group = dap_chain_net_get_gdb_group_mempool_by_chain_type(a_net, CHAIN_TYPE_TX);
+    char * l_key_str = dap_chain_hash_fast_to_str_new( l_key_hash );
+    char * l_gdb_group = dap_chain_net_get_gdb_group_mempool_new(a_chain);
 
-    if (dap_global_db_set(l_gdb_group, l_key_str, l_datum, dap_chain_datum_size(l_datum), false, NULL, NULL) == true) {
+    if (dap_global_db_set_sync(l_gdb_group, l_key_str, l_datum, dap_chain_datum_size(l_datum), false) ==
+            DAP_GLOBAL_DB_RC_SUCCESS)
         log_it(L_NOTICE, "Transaction %s placed in mempool group %s", l_key_str, l_gdb_group);
-    }
 
     DAP_DELETE(l_gdb_group);
     DAP_DELETE(l_key_str);
@@ -1256,26 +1285,26 @@ dap_chain_hash_fast_t* dap_chain_net_srv_stake_lock_mempool_create(dap_chain_net
     return l_key_hash;
 }
 
-dap_chain_datum_t* dap_chain_burning_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 char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
-    uint256_t a_value)
+dap_chain_datum_t *dap_chain_burning_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 char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
+                                             uint256_t a_value)
 {
     // check valid param
-    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) || (a_addr_to && !dap_chain_addr_check_sum(a_addr_to)) || IS_ZERO_256(a_value))
+    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) || (a_addr_to && !dap_chain_addr_check_sum(a_addr_to)) || IS_ZERO_256(a_value))
         return NULL;
 
     // find the transactions from which to take away coins
     uint256_t l_value_transfer = {}; // how many coins to transfer
-    dap_list_t* l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(a_chain->ledger, a_token_ticker,
-        a_addr_from, a_value, &l_value_transfer);
+    dap_list_t *l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(a_chain->ledger, a_token_ticker,
+                                                                             a_addr_from, a_value, &l_value_transfer);
     if (!l_list_used_out) {
-        log_it(L_WARNING, "Not enough funds to transfer");
+        log_it(L_WARNING,"Not enough funds to transfer");
         return NULL;
     }
     // create empty transaction
-    dap_chain_datum_tx_t* l_tx = dap_chain_datum_tx_create();
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
     // add 'in' items
     {
         uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
@@ -1285,14 +1314,14 @@ dap_chain_datum_t* dap_chain_burning_tx_create(dap_chain_t* a_chain, dap_enc_key
     // add 'out' items
     {
         uint256_t l_value_pack = {}; // how much datoshi add to 'out' items
-        if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to, a_value) == 1) {
+        if(dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to, a_value) == 1) {
             SUM_256_256(l_value_pack, a_value, &l_value_pack);
         }
         // coin back
         uint256_t l_value_back;
         SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back);
-        if (!IS_ZERO_256(l_value_back)) {
-            if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_from, l_value_back) != 1) {
+        if(!IS_ZERO_256(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 NULL;
             }
@@ -1300,30 +1329,84 @@ dap_chain_datum_t* dap_chain_burning_tx_create(dap_chain_t* a_chain, dap_enc_key
     }
 
     // add 'sign' items
-    if (dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from) != 1) {
+    if(dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from) != 1) {
         dap_chain_datum_tx_delete(l_tx);
         return NULL;
     }
 
     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_chain_datum_t *l_datum = dap_chain_datum_create(DAP_CHAIN_DATUM_TX, l_tx, l_tx_size);
 
     DAP_DELETE(l_tx);
 
     return l_datum;
 
-    //	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);
-    //	char *l_hash_str = dap_chain_mempool_datum_add(l_datum, a_chain);
-
-    //	DAP_DELETE( l_datum );
-    //
-    //	if (l_hash_str) {
-    //		DAP_DELETE(l_hash_str);
-    //		return l_ret;
-    //	}else{
-    //		DAP_DELETE(l_ret);
-    //		return NULL;
-    //	}
+//	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);
+//	char *l_hash_str = dap_chain_mempool_datum_add(l_datum, a_chain);
+
+//	DAP_DELETE( l_datum );
+//
+//	if (l_hash_str) {
+//		DAP_DELETE(l_hash_str);
+//		return l_ret;
+//	}else{
+//		DAP_DELETE(l_ret);
+//		return NULL;
+//	}
+}
+
+static dap_chain_hash_fast_t *dap_chain_mempool_base_tx_for_stake_lock_create(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_emission_hash,
+                                                        dap_chain_id_t a_emission_chain_id, uint256_t a_emission_value, const char *a_ticker,
+                                                        dap_chain_addr_t *a_addr_to, dap_enc_key_t *a_key_from)
+{
+    char *l_gdb_group_mempool_base_tx = dap_chain_net_get_gdb_group_mempool_new(a_chain);
+    // create first transaction (with tx_token)
+    dap_chain_datum_tx_t *l_tx = DAP_NEW_Z_SIZE(dap_chain_datum_tx_t, sizeof(dap_chain_datum_tx_t));
+    l_tx->header.ts_created = time(NULL);
+    dap_chain_hash_fast_t l_tx_prev_hash = { 0 };
+    // create items
+
+    dap_chain_tx_token_t *l_tx_token = dap_chain_datum_tx_item_token_create(a_emission_chain_id, a_emission_hash, a_ticker);
+    dap_chain_tx_in_t *l_in = dap_chain_datum_tx_item_in_create(&l_tx_prev_hash, 0);
+    dap_chain_tx_out_t *l_out = dap_chain_datum_tx_item_out_create(a_addr_to, a_emission_value);
+
+    // pack items to transaction
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_tx_token);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out);
+
+    if (a_key_from) {
+        if(dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from) < 0) {
+            log_it(L_WARNING, "Private key not valid");
+            return NULL;
+        }
+    } else {
+        log_it(L_WARNING, "No private key for base TX!");
+        return NULL;
+    }
+
+    DAP_DEL_Z(l_tx_token);
+    DAP_DEL_Z(l_in);
+    DAP_DEL_Z(l_out);
+
+    size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx);
+
+    // Pack transaction into the datum
+    dap_chain_datum_t * l_datum_tx = dap_chain_datum_create(DAP_CHAIN_DATUM_TX, l_tx, l_tx_size);
+    size_t l_datum_tx_size = dap_chain_datum_size(l_datum_tx);
+    DAP_DEL_Z(l_tx);
+    // calc datum hash
+    dap_chain_hash_fast_t *l_datum_tx_hash = DAP_NEW(dap_hash_fast_t);
+    dap_hash_fast(l_datum_tx, l_datum_tx_size, l_datum_tx_hash);
+    char *l_tx_hash_str = dap_chain_hash_fast_to_str_new(l_datum_tx_hash);
+    // Add to mempool tx token
+    bool l_placed = dap_global_db_set_sync(l_gdb_group_mempool_base_tx, l_tx_hash_str, l_datum_tx,
+                                           l_datum_tx_size, false) == DAP_GLOBAL_DB_RC_SUCCESS;
+    DAP_DEL_Z(l_tx_hash_str);
+    DAP_DELETE(l_datum_tx);
+    if (!l_placed)
+        return NULL;
+    return l_datum_tx_hash;
 }
diff --git a/modules/service/stake_lock/include/dap_chain_net_srv_stake_lock.h b/modules/service/stake_lock/include/dap_chain_net_srv_stake_lock.h
index 6018736c6dea95a89ea3b9f8d836a27a5cc7cb74..b7fbb5d2523fcf7089943d260a6a03a93829e986 100644
--- a/modules/service/stake_lock/include/dap_chain_net_srv_stake_lock.h
+++ b/modules/service/stake_lock/include/dap_chain_net_srv_stake_lock.h
@@ -39,27 +39,31 @@
 #define DAP_CHAIN_NET_SRV_STAKE_LOCK_FLAG_DELEGATE_PKEY            0x00000004
 // Lock by time
 #define DAP_CHAIN_NET_SRV_STAKE_LOCK_FLAG_BY_TIME                  0x00000008
+// Create base tx for delegated token
+#define DAP_CHAIN_NET_SRV_STAKE_LOCK_FLAG_CREATE_BASE_TX           0x00000010
+
+/**
+ * @brief The cond_params struct thats placed in tx_cond->params[] section
+ */
 
 
 int 					dap_chain_net_srv_stake_lock_init(void);
 void					dap_chain_net_srv_stake_lock_deinit(void);
-bool					s_callback_verificator(dap_ledger_t *a_ledger,dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner);
-bool					s_callback_verificator_added(dap_ledger_t *a_ledger,dap_chain_datum_tx_t * a_tx, dap_chain_tx_out_cond_t *a_tx_item);
-
 
 // Create cond out
-dap_chain_tx_out_cond_t	*dap_chain_net_srv_stake_lock_create_cond_out(dap_pkey_t *a_key, dap_chain_net_srv_uid_t a_srv_uid, uint256_t a_value,
-    uint64_t a_time_staking, uint8_t reinvest);
-
+dap_chain_tx_out_cond_t	*dap_chain_net_srv_stake_lock_create_cond_out(dap_pkey_t *a_key, dap_chain_net_srv_uid_t a_srv_uid,
+                                                                      uint256_t a_value, uint64_t a_time_staking,
+                                                                      uint256_t a_reinvest_percent, bool create_base_tx);
 // Create mempool
 dap_chain_hash_fast_t	*dap_chain_net_srv_stake_lock_mempool_create(dap_chain_net_t *a_net,
-    dap_enc_key_t* a_key_from, dap_pkey_t* a_key_cond,
-    const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
-    uint256_t a_value, dap_chain_net_srv_uid_t a_srv_uid,
-    dap_chain_addr_t* a_addr_holder, uint64_t a_time_staking, uint8_t reinvest);
-
+                                                                     dap_enc_key_t* a_key_from, dap_pkey_t* a_key_cond,
+                                                                     const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
+                                                                     uint256_t a_value, dap_chain_net_srv_uid_t a_srv_uid,
+                                                                     dap_chain_addr_t *a_addr_holder, dap_chain_t *a_chain,
+                                                                     uint64_t a_time_staking, uint256_t a_reinvest_percent,
+                                                                     bool create_base_tx);
 // Burning_tx_create
 dap_chain_datum_t*      dap_chain_burning_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 char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
-    uint256_t a_value);
+                                                    const dap_chain_addr_t* a_addr_from, const dap_chain_addr_t* a_addr_to,
+                                                    const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
+                                                    uint256_t a_value);
diff --git a/modules/service/stake_pos_delegate/dap_chain_net_srv_stake_pos_delegate.c b/modules/service/stake_pos_delegate/dap_chain_net_srv_stake_pos_delegate.c
index 3eb577a03dc3a3c5c9ebe7b20fe37a8070a252f5..18ff05af79b5d2433869212417d365d58ebc8dcb 100644
--- a/modules/service/stake_pos_delegate/dap_chain_net_srv_stake_pos_delegate.c
+++ b/modules/service/stake_pos_delegate/dap_chain_net_srv_stake_pos_delegate.c
@@ -41,6 +41,9 @@ static int s_callback_requested(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id,
 static int s_callback_response_success(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_remote_t *a_srv_client, const void *a_data, size_t a_data_size);
 static int s_callback_response_error(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_remote_t *a_srv_client, const void *a_data, size_t a_data_size);
 static int s_callback_receipt_next_success(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_remote_t *a_srv_client, const void *a_data, size_t a_data_size);
+static bool s_verificator_stake_callback(dap_ledger_t * a_ledger,dap_hash_fast_t *a_tx_out_hash, dap_chain_tx_out_cond_t *a_cond,
+                                                      dap_chain_datum_tx_t *a_tx_in, bool a_owner);
+static bool s_verificator_stake_updater_callback(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_tx_out_cond_t *a_cond);
 
 static dap_chain_net_srv_stake_t *s_srv_stake = NULL;
 
@@ -52,6 +55,7 @@ static dap_chain_net_srv_stake_t *s_srv_stake = NULL;
  */
 int dap_chain_net_srv_stake_pos_delegate_init()
 {
+    dap_chain_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, s_verificator_stake_callback, s_verificator_stake_updater_callback);
     dap_cli_server_cmd_add("srv_stake", s_cli_srv_stake, "Delegated stake service commands",
     "srv_stake order create -net <net_name> -addr_hldr <addr> -token <token_ticker> -coins <value> -cert <priv_cert_name> -fee_percent <value>\n"
         "\tCreate a new order with specified amount of datoshi to delegate specified cert from the specified address.\n"
@@ -105,7 +109,8 @@ int dap_chain_net_srv_stake_pos_delegate_init()
         }
         // Find all stake transactions
         do {
-            l_tx_tmp = dap_chain_ledger_tx_cache_find_out_cond(l_ledger, &l_tx_cur_hash, &l_out_cond, &l_out_cond_idx, l_token);
+            l_tx_tmp = dap_chain_ledger_tx_cache_find_out_cond(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE,
+                                                               &l_tx_cur_hash, &l_out_cond, &l_out_cond_idx, l_token);
             if (!l_tx_tmp) {
                 break;
             }
@@ -215,8 +220,9 @@ static bool s_stake_conditions_calc(dap_chain_tx_out_cond_t *a_cond, dap_chain_d
 {
     dap_chain_tx_out_cond_t *l_out_cond = NULL;
     if (!a_cond) {
+        int l_out_num = 0;
         // New stake tx
-        l_out_cond = (dap_chain_tx_out_cond_t *)dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_OUT_COND, NULL);
+        l_out_cond = dap_chain_datum_tx_out_cond_get(a_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK, &l_out_num);
     } else
         l_out_cond = a_cond;
     dap_chain_net_id_t l_cur_net_id = l_out_cond->subtype.srv_stake.hldr_addr.net_id;
@@ -254,22 +260,6 @@ static bool s_stake_conditions_calc(dap_chain_tx_out_cond_t *a_cond, dap_chain_d
     return false;
 }
 
-bool dap_chain_net_srv_stake_pos_delegate_verificator(dap_ledger_t* a_ledger, dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner)
-{
-    if (!s_srv_stake) {
-        return false;
-    }
-    return s_stake_conditions_calc(a_cond, a_tx, a_owner, false);
-}
-
-bool dap_chain_net_srv_stake_updater(dap_ledger_t* a_ledger, dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner)
-{
-    if (!s_srv_stake) {
-        return false;
-    }
-    return s_stake_conditions_calc(a_cond, a_tx, a_owner, true);
-}
-
 bool dap_chain_net_srv_stake_key_delegated(dap_chain_addr_t *a_addr)
 {
     if (!s_srv_stake) {
@@ -358,11 +348,11 @@ bool dap_chain_net_srv_stake_validator(dap_chain_addr_t *a_addr, dap_chain_datum
     }
     dap_list_free(l_list_out_items);
     uint256_t l_fee = uint256_0; // TODO replace with fractional mult MULT_256_FRAC_FRAC(l_outs_sum, l_stake->fee_value / 100.0); +++
-	DIV_256(l_stake->fee_value, dap_chain_coins_to_balance("100.0"), &l_fee);
-	if (MULT_256_COIN(l_outs_sum, l_fee, &l_fee)) {
-		log_it(L_WARNING, "DANGER: MULT_256_COIN overflow! in dap_chain_net_srv_stake_validator()");
-		l_fee = uint256_0;
-	}
+    DIV_256(l_stake->fee_value, dap_chain_coins_to_balance("100.0"), &l_fee);
+    if (MULT_256_COIN(l_outs_sum, l_fee, &l_fee)) {
+        log_it(L_WARNING, "DANGER: MULT_256_COIN overflow! in dap_chain_net_srv_stake_validator()");
+        l_fee = uint256_0;
+    }
     if (compare256(l_fee_sum, l_fee) == -1) {
         return false;
     }
@@ -487,7 +477,8 @@ static dap_chain_datum_tx_t *s_stake_tx_approve(dap_chain_net_srv_stake_item_t *
         return NULL;
     }
     int l_prev_cond_idx = 0;
-    dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_cond_tx, &l_prev_cond_idx);
+    dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_cond_tx,
+                                                  DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_prev_cond_idx);
     if (dap_chain_ledger_tx_hash_is_used_out_item(l_ledger, &a_stake->tx_hash, l_prev_cond_idx)) {
         log_it(L_WARNING, "Requested conditional transaction is already used out");
         return NULL;
@@ -540,9 +531,10 @@ static bool s_stake_tx_invalidate(dap_chain_net_srv_stake_item_t *a_stake, dap_c
     if (!l_cond_tx) {
         log_it(L_WARNING, "Requested conditional transaction not found");
         return false;
-    }   
+    }
     int l_prev_cond_idx = 0;
-    dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_cond_tx, &l_prev_cond_idx);
+    dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_cond_tx,
+                                                DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_prev_cond_idx);
     if (dap_chain_ledger_tx_hash_is_used_out_item(l_ledger, &a_stake->tx_hash, l_prev_cond_idx)) {
         log_it(L_WARNING, "Requested conditional transaction is already used out");
         return false;
@@ -600,11 +592,10 @@ dap_chain_net_srv_stake_item_t *s_stake_item_from_order(dap_chain_net_t *a_net,
     }
     dap_srv_stake_order_ext_t *l_ext = (dap_srv_stake_order_ext_t *)a_order->ext_n_sign;
     dap_sign_t *l_sign = (dap_sign_t *)(a_order->ext_n_sign + a_order->ext_size);
-    if (!dap_sign_verify_size(l_sign, dap_chain_net_srv_order_get_size(a_order)) ||
-            dap_sign_verify(l_sign, a_order, sizeof(dap_chain_net_srv_order_t) + a_order->ext_size) != 1) {
+    if (dap_sign_verify(l_sign, a_order, sizeof(dap_chain_net_srv_order_t) + a_order->ext_size) != 1) {
         log_it(L_WARNING, "Order sign is invalid");
         return NULL;
-    }
+    } /* no need to check size here */
     dap_hash_fast_t l_pkey_hash;
     dap_sign_get_pkey_hash(l_sign, &l_pkey_hash);
     dap_chain_addr_t l_cert_addr;
@@ -629,15 +620,6 @@ dap_chain_net_srv_stake_item_t *s_stake_item_from_order(dap_chain_net_t *a_net,
     return l_item;
 }
 
-// Ledger verificator for DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STAKE
-bool dap_chain_net_srv_fee_stake_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner)
-{
-    if (!s_srv_stake) {
-        return false;
-    }
-    return false;
-}
-
 static bool s_stake_block_commit(dap_chain_net_t *a_net, dap_list_t *a_tx_hash_list)
 {
     size_t l_all_tx = 0, l_process_tx = 0;
@@ -674,16 +656,11 @@ static bool s_stake_block_commit(dap_chain_net_t *a_net, dap_list_t *a_tx_hash_l
             a_tx_hash_list = dap_list_next(a_tx_hash_list);
             continue;
         }
-        // Get cond out with type=DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STAKE within tx
+        // Get cond out with type=DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STAKE within tx ???
         dap_chain_tx_out_cond_t *l_tx_out_cond = NULL;
         int l_prev_cond_idx = 0;
-        do {
-            l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_tx_with_cond, &l_prev_cond_idx);
-            if(l_tx_out_cond && l_tx_out_cond->header.subtype==DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STAKE) {
-                break;
-            }
-        }
-        while(l_tx_out_cond);
+        l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_tx_with_cond,
+                                                        DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, &l_prev_cond_idx);
 
         if(!l_tx_out_cond) {
             // go to the next tx
@@ -1281,7 +1258,7 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply)
                 dap_chain_datum_tx_t *l_tx = s_stake_tx_create(l_stake, l_wallet);
                 dap_chain_wallet_close(l_wallet);
                 if (l_tx && s_stake_tx_put(l_tx, l_net)) {
-                    dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_stake->tx_hash);         
+                    dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_stake->tx_hash);
                     // TODO send a notification to order owner to delete it
                     dap_chain_net_srv_order_delete_by_hash_str_sync(l_net, l_order_hash_str);
                 }
@@ -1494,22 +1471,31 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply)
     return 0;
 }
 
-static int s_callback_requested(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_remote_t *a_srv_client, const void *a_data, size_t a_data_size)
-{
-    return 0;
-}
-
-static int s_callback_response_success(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_remote_t *a_srv_client, const void *a_data, size_t a_data_size)
-{
-    return 0;
-}
-
-static int s_callback_response_error(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_remote_t *a_srv_client, const void *a_data, size_t a_data_size)
+static bool s_verificator_stake_callback(dap_ledger_t * a_ledger, dap_hash_fast_t *a_tx_out_hash, dap_chain_tx_out_cond_t *a_cond,
+                                                      dap_chain_datum_tx_t *a_tx_in, bool a_owner)
 {
-    return 0;
+    UNUSED(a_ledger);
+    UNUSED(a_tx_out_hash);
+    if (!s_srv_stake) {
+        return false;
+    }
+    return s_stake_conditions_calc(a_cond, a_tx_in, a_owner, false);
 }
 
-static int s_callback_receipt_next_success(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_remote_t *a_srv_client, const void *a_data, size_t a_data_size)
+/**
+ * @brief s_verificator_stake_updater_callback
+ * @param a_ledger
+ * @param a_tx_out
+ * @param a_cond
+ * @param a_tx_in
+ * @param a_owner
+ * @return
+ */
+static bool s_verificator_stake_updater_callback(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_tx_out_cond_t *a_cond)
 {
-    return 0;
+    UNUSED(a_ledger);
+    if (!s_srv_stake) {
+        return false;
+    }
+    return s_stake_conditions_calc(a_cond, a_tx, true, true);
 }
diff --git a/modules/service/stake_pos_delegate/include/dap_chain_net_srv_stake_pos_delegate.h b/modules/service/stake_pos_delegate/include/dap_chain_net_srv_stake_pos_delegate.h
index 69ecdce4f2980ef04e6c5230d9641e7c5a4ba040..5c1ebf6a8f9b33484e0c9b47a6218529ca05455c 100644
--- a/modules/service/stake_pos_delegate/include/dap_chain_net_srv_stake_pos_delegate.h
+++ b/modules/service/stake_pos_delegate/include/dap_chain_net_srv_stake_pos_delegate.h
@@ -57,11 +57,6 @@ typedef struct dap_chain_net_srv_stake {
 
 int dap_chain_net_srv_stake_pos_delegate_init();
 void dap_chain_net_srv_stake_pos_delegate_deinit();
-bool dap_chain_net_srv_stake_pos_delegate_verificator(dap_ledger_t* a_ledger, dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner);
-bool dap_chain_net_srv_stake_updater(dap_ledger_t* a_ledger, dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner);
 bool dap_chain_net_srv_stake_validator(dap_chain_addr_t *a_addr, dap_chain_datum_t *a_datum);
 bool dap_chain_net_srv_stake_key_delegated(dap_chain_addr_t *a_addr);
 dap_list_t *dap_chain_net_srv_stake_get_validators();
-
-// Ledger verificator for DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STAKE
-bool dap_chain_net_srv_fee_stake_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner);
diff --git a/modules/service/vpn/dap_chain_net_vpn_client.c b/modules/service/vpn/dap_chain_net_vpn_client.c
index acc3710bb286e01d0637c45c97753086c8163abd..a6a3a14fb60101f8d6a95e4e41e20b8955a32435 100644
--- a/modules/service/vpn/dap_chain_net_vpn_client.c
+++ b/modules/service/vpn/dap_chain_net_vpn_client.c
@@ -58,6 +58,7 @@
 
 #include "dap_chain_common.h"
 #include "dap_chain_mempool.h"
+#include "dap_chain_net_tx.h"
 #include "dap_chain_node_cli.h"
 #include "dap_chain_node_client.h"
 #include "dap_chain_net_srv_order.h"
@@ -528,7 +529,7 @@ int dap_chain_net_vpn_client_check(dap_chain_net_t *a_net, const char *a_ipv4_st
     if(l_res) {
         log_it(L_ERROR, "No response from VPN server=%s:%d", a_ipv4_str, a_port);
         // clean client struct
-        dap_chain_node_client_close(s_vpn_client);
+        dap_chain_node_client_close(s_vpn_client->uuid);
         DAP_DELETE(s_node_info);
         s_node_info = NULL;
         return -3;
@@ -574,7 +575,7 @@ int dap_chain_net_vpn_client_check(dap_chain_net_t *a_net, const char *a_ipv4_st
         log_it(L_NOTICE, "Got response from VPN server=%s:%d", a_ipv4_str, a_port);
     }
     // clean client struct
-    dap_chain_node_client_close(s_vpn_client);
+    dap_chain_node_client_close(s_vpn_client->uuid);
     DAP_DELETE(s_node_info);
     s_node_info = NULL;
     if(l_res)
@@ -607,7 +608,7 @@ int dap_chain_net_vpn_client_start(dap_chain_net_t *a_net, const char *a_ipv4_st
     if(!s_vpn_client) {
         log_it(L_ERROR, "Can't connect to VPN server=%s:%d", a_ipv4_str, a_port);
         // clean client struct
-        dap_chain_node_client_close(s_vpn_client);
+        dap_chain_node_client_close(s_vpn_client->uuid);
         DAP_DELETE(s_node_info);
         s_node_info = NULL;
         return -2;
@@ -618,7 +619,7 @@ int dap_chain_net_vpn_client_start(dap_chain_net_t *a_net, const char *a_ipv4_st
     if(res) {
         log_it(L_ERROR, "No response from VPN server=%s:%d", a_ipv4_str, a_port);
         // clean client struct
-        dap_chain_node_client_close(s_vpn_client);
+        dap_chain_node_client_close(s_vpn_client->uuid);
         DAP_DELETE(s_node_info);
         s_node_info = NULL;
         return -3;
@@ -657,7 +658,7 @@ int dap_chain_net_vpn_client_stop(void)
 {
     // delete connection with VPN server
     if(s_vpn_client) {
-        dap_chain_node_client_close(s_vpn_client);
+        dap_chain_node_client_close(s_vpn_client->uuid);
         s_vpn_client = NULL;
     }
     DAP_DELETE(s_node_info);
diff --git a/modules/service/xchange/dap_chain_net_srv_xchange.c b/modules/service/xchange/dap_chain_net_srv_xchange.c
index e42b695dc2f4c5970049f73b2c415a8122a19746..52377773602666bf435c71b10b6090f236106dba 100644
--- a/modules/service/xchange/dap_chain_net_srv_xchange.c
+++ b/modules/service/xchange/dap_chain_net_srv_xchange.c
@@ -24,8 +24,13 @@
 
 #include <math.h>
 #include <pthread.h>
+#include <stdbool.h>
 #include "dap_chain_net.h"
 #include "dap_chain_datum_tx.h"
+#include "dap_chain_datum_tx_out_cond.h"
+#include "dap_chain_datum_tx_sig.h"
+#include "dap_list.h"
+#include "dap_sign.h"
 #include "dap_time.h"
 #include "dap_chain_net_srv.h"
 #include "dap_chain_ledger.h"
@@ -38,35 +43,19 @@
 #include "dap_chain_mempool.h"
 #include "dap_chain_datum_decree.h"
 #include "dap_tsd.h"
+#include "dap_chain_net_tx.h"
 #include "dap_chain_net_srv.h"
 #include "dap_chain_net_srv_xchange.h"
 #include "uthash.h"
 
 #define LOG_TAG "dap_chain_net_srv_xchange"
 
-//
-enum tsd_type{
-    TSD_FEE_PERCENT = 0x0001,
-    TSD_FEE_FIXED = 0x0002,
-    TSD_FEE_ADDR = 0x0003,
-};
-
-struct net_fee
-{
-    dap_chain_net_id_t net_id;
-
-    // Network fee
-    uint256_t fee_percents;
-    uint256_t fee_fixed;
-    dap_chain_addr_t fee_addr; // Addr collector
-
-    UT_hash_handle hh;
-} *s_net_fees = NULL; // Governance statements for networks
-pthread_rwlock_t s_net_fees_rwlock = PTHREAD_RWLOCK_INITIALIZER;
+static dap_chain_net_srv_fee_item_t *s_service_fees = NULL; // Governance statements for networks
+static pthread_rwlock_t s_service_fees_rwlock = PTHREAD_RWLOCK_INITIALIZER;
 
 static void s_callback_decree (dap_chain_net_srv_t * a_srv, dap_chain_net_t *a_net, dap_chain_t * a_chain, dap_chain_datum_decree_t * a_decree, size_t a_decree_size);
-
-
+static bool s_xchange_verificator_callback(dap_ledger_t * a_ledger,dap_hash_fast_t *a_tx_out_hash,  dap_chain_tx_out_cond_t *a_cond,
+                            dap_chain_datum_tx_t *a_tx_in, bool a_owner);
 const dap_chain_net_srv_uid_t c_dap_chain_net_srv_xchange_uid = {.uint64= DAP_CHAIN_NET_SRV_XCHANGE_ID};
 
 
@@ -75,14 +64,13 @@ static int s_callback_requested(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id,
 static int s_callback_response_success(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_remote_t *a_srv_client, const void *a_data, size_t a_data_size);
 static int s_callback_response_error(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_remote_t *a_srv_client, const void *a_data, size_t a_data_size);
 static int s_callback_receipt_next_success(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_remote_t *a_srv_client, const void *a_data, size_t a_data_size);
-static dap_chain_net_srv_xchange_price_t *s_xchange_db_load(char *a_key, uint8_t *a_item);
 
 static int s_tx_check_for_open_close(dap_chain_net_t * a_net, dap_chain_datum_tx_t * a_tx);
-static void s_string_append_tx_info( dap_string_t * a_reply_str, dap_chain_net_t * a_net, dap_chain_datum_tx_t * a_tx );
-
+static void s_string_append_tx_cond_info( dap_string_t * a_reply_str, dap_chain_net_t * a_net, dap_chain_datum_tx_t * a_tx );
+static bool s_srv_xchange_get_fee(dap_chain_net_id_t a_net_id, uint256_t *a_fee, dap_chain_addr_t *a_addr, uint16_t *a_type);
 
 static dap_chain_net_srv_xchange_t *s_srv_xchange;
-
+static bool s_debug_more = true;
 
 /**
  * @brief dap_stream_ch_vpn_init Init actions for VPN stream channel
@@ -92,17 +80,24 @@ static dap_chain_net_srv_xchange_t *s_srv_xchange;
  */
 int dap_chain_net_srv_xchange_init()
 {
+    dap_chain_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, s_xchange_verificator_callback, NULL);
     dap_cli_server_cmd_add("srv_xchange", s_cli_srv_xchange, "eXchange service commands",
 
-    "srv_xchange order create -net <net_name> -token_sell <token_ticker> -token_buy <token_ticker> -wallet <wallet_name> -coins <value> -rate <value>\n"
+    "srv_xchange order create -net <net_name> -token_sell <token_ticker> -token_buy <token_ticker> -wallet <wallet_name>"
+                                            " -coins <value> -rate <value> -fee <value>\n"
         "\tCreate a new order and tx with specified amount of datoshi to exchange with specified rate (buy / sell)\n"
     "srv_xchange order remove -net <net_name> -order <order_hash> -wallet <wallet_name>\n"
          "\tRemove order with specified order hash in specified net name\n"
     "srv_xchange order update -net <net_name> -order <order_hash> -wallet <wallet_name> [-token_sell <token_ticker>] "
                             "[-net_buy <net_name>] [-token_buy <token_ticker>] [-coins <value>] [-rate <value>]\n"
          "\tUpdate order with specified order hash in specified net name\n"
+    "srv_xchange order history -net <net_name> {-order <order_hash> | -addr <wallet_addr>}"
+         "\tShows transaction history for the selected order\n"
+    "srv_xchange order status -net <net_name> -order <order_hash>"
+         "\tShows current amount of unselled coins from the selected order and percentage of its completion\n"
     "srv_xchange orders -net <net_name>\n"
          "\tGet the exchange orders list within specified net name\n"
+
     "srv_xchange purchase -order <order hash> -net <net_name> -wallet <wallet_name> -coins <value>\n"
          "\tExchange tokens with specified order within specified net name. Specify how many datoshies to sell with rate specified by order\n"
 
@@ -112,14 +107,10 @@ int dap_chain_net_srv_xchange_init()
 
     "srv_xchange token_pair -net <net_name> list all\n"
         "\tList of all token pairs\n"
-
     "srv_xchange token_pair -net <net_name> price average -token_from <token_ticker> -token_to <token_ticker> [-time_from <From time>] [-time_to <To time>]  \n"
         "\tGet average rate for token pair <token from>:<token to> from <From time> to <To time> \n"
         "\tAll times are in RFC822\n"
-    "srv_xchange token_pair -net <net_name> price last -token_from <token_ticker> -token_to <token_ticker> [-time_from <From time>] [-time_to <To time>]  \n"
-        "\tGet average rate for token pair <token from>:<token to> from <From time> to <To time> \n"
-        "\tAll times are in RFC822\n"
-    "srv_xchange token_pair -net <net_name> price history -token_from <token_ticker> -token2 <token_ticker> [-time_from <From time>] [-time_to <To time>] \n"
+    "srv_xchange token_pair -net <net_name> price history -token_from <token_ticker> -token_to <token_ticker> [-time_from <From time>] [-time_to <To time>] \n"
         "\tPrint rate history for token pair <token from>:<token to> from <From time> to <To time>\n"
         "\tAll times are in RFC822\n"
 
@@ -142,6 +133,7 @@ int dap_chain_net_srv_xchange_init()
     l_srv->_internal = s_srv_xchange;
     s_srv_xchange->parent = l_srv;
     s_srv_xchange->enabled = false;
+    s_debug_more = dap_config_get_item_bool_default(g_config, "srv_xchange", "debug_more", s_debug_more);
 
     return 0;
 }
@@ -154,61 +146,104 @@ void dap_chain_net_srv_xchange_deinit()
     DAP_DELETE(s_srv_xchange);
 }
 
-bool dap_chain_net_srv_xchange_verificator(dap_ledger_t * a_ledger, dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner)
+/**
+ * @brief s_verificator_callback
+ * @param a_ledger
+ * @param a_tx_out_hash
+ * @param a_cond
+ * @param a_tx_in
+ * @param a_owner
+ * @return
+ */
+static bool s_xchange_verificator_callback(dap_ledger_t * a_ledger,dap_hash_fast_t *a_tx_out_hash,  dap_chain_tx_out_cond_t *a_tx_out_cond,
+                                           dap_chain_datum_tx_t *a_tx_in, bool a_owner)
 {
+    return true;//for tests
     if (a_owner)
         return true;
+    if(!a_tx_out_hash || !a_tx_in || !a_tx_out_cond)
+        return false;
 
-    pthread_rwlock_rdlock(&s_net_fees_rwlock);
-    struct net_fee * l_fee = NULL;
-    dap_chain_net_t * l_net = dap_chain_ledger_get_net(a_ledger);
-    HASH_FIND(hh,s_net_fees, &l_net->pub.id, sizeof(l_net->pub.id),l_fee);
-    if(l_fee == NULL)
-        pthread_rwlock_unlock(&s_net_fees_rwlock);
+    const char *l_sell_ticker = dap_chain_ledger_tx_get_token_ticker_by_hash(a_ledger,a_tx_out_hash);
+    if (!l_sell_ticker)
+        return false;
+    const char *l_buy_ticker = a_tx_out_cond->subtype.srv_xchange.buy_token;
+
+    uint256_t l_buy_val = {}, l_fee_val = {},
+              l_sell_again_val = {}, l_service_fee_val = {};
+    int l_item_idx_start = 0;
+    byte_t * l_tx_item;
+
+    dap_chain_addr_t l_service_fee_addr, *l_seller_addr = &a_tx_out_cond->subtype.srv_xchange.seller_addr;
+    uint16_t l_service_fee_type;
+    dap_chain_net_t *l_net = dap_chain_net_by_name(a_ledger->net_name);
+    bool l_service_fee_used = s_srv_xchange_get_fee(l_net->pub.id, &l_service_fee_val, &l_service_fee_addr, &l_service_fee_type);
+    const char *l_native_ticker = l_net->pub.native_ticker;
+    const char *l_service_ticker = (l_service_fee_type == SERVICE_FEE_OWN_FIXED || l_service_fee_type == SERVICE_FEE_OWN_PERCENT) ?
+                l_buy_ticker : l_native_ticker;
+    while ((l_tx_item = dap_chain_datum_tx_item_get(a_tx_in, &l_item_idx_start, TX_ITEM_TYPE_OUT_ALL, NULL)) != NULL)
+    {
+        dap_chain_tx_item_type_t l_tx_out_type = dap_chain_datum_tx_item_get_type(l_tx_item);
+        switch(l_tx_out_type){
+            case TX_ITEM_TYPE_OUT_EXT: {
+                dap_chain_tx_out_ext_t *l_tx_in_output = (dap_chain_tx_out_ext_t *)l_tx_item;
+                const char * l_out_token = l_tx_in_output->token;
+                const uint256_t *l_out_value = &l_tx_in_output->header.value;
+                dap_chain_addr_t * l_out_addr = &l_tx_in_output->addr;
+                // Out is with token to buy
+                if (!strcmp(l_out_token, l_buy_ticker) &&
+                        !memcmp(l_out_addr, l_seller_addr, sizeof(*l_out_addr)))
+                    SUM_256_256(l_buy_val, *l_out_value, &l_buy_val);
+                // Out is with token to fee
+                if (l_service_fee_used && !strcmp(l_out_token, l_service_ticker) &&
+                        !memcmp(l_out_addr, &l_service_fee_addr, sizeof(*l_out_addr)))
+                    SUM_256_256(l_fee_val, *l_out_value, &l_fee_val);
+            } break;
+            case TX_ITEM_TYPE_OUT_COND: {
+                dap_chain_tx_out_cond_t *l_tx_in_output = (dap_chain_tx_out_cond_t *)l_tx_item;
+                if (l_tx_in_output->header.subtype == a_tx_out_cond->header.subtype &&                             // Same subtype
+                        l_tx_in_output->header.srv_uid.uint64 == a_tx_out_cond->header.srv_uid.uint64 &&          // Same service uid
+                        l_tx_in_output->header.ts_expires == a_tx_out_cond->header.ts_expires &&                  // Same expires time
+                        l_tx_in_output->tsd_size == a_tx_out_cond->tsd_size &&                              // Same params size
+                        memcmp(l_tx_in_output->tsd, a_tx_out_cond->tsd, l_tx_in_output->tsd_size) == 0 && // Same params itself
+                        memcmp(&l_tx_in_output->subtype.srv_xchange, &a_tx_out_cond->subtype.srv_xchange,         // Same subtype header
+                           sizeof(a_tx_out_cond->subtype.srv_xchange)) == 0) {
+                    l_sell_again_val = l_tx_in_output->header.value;                                    // It is back to cond owner value
+                }
+            }break;
+            default: break;
+        }
+        l_item_idx_start++;
+    }
 
-    /* Check the condition for verification success
+    /* Check the condition for rate verification success
+     * seller rate >= buyer_rate
+     * OR
      * a_cond.srv_xchange.rate (a_cond->header.value / a_cond->subtype.srv_xchange.buy_value) >=
-     * a_tx.out.rate ((a_cond->header.value - l_back_val) / l_out_val)
+     * a_tx.out.rate ((a_cond->header.value - new_cond->header.value) / out_ext.seller_addr(buy_ticker).value)
+     * OR
+     * a_cond->header.value * out_ext.seller_addr(buy_ticker).value >=
+     * a_cond->subtype.srv_xchange.buy_value * (a_cond->header.value - new_cond->header.value)
      */
-    dap_list_t *l_list_out = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_OUT_EXT, NULL);
-    uint256_t l_out_val = {}, l_back_val = {}, l_fee_val = {};
-    char *l_ticker_ctrl = NULL;
-    for (dap_list_t *l_list_tmp = l_list_out; l_list_tmp;  l_list_tmp = l_list_tmp->next) {
-        dap_chain_tx_out_ext_t *l_tx_out = (dap_chain_tx_out_ext_t *)l_list_tmp->data;
-        if (memcmp(&l_tx_out->addr, &l_fee->fee_addr, sizeof(l_fee->fee_addr) == 0 ) ){
-            SUM_256_256(l_fee_val, l_tx_out->header.value, &l_fee_val);
-        }
-
-        // If its returning back to owner
-        if (memcmp(&l_tx_out->addr, &a_cond->params, sizeof(dap_chain_addr_t))) {
-            continue;
-        }
 
-        // Chek if its buy token or not
-        if (strcmp(l_tx_out->token, a_cond->subtype.srv_xchange.buy_token)) {
+    uint256_t l_sell_val, l_buyer_mul, l_seller_mul;
+    if (compare256(l_sell_again_val, a_tx_out_cond->header.value) >= 0)
+        return false;
+    SUBTRACT_256_256(a_tx_out_cond->header.value, l_sell_again_val, &l_sell_val);
+    MULT_256_256(a_tx_out_cond->header.value, l_buy_val, &l_seller_mul);
+    MULT_256_256(a_tx_out_cond->subtype.srv_xchange.buy_value, l_sell_val, &l_buyer_mul);
+    if (compare256(l_seller_mul, l_buyer_mul) < 0)
+        return false;
 
-            // If we alredy have buy token out
-            if (l_ticker_ctrl && strcmp(l_ticker_ctrl, l_tx_out->token)) {
-                if(l_fee) pthread_rwlock_unlock(&s_net_fees_rwlock);
-                return false;   // too many tokens
-            }
-            l_ticker_ctrl = l_tx_out->token;
-            SUM_256_256(l_back_val, l_tx_out->header.value, &l_back_val);
-        } else {                // buying token
-            SUM_256_256(l_out_val, l_tx_out->header.value, &l_out_val);
-        }
-    }
-    //long double l_buyer_rate = (a_cond->header.value - l_back_val) / (long double)l_out_val;
-    //long double l_seller_rate =
-    uint256_t l_buyer_val = {}, l_buyer_mul = {}, l_seller_mul = {};
-    SUBTRACT_256_256(a_cond->header.value, l_back_val, &l_buyer_val);
-    MULT_256_256(l_buyer_val, a_cond->subtype.srv_xchange.buy_value, &l_buyer_mul);
-    MULT_256_256(l_out_val, a_cond->header.value, &l_seller_mul);
-    if (compare256(l_seller_mul, l_buyer_mul) == -1) {
-        if(l_fee) pthread_rwlock_unlock(&s_net_fees_rwlock);
-        return false;           // wrong changing rate
+    /* Check the condition for fee verification success
+     * out_ext.fee_addr(fee_ticker).value >= fee_value
+     */
+    if (l_service_fee_used) {
+        if (l_service_fee_type == SERIVCE_FEE_NATIVE_PERCENT || l_service_fee_type == SERVICE_FEE_OWN_PERCENT)
+            MULT_256_COIN(l_service_fee_val, l_sell_val, &l_service_fee_val);
+        if (compare256(l_fee_val, l_service_fee_val) < 0)
+            return false;
     }
-    if(l_fee) pthread_rwlock_unlock(&s_net_fees_rwlock);
     return true;
 }
 
@@ -222,45 +257,68 @@ bool dap_chain_net_srv_xchange_verificator(dap_ledger_t * a_ledger, dap_chain_tx
  */
 static void s_callback_decree (dap_chain_net_srv_t * a_srv, dap_chain_net_t *a_net, dap_chain_t * a_chain, dap_chain_datum_decree_t * a_decree, size_t a_decree_size)
 {
-    pthread_rwlock_wrlock(&s_net_fees_rwlock);
-    struct net_fee * l_fee = NULL;
+    pthread_rwlock_wrlock(&s_service_fees_rwlock);
+    dap_chain_net_srv_fee_item_t *l_fee = NULL;
     switch(a_decree->header.action){
         case DAP_CHAIN_DATUM_DECREE_ACTION_UPDATE:{
-            HASH_FIND(hh,s_net_fees,&a_net->pub.id, sizeof(a_net->pub.id), l_fee);
+            HASH_FIND(hh,s_service_fees,&a_net->pub.id, sizeof(a_net->pub.id), l_fee);
             if(l_fee == NULL){
                 log_it(L_WARNING,"Decree update for net id 0x%016" DAP_UINT64_FORMAT_X" when such id can't find in hash table", a_net->pub.id.uint64);
+                pthread_rwlock_unlock(&s_service_fees_rwlock);
                 return;
             }
         }break;
         case DAP_CHAIN_DATUM_DECREE_ACTION_CREATE:{
-            l_fee = DAP_NEW_Z(struct net_fee);
+            HASH_FIND(hh,s_service_fees,&a_net->pub.id, sizeof(a_net->pub.id), l_fee);
+            if (l_fee) {
+                log_it(L_WARNING, "Decree create for net id 0x%016" DAP_UINT64_FORMAT_X" when such id already in hash table", a_net->pub.id.uint64);
+                pthread_rwlock_unlock(&s_service_fees_rwlock);
+                return;
+            }
+            l_fee = DAP_NEW_Z(dap_chain_net_srv_fee_item_t);
             l_fee->net_id = a_net->pub.id;
-            HASH_ADD(hh, s_net_fees, net_id, sizeof(l_fee->net_id), l_fee);
+            HASH_ADD(hh, s_service_fees, net_id, sizeof(l_fee->net_id), l_fee);
         } break;
     }
     size_t l_tsd_offset = 0;
 
     while(l_tsd_offset < (a_decree_size - sizeof(a_decree->header)) ){
         dap_tsd_t *l_tsd = (dap_tsd_t*) (a_decree->tsd_sections + l_tsd_offset);
-        switch( (enum tsd_type) l_tsd->type){
-            case TSD_FEE_ADDR:{
-                l_fee->fee_addr = dap_tsd_get_scalar(l_tsd, dap_chain_addr_t);
-            } break;
-            case TSD_FEE_PERCENT:{
-                l_fee->fee_percents = dap_tsd_get_scalar(l_tsd, uint256_t);
-            } break;
-            case TSD_FEE_FIXED:{
-                l_fee->fee_fixed = dap_tsd_get_scalar(l_tsd, uint256_t);
-            } break;
+        switch((dap_chain_net_srv_fee_tsd_type_t)l_tsd->type) {
+        case TSD_FEE_TYPE:
+            l_fee->fee_type = dap_tsd_get_scalar(l_tsd, uint16_t);
+            break;
+        case TSD_FEE:
+            l_fee->fee = dap_tsd_get_scalar(l_tsd, uint256_t);
+            break;
+        case TSD_FEE_ADDR:
+            l_fee->fee_addr = dap_tsd_get_scalar(l_tsd, dap_chain_addr_t);
+        default:
+            break;
         }
         l_tsd_offset += dap_tsd_size(l_tsd);
     }
-    pthread_rwlock_unlock(&s_net_fees_rwlock);
+    pthread_rwlock_unlock(&s_service_fees_rwlock);
 }
 
+static bool s_srv_xchange_get_fee(dap_chain_net_id_t a_net_id, uint256_t *a_fee, dap_chain_addr_t *a_addr, uint16_t *a_type)
+{
+    pthread_rwlock_wrlock(&s_service_fees_rwlock);
+    dap_chain_net_srv_fee_item_t *l_fee = NULL;
+    HASH_FIND(hh,s_service_fees, &a_net_id, sizeof(a_net_id), l_fee);
+    pthread_rwlock_unlock(&s_service_fees_rwlock);
+    if (!l_fee || IS_ZERO_256(l_fee->fee))
+        return false;
+    if (a_type)
+        *a_type = l_fee->fee_type;
+    if (a_addr)
+        *a_addr = l_fee->fee_addr;
+    if (a_fee)
+        *a_fee = l_fee->fee;
+    return true;
+}
 
-
-static dap_chain_datum_tx_receipt_t *s_xchage_receipt_create(dap_chain_net_srv_xchange_price_t *a_price, uint256_t a_datoshi_buy)
+static dap_chain_datum_tx_receipt_t *s_xchange_receipt_create(dap_chain_net_srv_xchange_price_t *a_price, uint256_t a_datoshi_buy)
 {
     uint32_t l_ext_size = sizeof(uint256_t) + DAP_CHAIN_TICKER_SIZE_MAX;
     uint8_t *l_ext = DAP_NEW_STACK_SIZE(uint8_t, l_ext_size);
@@ -269,15 +327,13 @@ static dap_chain_datum_tx_receipt_t *s_xchage_receipt_create(dap_chain_net_srv_x
     dap_chain_net_srv_price_unit_uid_t l_unit = { .uint32 = SERV_UNIT_UNDEFINED};
     dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_XCHANGE_ID };
     uint256_t l_datoshi_sell = {};
-    if (compare256(a_price->rate, uint256_0)!=0){
+    if (!IS_ZERO_256(a_price->rate)){
         DIV_256_COIN(a_datoshi_buy, a_price->rate, &l_datoshi_sell);
         dap_chain_datum_tx_receipt_t *l_receipt =  dap_chain_datum_tx_receipt_create(l_uid, l_unit, 0, l_datoshi_sell,
                                                                                  l_ext, l_ext_size);
         return l_receipt;
-    }else{
-        DAP_DELETE(l_ext);
-        return NULL;
     }
+    return NULL;
 }
 
 static dap_chain_datum_tx_t *s_xchange_tx_create_request(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet)
@@ -285,42 +341,75 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_request(dap_chain_net_srv_xchan
     if (!a_price || !a_price->net || !*a_price->token_sell || !*a_price->token_buy || !a_wallet) {
         return NULL;
     }
-
-    // create empty transaction
-    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
-
-    dap_ledger_t *l_ledger = dap_chain_ledger_by_net_name(a_price->net->pub.name);
+    const char *l_native_ticker = a_price->net->pub.native_ticker;
+    bool l_single_channel = !dap_strcmp(a_price->token_sell, l_native_ticker);
+    // find the transactions from which to take away coins
+    uint256_t l_value_transfer; // how many coins to transfer
+    uint256_t l_value_need = a_price->datoshi_sell,
+              l_net_fee,
+              l_total_fee = a_price->fee,
+              l_fee_transfer;
+    dap_chain_addr_t l_addr_net_fee;
+    dap_list_t *l_list_fee_out = NULL;
+    bool l_net_fee_used = dap_chain_net_tx_get_fee(a_price->net->pub.id, &l_net_fee, &l_addr_net_fee);
+    if (l_net_fee_used)
+        SUM_256_256(l_total_fee, l_net_fee, &l_total_fee);
+
+    dap_ledger_t *l_ledger = a_price->net->pub.ledger;
     dap_chain_addr_t *l_seller_addr = (dap_chain_addr_t *)dap_chain_wallet_get_addr(a_wallet, a_price->net->pub.id);
+    if (l_single_channel)
+        SUM_256_256(l_value_need, l_total_fee, &l_value_need);
+    else {
+        l_list_fee_out = dap_chain_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker,
+                                                                    l_seller_addr, l_total_fee, &l_fee_transfer);
+        if (!l_list_fee_out) {
+            log_it(L_WARNING, "Not enough funds to pay fee");
+            return NULL;
+        }
+    }
     dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0);
-    uint256_t l_value_sell = {}; // how many coins to transfer
     // list of transaction with 'out' items to sell
     dap_list_t *l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(l_ledger, a_price->token_sell,
-                                                                             l_seller_addr, a_price->datoshi_sell, &l_value_sell);
+                                                                             l_seller_addr, l_value_need, &l_value_transfer);
     if(!l_list_used_out) {
-        dap_chain_datum_tx_delete(l_tx);
         DAP_DELETE(l_seller_addr);
         log_it(L_WARNING, "Nothing to change (not enough funds)");
         return NULL;
     }
 
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+
     // add 'in' items to sell
     uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
-    dap_list_free_full(l_list_used_out, free);
-    if (compare256(l_value_to_items, l_value_sell) != 0) {
+    dap_list_free_full(l_list_used_out, NULL);
+    if (!EQUAL_256(l_value_to_items, l_value_transfer) != 0) {
         dap_chain_datum_tx_delete(l_tx);
         DAP_DELETE(l_seller_addr);
         log_it(L_ERROR, "Can't compose the transaction input");
         return NULL;
     }
+    if (!l_single_channel) {
+        // add 'in' items to fee
+        uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+        dap_list_free_full(l_list_used_out, NULL);
+        if (!EQUAL_256(l_value_fee_items, l_fee_transfer) != 0) {
+            dap_chain_datum_tx_delete(l_tx);
+            DAP_DELETE(l_seller_addr);
+            log_it(L_ERROR, "Can't compose the transaction input");
+            return NULL;
+        }
+    }
 
     // add 'out_cond' & 'out' items
+
     {
         uint256_t l_datoshi_buy = uint256_0;
         MULT_256_COIN(a_price->datoshi_sell, a_price->rate, &l_datoshi_buy);
         dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_XCHANGE_ID };
         dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_xchange(l_uid, a_price->net->pub.id, a_price->datoshi_sell,
                                                                                                 a_price->net->pub.id, a_price->token_buy, l_datoshi_buy,
-                                                                                                (void *)l_seller_addr, sizeof(dap_chain_addr_t));
+                                                                                                l_seller_addr, NULL, 0);
         if (!l_tx_out) {
             dap_chain_datum_tx_delete(l_tx);
             DAP_DELETE(l_seller_addr);
@@ -329,9 +418,27 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_request(dap_chain_net_srv_xchan
         }
         dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out);
         DAP_DELETE(l_tx_out);
+        // Network fee
+        if (l_net_fee_used) {
+            if (dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_net_fee, l_net_fee) != 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                DAP_DELETE(l_seller_addr);
+                log_it(L_ERROR, "Cant add network fee output");
+                return NULL;
+            }
+        }
+        // Validator's fee
+        if (!IS_ZERO_256(a_price->fee)) {
+            if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) == 1) {
+                dap_chain_datum_tx_delete(l_tx);
+                DAP_DELETE(l_seller_addr);
+                log_it(L_ERROR, "Cant add validator's fee output");
+                return NULL;
+            }
+        }
         // coin back
         uint256_t l_value_back = {};
-        SUBTRACT_256_256(l_value_sell, a_price->datoshi_sell, &l_value_back);
+        SUBTRACT_256_256(l_value_transfer, l_value_need, &l_value_back);
         if (!IS_ZERO_256(l_value_back)) {
             if (dap_chain_datum_tx_add_out_item(&l_tx, l_seller_addr, l_value_back) != 1) {
                 dap_chain_datum_tx_delete(l_tx);
@@ -340,6 +447,19 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_request(dap_chain_net_srv_xchan
                 return NULL;
             }
         }
+        // Fee coinback
+        if (!l_single_channel) {
+            SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_value_back);
+            if (!IS_ZERO_256(l_value_back)) {
+                if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_seller_addr, l_value_back,
+                                                        a_price->net->pub.native_ticker) != 1) {
+                    dap_chain_datum_tx_delete(l_tx);
+                    DAP_DELETE(l_seller_addr);
+                    log_it(L_ERROR, "Cant add fee back output");
+                    return NULL;
+                }
+            }
+        }
     }
     DAP_DELETE(l_seller_addr);
 
@@ -359,25 +479,68 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha
     if (!a_price || !a_price->net || !*a_price->token_sell || !*a_price->token_buy || !a_wallet) {
         return NULL;
     }
-
-    // create empty transaction
-    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
-
-    dap_ledger_t *l_ledger = dap_chain_ledger_by_net_name(a_price->net->pub.name);
+    const char *l_native_ticker = a_price->net->pub.native_ticker;
+    const char *l_service_ticker;
+    bool l_pay_with_native = !dap_strcmp(a_price->token_buy, l_native_ticker);
+    // find the transactions from which to take away coins
+    uint256_t l_value_transfer, // how many coins to transfer
+              l_value_need = a_price->datoshi_buy,
+              l_net_fee,
+              l_service_fee,
+              l_total_fee = a_price->fee,
+              l_fee_transfer;
+    dap_chain_addr_t l_net_fee_addr, l_service_fee_addr;
+    dap_list_t *l_list_fee_out = NULL;
+    bool l_net_fee_used = dap_chain_net_tx_get_fee(a_price->net->pub.id, &l_net_fee, &l_net_fee_addr);
+    if (l_net_fee_used)
+        SUM_256_256(l_net_fee, a_price->fee, &l_total_fee);
+    uint16_t l_service_fee_type;
+    bool l_service_fee_used = s_srv_xchange_get_fee(a_price->net->pub.id, &l_service_fee, &l_service_fee_addr, &l_service_fee_type);
+    if (l_service_fee_used) {
+        switch (l_service_fee_type) {
+        case SERIVCE_FEE_NATIVE_PERCENT:
+            MULT_256_COIN(l_service_fee, a_price->datoshi_buy, &l_service_fee);
+        case SERVICE_FEE_NATIVE_FIXED:
+            SUM_256_256(l_total_fee, l_service_fee, &l_total_fee);
+            l_service_ticker = l_native_ticker;
+            break;
+        case SERVICE_FEE_OWN_PERCENT:
+            MULT_256_COIN(l_service_fee, a_price->datoshi_buy, &l_service_fee);
+        case SERVICE_FEE_OWN_FIXED:
+            SUM_256_256(l_value_need, l_service_fee, &l_value_need);
+            l_service_ticker = a_price->token_buy;
+        default:
+            break;
+        }
+    }
+    dap_ledger_t *l_ledger = a_price->net->pub.ledger;
     dap_chain_addr_t *l_buyer_addr = (dap_chain_addr_t *)dap_chain_wallet_get_addr(a_wallet, a_price->net->pub.id);
-    dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0);
-    uint256_t l_value_buy = {}; // how many coins to transfer
+    if (l_pay_with_native)
+        SUM_256_256(l_value_need, l_total_fee, &l_value_need);
+    else {
+        l_list_fee_out = dap_chain_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker,
+                                                                    l_buyer_addr, l_total_fee, &l_fee_transfer);
+        if (!l_list_fee_out) {
+            log_it(L_WARNING, "Not enough funds to pay fee");
+            return NULL;
+        }
+    }
     // list of transaction with 'out' items to sell
     dap_list_t *l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(l_ledger, a_price->token_buy,
-                                                                             l_buyer_addr, a_datoshi_buy, &l_value_buy);
+                                                                             l_buyer_addr, l_value_need, &l_value_transfer);
     if(!l_list_used_out) {
-        dap_chain_datum_tx_delete(l_tx);
+        DAP_DELETE(l_buyer_addr);
         log_it(L_WARNING, "Nothing to change (not enough funds)");
         return NULL;
     }
 
+    dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0);
+
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+
     // create and add reciept
-    dap_chain_datum_tx_receipt_t *l_receipt = s_xchage_receipt_create(a_price, a_datoshi_buy);
+    dap_chain_datum_tx_receipt_t *l_receipt = s_xchange_receipt_create(a_price, a_datoshi_buy);
     if( l_receipt == NULL){
         DAP_DELETE(l_buyer_addr);
         log_it(L_ERROR, "Can't compose the receipt");
@@ -388,12 +551,23 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha
     // add 'in' items to sell
     uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
     dap_list_free_full(l_list_used_out, NULL);
-    if (compare256(l_value_to_items, l_value_buy) != 0) {
+    if (!EQUAL_256(l_value_to_items, l_value_transfer)) {
         dap_chain_datum_tx_delete(l_tx);
         DAP_DELETE(l_buyer_addr);
         log_it(L_ERROR, "Can't compose the transaction input");
         return NULL;
     }
+    if (!l_pay_with_native) {
+        // add 'in' items to fee
+        uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out);
+        dap_list_free_full(l_list_used_out, NULL);
+        if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) {
+            dap_chain_datum_tx_delete(l_tx);
+            DAP_DELETE(l_buyer_addr);
+            log_it(L_ERROR, "Can't compose the transaction input");
+            return NULL;
+        }
+    }
     // add 'in' item to buy from conditional transaction
     dap_chain_datum_tx_t *l_cond_tx = dap_chain_ledger_tx_find_by_hash(l_ledger, &a_price->tx_hash);
     if (!l_cond_tx) {
@@ -401,61 +575,131 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha
         return NULL;
     }
     int l_prev_cond_idx = 0;
-    dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_cond_tx, &l_prev_cond_idx);
+    dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_cond_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE,
+                                                                             &l_prev_cond_idx);
+    if (!l_tx_out_cond) {
+        log_it(L_WARNING, "Requested transaction has no conditional output");
+        return NULL;
+    }
     if (dap_chain_ledger_tx_hash_is_used_out_item(l_ledger, &a_price->tx_hash, l_prev_cond_idx)) {
         log_it(L_WARNING, "Requested conditional transaction is already used out");
         return NULL;
     }
+    const dap_chain_addr_t *l_seller_addr = &l_tx_out_cond->subtype.srv_xchange.seller_addr;
     dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_price->tx_hash, l_prev_cond_idx, 0);
+
     // add 'out' items
-    {
-        // transfer buying coins
-        const dap_chain_addr_t *l_seller_addr = (dap_chain_addr_t *)l_tx_out_cond->params;
-        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_seller_addr, a_datoshi_buy, a_price->token_buy) == -1) {
+    // transfer selling coins
+    uint256_t l_datoshi_sell,
+              l_datoshi_buy,
+              l_value_back;
+    if (!IS_ZERO_256(a_price->rate)) {
+        DIV_256_COIN(a_datoshi_buy, a_price->rate, &l_datoshi_sell);
+        if (compare256(l_tx_out_cond->header.value, l_datoshi_sell) < 0) {
+            l_datoshi_sell = l_tx_out_cond->header.value;
+            MULT_256_COIN(l_datoshi_sell, a_price->rate, &l_datoshi_buy);
+        } else
+            l_datoshi_buy = a_datoshi_buy;
+        debug_if(s_debug_more, L_NOTICE, "l_datoshi_sell = %s", dap_chain_balance_to_coins(l_datoshi_sell));
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_buyer_addr, l_datoshi_sell, a_price->token_sell) == -1) {
             dap_chain_datum_tx_delete(l_tx);
             DAP_DELETE(l_buyer_addr);
-            log_it(L_ERROR, "Can't add buying coins output");
+            log_it(L_ERROR, "Can't add selling coins output");
             return NULL;
         }
-        // coin back
-        uint256_t l_value_back = {};
-        SUBTRACT_256_256(l_value_buy, a_datoshi_buy, &l_value_back);
-        if (!IS_ZERO_256(l_value_back)) {
-            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_buyer_addr, l_value_back, a_price->token_buy) == -1) {
-                dap_chain_datum_tx_delete(l_tx);
-                DAP_DELETE(l_buyer_addr);
-                log_it(L_ERROR, "Can't add buying coins back output");
-                return NULL;
-            }
+    }else{
+        DAP_DELETE(l_buyer_addr);
+        log_it(L_ERROR, "Can't add selling coins output because price rate is 0");
+        return NULL;
+    }
+    DAP_DELETE(l_buyer_addr);
+    // transfer unselling coins (partial exchange)
+    debug_if(s_debug_more, L_NOTICE, "l_datoshi_cond = %s", dap_chain_balance_to_coins(l_tx_out_cond->header.value));
+    if (compare256(l_tx_out_cond->header.value, l_datoshi_sell) == 1) {
+        SUBTRACT_256_256(l_tx_out_cond->header.value, l_datoshi_sell, &l_value_back);
+        debug_if(s_debug_more, L_NOTICE, "l_value_back = %s", dap_chain_balance_to_coins(l_value_back));
+        uint256_t l_datoshi_buy_again;
+        MULT_256_COIN(l_value_back, a_price->rate, &l_datoshi_buy_again);
+        debug_if(s_debug_more, L_NOTICE, "l_datoshi_buy_again = %s", dap_chain_balance_to_coins(l_datoshi_buy_again));
+        dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_xchange(
+                    c_dap_chain_net_srv_xchange_uid, a_price->net->pub.id, l_value_back,
+                    a_price->net->pub.id, a_price->token_buy, l_datoshi_buy_again,
+                    l_seller_addr, NULL, 0);
+        if (!l_tx_out) {
+            dap_chain_datum_tx_delete(l_tx);
+            DAP_DELETE(l_seller_addr);
+            log_it(L_WARNING, "Can't add selling coins back conditioned output (cond cashback)");
+            return NULL;
         }
-        //transfer selling coins
-        uint256_t l_datoshi_sell = {};
-        if (compare256(a_price->rate, uint256_0)!=0){
-            DIV_256_COIN(a_datoshi_buy, a_price->rate, &l_datoshi_sell);
+        dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out);
+        DAP_DELETE(l_tx_out);
+    } else // mark price order as ready
+        memset(&a_price->order_hash, 0, sizeof(dap_hash_fast_t));
 
-            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_buyer_addr, l_datoshi_sell, a_price->token_sell) == -1) {
-                dap_chain_datum_tx_delete(l_tx);
-                DAP_DELETE(l_buyer_addr);
-                log_it(L_ERROR, "Can't add selling coins output");
-                return NULL;
-            }
-        }else{
+    // transfer buying coins
+    if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_seller_addr, l_datoshi_buy, a_price->token_buy) == -1) {
+        dap_chain_datum_tx_delete(l_tx);
+        DAP_DELETE(l_buyer_addr);
+        log_it(L_ERROR, "Can't add buying coins output");
+        return NULL;
+    }
+    debug_if(s_debug_more, L_NOTICE, "l_datoshi_buy = %s", dap_chain_balance_to_coins(l_datoshi_buy));
+    // transfer validator's fee
+    if (!IS_ZERO_256(a_price->fee)) {
+        if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) == -1) {
+            dap_chain_datum_tx_delete(l_tx);
             DAP_DELETE(l_buyer_addr);
-            log_it(L_ERROR, "Can't add selling coins output because price rate is 0");
+            log_it(L_ERROR, "Can't add validator fee output");
             return NULL;
         }
-        DAP_DELETE(l_buyer_addr);
-        //transfer unselling coins (partial exchange)
-        SUBTRACT_256_256(l_tx_out_cond->header.value, l_datoshi_sell, &l_value_back);
+        debug_if(s_debug_more, L_NOTICE, "l_validator_fee = %s", dap_chain_balance_to_coins(a_price->fee));
+    }
+    // transfer net fee
+    if (l_net_fee_used) {
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_net_fee_addr, l_net_fee, l_native_ticker) == -1) {
+            dap_chain_datum_tx_delete(l_tx);
+            DAP_DELETE(l_buyer_addr);
+            log_it(L_ERROR, "Can't add net fee output");
+            return NULL;
+        }
+        debug_if(s_debug_more, L_NOTICE, "l_net_fee = %s", dap_chain_balance_to_coins(l_net_fee));
+    }
+    // transfer service fee
+    if (l_service_fee_used) {
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_service_fee_addr, l_service_fee, l_service_ticker) == -1) {
+            dap_chain_datum_tx_delete(l_tx);
+            DAP_DELETE(l_buyer_addr);
+            log_it(L_ERROR, "Can't add net fee output");
+            return NULL;
+        }
+        debug_if(s_debug_more, L_NOTICE, "l_service_fee = %s", dap_chain_balance_to_coins(l_net_fee));
+    }
+    // coin back
+    SUBTRACT_256_256(l_value_transfer, l_value_need, &l_value_back);
+    if (!IS_ZERO_256(l_value_back)) {
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_buyer_addr, l_value_back, a_price->token_buy) == -1) {
+            dap_chain_datum_tx_delete(l_tx);
+            DAP_DELETE(l_buyer_addr);
+            log_it(L_ERROR, "Can't add buying coins back output");
+            return NULL;
+        }
+    }
+    debug_if(s_debug_more, L_NOTICE, "l_value_transfer = %s", dap_chain_balance_to_coins(l_value_transfer));
+    debug_if(s_debug_more, L_NOTICE, "l_value_back = %s", dap_chain_balance_to_coins(l_value_back));
+    // fee back
+    if (!l_pay_with_native) {
+        SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_value_back);
         if (!IS_ZERO_256(l_value_back)) {
-            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_seller_addr, l_value_back, a_price->token_sell) == -1) {
-                log_it(L_WARNING, "Can't add selling coins back output (cashback)");
+            if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_buyer_addr, l_value_back, a_price->token_buy) == -1) {
                 dap_chain_datum_tx_delete(l_tx);
+                DAP_DELETE(l_buyer_addr);
+                log_it(L_ERROR, "Can't add buying coins back output");
                 return NULL;
             }
         }
+        debug_if(s_debug_more, L_NOTICE, "l_fee_transfer = %s", dap_chain_balance_to_coins(l_fee_transfer));
+        debug_if(s_debug_more, L_NOTICE, "l_value_back = %s", dap_chain_balance_to_coins(l_value_back));
     }
-
     // add 'sign' items
     if(dap_chain_datum_tx_add_sign_item(&l_tx, l_seller_key) != 1) {
         dap_chain_datum_tx_delete(l_tx);
@@ -493,8 +737,9 @@ static bool s_xchange_tx_put(dap_chain_datum_tx_t *a_tx, dap_chain_net_t *a_net)
     return true;
 }
 
-static bool s_xchage_tx_invalidate(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet)
+static bool s_xchange_tx_invalidate(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet)
 {
+    const char *l_native_ticker = a_price->net->pub.native_ticker;
     // create empty transaction
     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
 
@@ -503,9 +748,10 @@ static bool s_xchage_tx_invalidate(dap_chain_net_srv_xchange_price_t *a_price, d
     dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0);
 
     // create and add reciept
-    dap_chain_datum_tx_receipt_t *l_receipt = s_xchage_receipt_create(a_price, uint256_0);
+    dap_chain_datum_tx_receipt_t *l_receipt = s_xchange_receipt_create(a_price, uint256_0);
     if (!l_receipt) {
         log_it(L_WARNING, "Can't create receipt");
+        dap_chain_datum_tx_delete(l_tx);
         return false;
     }
     dap_chain_datum_tx_add_item(&l_tx, (byte_t *)l_receipt);
@@ -515,26 +761,95 @@ static bool s_xchage_tx_invalidate(dap_chain_net_srv_xchange_price_t *a_price, d
     dap_chain_datum_tx_t *l_cond_tx = dap_chain_ledger_tx_find_by_hash(l_ledger, &a_price->tx_hash);
     if (!l_cond_tx) {
         log_it(L_WARNING, "Requested conditional transaction not found");
+        dap_chain_datum_tx_delete(l_tx);
         return false;
     }
+    const char *l_tx_ticker = dap_chain_ledger_tx_get_token_ticker_by_hash(l_ledger, &a_price->tx_hash);
+    bool l_single_channel = !dap_strcmp(l_tx_ticker, l_native_ticker);
     int l_prev_cond_idx;
-    dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_cond_tx, &l_prev_cond_idx);
+    dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_cond_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE,
+                                                                             &l_prev_cond_idx);
     if (dap_chain_ledger_tx_hash_is_used_out_item(l_ledger, &a_price->tx_hash, l_prev_cond_idx)) {
         log_it(L_WARNING, "Requested conditional transaction is already used out");
+        dap_chain_datum_tx_delete(l_tx);
         return false;
     }
     dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_price->tx_hash, l_prev_cond_idx, 0);
 
-    // add 'out' item
-    const dap_chain_addr_t *l_buyer_addr = (dap_chain_addr_t *)l_tx_out_cond->params;
-    if (memcmp(l_seller_addr->data.hash, l_buyer_addr->data.hash, sizeof(dap_chain_hash_fast_t))) {
+    // check 'out_cond' item
+    dap_chain_addr_t *l_cond_addr = &l_tx_out_cond->subtype.srv_xchange.seller_addr;
+    if (dap_hash_fast_compare(&l_seller_addr->data.hash_fast, &l_cond_addr->data.hash_fast)) {
         log_it(L_WARNING, "Only owner can invalidate exchange transaction");
+        dap_chain_datum_tx_delete(l_tx);
         return false;
     }
-    if (dap_chain_datum_tx_add_out_item(&l_tx, l_seller_addr, l_tx_out_cond->header.value) == -1) {
+    uint256_t l_net_fee = {}, l_transfer_fee;
+    dap_chain_addr_t l_addr_fee = {};
+    bool l_net_fee_used = dap_chain_net_tx_get_fee(a_price->net->pub.id, &l_net_fee, &l_addr_fee);
+    uint256_t l_total_fee = {};
+    SUM_256_256(a_price->fee, l_net_fee, &l_total_fee);
+    // list of transaction with 'out' items to get net fee
+    dap_list_t *l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker,
+                                                                             l_seller_addr, l_total_fee, &l_transfer_fee);
+    if(!l_list_used_out) {
+        dap_chain_datum_tx_delete(l_tx);
+        log_it(L_WARNING, "Nothing to pay for network fee (not enough funds)");
+        return false;
+    }
+    // add 'in' items to net fee
+    uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+    dap_list_free_full(l_list_used_out, NULL);
+    if (!EQUAL_256(l_value_to_items, l_transfer_fee)) {
+        dap_chain_datum_tx_delete(l_tx);
+        log_it(L_ERROR, "Can't compose the transaction input");
+        return NULL;
+    }
+
+    // return coins to owner
+    if (l_single_channel) {
+        if (dap_chain_datum_tx_add_out_item(&l_tx, l_seller_addr, l_tx_out_cond->header.value) == -1) {
+            dap_chain_datum_tx_delete(l_tx);
+            DAP_DELETE(l_seller_addr);
+            log_it(L_ERROR, "Cant add returning coins output");
+            return false;
+        }
+    } else {
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_seller_addr, l_tx_out_cond->header.value,
+                                                l_tx_ticker) == -1) {
+            dap_chain_datum_tx_delete(l_tx);
+            DAP_DELETE(l_seller_addr);
+            log_it(L_ERROR, "Cant add returning coins output");
+            return false;
+        }
+    }
+
+    // Network fee
+    if (l_net_fee_used) {
+        if (dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_fee, l_net_fee) != 1) {
+            dap_chain_datum_tx_delete(l_tx);
+            DAP_DELETE(l_seller_addr);
+            log_it(L_ERROR, "Cant add network fee output");
+            return NULL;
+        }
+    }
+    // Validator's fee
+    if (!IS_ZERO_256(a_price->fee)) {
+        if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) == 1) {
+            dap_chain_datum_tx_delete(l_tx);
+            DAP_DELETE(l_seller_addr);
+            log_it(L_ERROR, "Cant add validator's fee output");
+            return NULL;
+        }
+    }
+
+    // put the net fee cashback
+    uint256_t l_fee_back = {};
+    SUBTRACT_256_256(l_transfer_fee, l_total_fee, &l_fee_back);
+    if (!IS_ZERO_256(l_fee_back) &&
+            dap_chain_datum_tx_add_out_item(&l_tx, l_seller_addr, l_tx_out_cond->header.value) == -1) {
         dap_chain_datum_tx_delete(l_tx);
         DAP_DELETE(l_seller_addr);
-        log_it(L_ERROR, "Cant add returning coins output");
+        log_it(L_ERROR, "Cant add fee cachback output");
         return false;
     }
     DAP_DELETE(l_seller_addr);
@@ -562,18 +877,17 @@ char *s_xchange_order_create(dap_chain_net_srv_xchange_price_t *a_price, dap_cha
     dap_chain_hash_fast_t l_tx_hash = {};
     dap_hash_fast(a_tx, dap_chain_datum_tx_get_size(a_tx), &l_tx_hash);
     a_price->tx_hash = l_tx_hash;
-    dap_srv_xchange_order_ext_t l_ext={0};
-    l_ext.datoshi_sell = a_price->datoshi_sell;
-    strncpy(l_ext.token_sell, a_price->token_sell, DAP_CHAIN_TICKER_SIZE_MAX);
-    uint32_t l_ext_size = sizeof(dap_srv_xchange_order_ext_t);
     dap_chain_node_addr_t *l_node_addr = dap_chain_net_get_cur_addr(a_price->net);
     dap_chain_net_srv_price_unit_uid_t l_unit = { .uint32 =  SERV_UNIT_UNDEFINED};
     dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_XCHANGE_ID };
     uint256_t l_datoshi_buy = uint256_0;
     MULT_256_COIN(a_price->datoshi_sell, a_price->rate, &l_datoshi_buy);
-
-    char *l_order_hash_str = dap_chain_net_srv_order_create(a_price->net, SERV_DIR_BUY, l_uid, *l_node_addr,
-                                                            l_tx_hash, &l_datoshi_buy, l_unit, a_price->token_buy, 0,
+    dap_srv_xchange_order_ext_t l_ext={0};
+    l_ext.datoshi_buy = l_datoshi_buy;
+    strncpy(l_ext.token_buy, a_price->token_buy, DAP_CHAIN_TICKER_SIZE_MAX);
+    uint32_t l_ext_size = sizeof(dap_srv_xchange_order_ext_t);
+    char *l_order_hash_str = dap_chain_net_srv_order_create(a_price->net, SERV_DIR_SELL, l_uid, *l_node_addr,
+                                                            l_tx_hash, &a_price->datoshi_sell, l_unit, a_price->token_sell, 0,
                                                             (uint8_t *)&l_ext, l_ext_size, NULL, 0, a_price->wallet_key);
     return l_order_hash_str;
 }
@@ -588,18 +902,24 @@ dap_chain_net_srv_xchange_price_t *s_xchange_price_from_order(dap_chain_net_t *a
 {
     dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t);
     dap_srv_xchange_order_ext_t *l_ext = (dap_srv_xchange_order_ext_t *)a_order->ext_n_sign;
-    l_price->datoshi_sell = l_ext->datoshi_sell;
-    strcpy(l_price->token_sell, l_ext->token_sell);
+    strcpy(l_price->token_buy, l_ext->token_buy);
+    l_price->datoshi_buy = l_ext->datoshi_buy;
+    strcpy(l_price->token_sell, a_order->price_ticker);
+    l_price->datoshi_sell = a_order->price;
     l_price->net = a_net;
-    strcpy(l_price->token_buy, a_order->price_ticker);
-    if( compare256(l_price->datoshi_sell, uint256_0) !=0 ){
-        DIV_256_COIN(a_order->price, l_price->datoshi_sell, &l_price->rate);
-        l_price->tx_hash = a_order->tx_cond_hash;
-        return l_price;
-    }else{
-        DAP_DELETE(l_price);
-        return NULL;
-    }
+    if (!IS_ZERO_256(l_price->datoshi_buy)) {
+        DIV_256_COIN(l_price->datoshi_buy, l_price->datoshi_sell, &l_price->rate);
+        dap_hash_fast_t *l_final_hash = dap_chain_ledger_get_final_chain_tx_hash(a_net->pub.ledger,
+                                           DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &a_order->tx_cond_hash);
+        if (l_final_hash) {
+            l_price->tx_hash = *l_final_hash;
+            return l_price;
+        } else
+            log_it(L_WARNING, "This order have no active conditional transaction");
+    } else
+        log_it(L_WARNING, "Can't calculate price rate, because amount od datoshi sell is zero");
+    DAP_DELETE(l_price);
+    return NULL;
 }
 
 /**
@@ -613,7 +933,7 @@ dap_chain_net_srv_xchange_price_t *s_xchange_price_from_order(dap_chain_net_t *a
 static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, char **a_str_reply)
 {
     enum {
-        CMD_NONE, CMD_CREATE, CMD_REMOVE, CMD_UPDATE, CMD_HISTORY
+        CMD_NONE, CMD_CREATE, CMD_REMOVE, CMD_UPDATE, CMD_HISTORY, CMD_STATUS
     };
     int l_cmd_num = CMD_NONE;
     if(dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, min(a_argc, a_arg_index + 1), "create", NULL)) {
@@ -628,6 +948,9 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
     else if(dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, min(a_argc, a_arg_index + 1), "history", NULL)) {
         l_cmd_num = CMD_HISTORY;
     }
+    else if(dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, min(a_argc, a_arg_index + 1), "status", NULL)) {
+        l_cmd_num = CMD_STATUS;
+    }
     int l_arg_index = a_arg_index + 1;
     const char *l_net_str = NULL;
     const char *l_token_sell_str = NULL, *l_token_buy_str = NULL;
@@ -671,7 +994,7 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
             }
             uint256_t l_datoshi_sell = dap_chain_balance_scan(l_val_sell_str);
             if (IS_ZERO_256(l_datoshi_sell)) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -coins <unsigned long long>");
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -coins <unsigned integer 256>");
                 return -9;
             }
             dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-rate", &l_val_rate_str);
@@ -680,10 +1003,21 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
                 return -8;
             }
             uint256_t l_rate = dap_chain_coins_to_balance(l_val_rate_str);
-            if (!compare256(l_rate, uint256_0)) { // if (l_rate == 0)
+            if (!IS_ZERO_256(l_rate)) {
                 dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -rate n.n = buy / sell (eg: 1.0, 1.135)");
                 return -9;
             }
+            const char *l_fee_str = NULL;
+            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str);
+            if (!l_fee_str) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'price create' required parameter -fee");
+                return -20;
+            }
+            uint256_t l_fee = dap_chain_coins_to_balance(l_fee_str);
+            if (!IS_ZERO_256(l_fee)) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -fee <unsigned integer 256>");
+                return -21;
+            }
             dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-wallet", &l_wallet_str);
             if (!l_wallet_str) {
                 dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'price create' required parameter -wallet");
@@ -695,7 +1029,22 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
                 return -11;
             }
             uint256_t l_value = dap_chain_wallet_get_balance(l_wallet, l_net->pub.id, l_token_sell_str);
-            if (compare256(l_value, l_datoshi_sell) == -1) {
+            uint256_t l_value_sell = l_datoshi_sell;
+            if (!dap_strcmp(l_net->pub.native_ticker, l_token_sell_str)) {
+                if (SUM_256_256(l_value_sell, l_fee, &l_value_sell)) {
+                    dap_chain_wallet_close(l_wallet);
+                    log_it(L_ERROR, "Integer overflow with sum of value and fee");
+                    return -22;
+                }
+            } else { // sell non-native ticker
+                uint256_t l_fee_value = dap_chain_wallet_get_balance(l_wallet, l_net->pub.id, l_net->pub.native_ticker);
+                if (compare256(l_fee_value, l_fee) == -1) {
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Not enough cash for fee in specified wallet");
+                    dap_chain_wallet_close(l_wallet);
+                    return -23;
+                }
+            }
+            if (compare256(l_value, l_value_sell) == -1) {
                 dap_cli_server_cmd_set_reply_text(a_str_reply, "Not enough cash in specified wallet");
                 dap_chain_wallet_close(l_wallet);
                 return -12;
@@ -708,6 +1057,7 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
             dap_stpcpy(l_price->token_buy, l_token_buy_str);
             l_price->datoshi_sell = l_datoshi_sell;
             l_price->rate = l_rate;
+            l_price->fee = l_fee;
             // Create conditional transaction
             dap_chain_datum_tx_t *l_tx = s_xchange_tx_create_request(l_price, l_wallet);
             if (!l_tx) {
@@ -740,10 +1090,11 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
                 return -18;
             }
         } break;
+
         case CMD_HISTORY:{
             dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
             if (!l_net_str) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order create' required parameter -net");
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order history' required parameter -net");
                 return -2;
             }
             l_net = dap_chain_net_by_name(l_net_str);
@@ -752,44 +1103,70 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
                 return -3;
             }
 
-            } break;
-
             const char * l_order_hash_str = NULL;
+            const char * l_addr_hash_str = NULL;
+
             dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-order", &l_order_hash_str);
-            if (!l_order_hash_str) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'price %s' required parameter -order",
-                                                                l_cmd_num == CMD_REMOVE ? "remove" : "update");
+            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-addr", &l_addr_hash_str);
+
+            if (!l_order_hash_str && ! l_addr_hash_str) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order history' required parameter -order or -addr" );
                 return -12;
             }
-            dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_find_by_hash_str(l_net, l_order_hash_str);
-            if (!l_order) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order not found");
-                return -13;
+            if(l_addr_hash_str){
+                dap_chain_addr_t *l_addr = dap_chain_addr_from_str(l_addr_hash_str);
+                if (!l_addr) {
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Incorrect chain address");
+                    return -14;
+                }
+                if (dap_chain_addr_check_sum(l_addr) != 1 ) {
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Incorrect chain address");
+                    return -15;
+                }
+                dap_list_t *l_tx_list = dap_chain_net_get_tx_cond_all_for_addr(l_net,l_addr, c_dap_chain_net_srv_xchange_uid );
+                dap_string_t * l_str_reply = dap_string_new("");
+                while(l_tx_list ){
+                    dap_chain_datum_tx_t * l_tx_cur = (dap_chain_datum_tx_t*) l_tx_list->data;
+                    s_string_append_tx_cond_info(l_str_reply, l_net, l_tx_cur );
+                }
+                dap_list_free(l_tx_list);
+                *a_str_reply = dap_string_free(l_str_reply, false);
+                DAP_DELETE(l_addr);
             }
+            if(l_order_hash_str){
+                dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_find_by_hash_str(l_net, l_order_hash_str);
+                if (!l_order) {
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order not found");
+                    return -13;
+                }
 
-            dap_chain_datum_tx_t * l_tx = dap_chain_net_get_tx_by_hash(l_net,&l_order->tx_cond_hash, TX_SEARCH_TYPE_NET);
-            if( l_tx){
-                int l_rc = s_tx_check_for_open_close(l_net,l_tx);
-                char *l_tx_hash = dap_chain_hash_fast_to_str_new(&l_order->tx_cond_hash);
-                if(l_rc == 0){
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "WRONG TX %s", l_tx_hash);
-                }else if(l_rc == 1){
-                    dap_string_t * l_str_reply = dap_string_new("");
-                    s_string_append_tx_info(l_str_reply, l_net, l_tx);
-                    *a_str_reply = dap_string_free(l_str_reply, false);
-                }else if(l_rc == 2){
-                    dap_string_t * l_str_reply = dap_string_new("");
-                    while(l_tx){
-                        s_string_append_tx_info(l_str_reply, l_net, l_tx);
-
+                dap_chain_datum_tx_t * l_tx = dap_chain_net_get_tx_by_hash(l_net,&l_order->tx_cond_hash, TX_SEARCH_TYPE_NET);
+                if( l_tx){
+                    int l_rc = s_tx_check_for_open_close(l_net,l_tx);
+                    char *l_tx_hash = dap_chain_hash_fast_to_str_new(&l_order->tx_cond_hash);
+                    if(l_rc == 0){
+                        dap_cli_server_cmd_set_reply_text(a_str_reply, "WRONG TX %s", l_tx_hash);
+                    }else if(l_rc == 1){
+                        dap_string_t * l_str_reply = dap_string_new("");
+                        s_string_append_tx_cond_info(l_str_reply, l_net, l_tx);
+                        *a_str_reply = dap_string_free(l_str_reply, false);
+                    }else if(l_rc == 2){
+                        dap_string_t * l_str_reply = dap_string_new("");
+                        dap_list_t *l_tx_list = dap_chain_net_get_tx_cond_chain(l_net,&l_order->tx_cond_hash, c_dap_chain_net_srv_xchange_uid );
+                        while(l_tx_list ){
+                            dap_chain_datum_tx_t * l_tx_cur = (dap_chain_datum_tx_t*) l_tx_list->data;
+                            s_string_append_tx_cond_info(l_str_reply, l_net, l_tx_cur );
+                        }
+                        dap_list_free(l_tx_list);
+                        *a_str_reply = dap_string_free(l_str_reply, false);
+                    }else{
+                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Internal error!");
                     }
-                    *a_str_reply = dap_string_free(l_str_reply, false);
                 }else{
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Internal error!");
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "No history");
                 }
-            }else{
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "No history");
             }
+        } break;
 
         case CMD_REMOVE:
         case CMD_UPDATE: {
@@ -835,14 +1212,13 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
 
             if (l_cmd_num == CMD_REMOVE) {
                 dap_string_t *l_str_reply = dap_string_new("");
-                bool l_ret = s_xchage_tx_invalidate(l_price, l_wallet);
+                bool l_ret = s_xchange_tx_invalidate(l_price, l_wallet);
                 dap_chain_wallet_close(l_wallet);
                 if (!l_ret) {
                     char *l_tx_hash_str = dap_chain_hash_fast_to_str_new(&l_price->tx_hash);
                     dap_string_append_printf(l_str_reply, "Can't invalidate transaction %s\n", l_tx_hash_str);
                     DAP_DELETE(l_tx_hash_str);
                 }
-                char *l_order_hash_str = dap_chain_hash_fast_to_str_new(&l_price->order_hash);
                 if (dap_chain_net_srv_order_delete_by_hash_str_sync(l_price->net, l_order_hash_str)) {
                     dap_string_append_printf(l_str_reply, "Can't remove order %s\n", l_order_hash_str);
                 }
@@ -868,7 +1244,7 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
                 dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-rate", &l_val_rate_str);
                 if (l_val_rate_str) {
                     l_rate = dap_chain_coins_to_balance(l_val_rate_str);
-                    if (!compare256(l_rate, uint256_0)) { // if (l_rate == 0)
+                    if (IS_ZERO_256(l_rate)) {
                         dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -rate <long double> = sell / buy");
                         return -9;
                     }
@@ -908,7 +1284,7 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't compose the conditional transaction");
                     return -14;
                 }
-                bool l_ret = s_xchage_tx_invalidate(l_price, l_wallet); // may be changed to old price later
+                bool l_ret = s_xchange_tx_invalidate(l_price, l_wallet); // may be changed to old price later
                 dap_chain_wallet_close(l_wallet);
                 if (!l_ret) {
                     char *l_tx_hash_str = dap_chain_hash_fast_to_str_new(&l_price->tx_hash);
@@ -917,7 +1293,6 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
                     return -17;
                 }
                 // Update the order
-                char *l_order_hash_str = dap_chain_hash_fast_to_str_new(&l_price->order_hash);
                 dap_chain_net_srv_order_delete_by_hash_str_sync(l_price->net, l_order_hash_str);
                 DAP_DELETE(l_order_hash_str);
                 l_order_hash_str = s_xchange_order_create(l_price, l_tx);
@@ -939,6 +1314,70 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c
                 }
             }
         } break;
+
+        case CMD_STATUS: {
+            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
+            if (!l_net_str) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order status' required parameter -net");
+                return -2;
+            }
+            l_net = dap_chain_net_by_name(l_net_str);
+            if (!l_net) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Network %s not found", l_net_str);
+                return -3;
+            }
+            const char * l_order_hash_str = NULL;
+            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-order", &l_order_hash_str);
+            if (!l_order_hash_str) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order history' required parameter -order or -addr" );
+                return -12;
+            }
+            dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_find_by_hash_str(l_net, l_order_hash_str);
+            if (!l_order) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order not found");
+                return -13;
+            }
+            dap_hash_fast_t *l_final_hash = dap_chain_ledger_get_final_chain_tx_hash(l_net->pub.ledger,
+                                                 DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &l_order->tx_cond_hash);
+            if (!l_final_hash) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order have no active tx (copmleted)");
+                DAP_DELETE(l_order);
+                return -18;
+            }
+            dap_chain_datum_tx_t *l_tx = dap_chain_ledger_tx_find_by_hash(l_net->pub.ledger, l_final_hash);
+            if (!l_tx) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Internal error");
+                DAP_DELETE(l_order);
+                return -19;
+            }
+            dap_chain_tx_out_cond_t *l_out_cond = dap_chain_datum_tx_out_cond_get(l_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE,
+                                                                                  NULL);
+            if (!l_out_cond) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order have no active conditional tx (copmleted)");
+                DAP_DELETE(l_order);
+                return -20;
+            }
+            uint256_t l_filled, l_filled_percent, l_rate;
+            dap_srv_xchange_order_ext_t *l_ext = (dap_srv_xchange_order_ext_t *)l_order->ext_n_sign;
+            char *l_amount_str = dap_chain_balance_to_coins(l_order->price);
+            char *l_current_str = dap_chain_balance_to_coins(l_out_cond->header.value);
+            SUBTRACT_256_256(l_order->price, l_out_cond->header.value, &l_filled);
+            DIV_256_COIN(l_filled, l_out_cond->header.value, &l_filled_percent);
+            MULT_256_256(l_filled_percent, dap_chain_uint256_from(100), &l_filled_percent);
+            char *l_filled_str = dap_chain_balance_to_coins(l_filled_percent);
+            DIV_256_COIN(l_ext->datoshi_buy, l_order->price, &l_rate);
+            char *l_rate_str = dap_chain_balance_to_coins(l_rate);
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "tokenSell: %s, tokenBuy: %s, amount: %s, current %s, filled: %s%% rate(buy/sell): %s\n",
+                                                            l_order->price_ticker, l_ext->token_buy,
+                                                            l_amount_str, l_current_str,
+                                                            l_filled_str, l_rate_str);
+            DAP_DEL_Z(l_amount_str);
+            DAP_DEL_Z(l_current_str);
+            DAP_DEL_Z(l_filled_str);
+            DAP_DEL_Z(l_rate_str);
+            DAP_DELETE(l_order);
+        } break;
+
         default: {
             dap_cli_server_cmd_set_reply_text(a_str_reply, "Subcommand %s not recognized", a_argv[a_arg_index]);
             return -4;
@@ -995,14 +1434,13 @@ static int s_tx_check_for_open_close(dap_chain_net_t * a_net, dap_chain_datum_tx
     dap_hash_fast_t l_tx_hash = {0};
     size_t l_tx_size = dap_chain_datum_tx_get_size(a_tx);
     dap_hash_fast(a_tx, l_tx_size, &l_tx_hash);
-    dap_chain_tx_out_cond_t *l_out_cond_item = dap_chain_datum_tx_out_cond_get(a_tx, &l_cond_idx);
-    if ( l_out_cond_item && (l_out_cond_item->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE) )
-    {
+    dap_chain_tx_out_cond_t *l_out_cond_item = dap_chain_datum_tx_out_cond_get(a_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE,
+                                                                               &l_cond_idx);
+    if (l_out_cond_item) {
         if(dap_chain_ledger_tx_hash_is_used_out_item(a_net->pub.ledger, &l_tx_hash, l_cond_idx))
             return 1; // If its SRV_XCHANGE and spent its closed
         else
             return 2; // If its SRV_XCHANGE and not spent its open
-
     }
     return 0;
 }
@@ -1013,7 +1451,7 @@ static int s_tx_check_for_open_close(dap_chain_net_t * a_net, dap_chain_datum_tx
  * @param a_net
  * @param a_tx
  */
-static void s_string_append_tx_info( dap_string_t * a_reply_str, dap_chain_net_t * a_net, dap_chain_datum_tx_t * a_tx )
+static void s_string_append_tx_cond_info( dap_string_t * a_reply_str, dap_chain_net_t * a_net, dap_chain_datum_tx_t * a_tx )
 {
     size_t l_tx_size = dap_chain_datum_tx_get_size(a_tx);
 
@@ -1028,9 +1466,14 @@ static void s_string_append_tx_info( dap_string_t * a_reply_str, dap_chain_net_t
     const char * l_tx_input_ticker = dap_chain_ledger_tx_get_token_ticker_by_hash(
                 a_net->pub.ledger, &l_tx_hash);
 
+
+
+
     // Find SRV_XCHANGE out_cond item
     int l_cond_idx = 0;
-    dap_chain_tx_out_cond_t *l_out_cond_item = dap_chain_datum_tx_out_cond_get(a_tx, &l_cond_idx);
+    dap_chain_tx_out_cond_t *l_out_cond_item = dap_chain_datum_tx_out_cond_get(a_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE,
+                                                                               &l_cond_idx);
+    bool l_is_cond_out = false;
     if ( l_out_cond_item && (l_out_cond_item->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE) )
     {
         bool l_is_closed = dap_chain_ledger_tx_hash_is_used_out_item(a_net->pub.ledger, &l_tx_hash, l_cond_idx);
@@ -1040,14 +1483,29 @@ static void s_string_append_tx_info( dap_string_t * a_reply_str, dap_chain_net_t
         char *l_value_to_str = dap_chain_balance_to_coins(l_value_to);
         char *l_value_from_str = dap_chain_balance_to_coins(l_value_from);
 
-        dap_string_append_printf(a_reply_str, "Hash: %s,", l_tx_hash_str);
-        dap_string_append_printf(a_reply_str, "  Status: %s,", l_is_closed ? "closed" : "open");
-        dap_string_append_printf(a_reply_str, "  From: %s %s,", l_value_from_str, l_tx_input_ticker);
-        dap_string_append_printf(a_reply_str, "  To: %s %s\n", l_value_to_str, l_out_cond_item->subtype.srv_xchange.buy_token);
+        dap_string_append_printf(a_reply_str, "Hash: %s", l_tx_hash_str);
+        dap_string_append_printf(a_reply_str, "  Status: %s", l_is_closed ? "closed" : "open");
+        dap_string_append_printf(a_reply_str, "  From: %s %s", l_value_from_str, l_tx_input_ticker);
+        dap_string_append_printf(a_reply_str, "  To: %s %s", l_value_to_str, l_out_cond_item->subtype.srv_xchange.buy_token);
 
         DAP_DELETE(l_value_from_str);
         DAP_DELETE(l_value_to_str);
+        l_is_cond_out = true;
     }
+    if(l_is_cond_out){
+        // Get IN_COND items from transaction
+        int l_item_idx = 0;
+        byte_t *l_tx_item;
+        while ((l_tx_item = dap_chain_datum_tx_item_get(a_tx, &l_item_idx, TX_ITEM_TYPE_IN_COND , NULL)) != NULL){
+            dap_chain_tx_in_cond_t * l_in_cond = (dap_chain_tx_in_cond_t *) l_tx_item;
+            char l_tx_prev_cond_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
+            dap_hash_fast_to_str(&l_in_cond->header.tx_prev_hash,l_tx_prev_cond_hash_str, sizeof(l_tx_prev_cond_hash_str));
+            dap_string_append_printf(a_reply_str, "  Prev cond: %s", l_tx_prev_cond_hash_str);
+            l_item_idx++;
+        }
+        dap_string_append_printf(a_reply_str, "\n");
+    }
+
 }
 
 
@@ -1279,7 +1737,7 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
             }
             uint256_t l_datoshi_buy = dap_chain_balance_scan(l_val_buy_str);
             if (IS_ZERO_256(l_datoshi_buy)) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -coins <unsigned long long>");
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -coins <unsigned int256>");
                 return -9;
             }
             dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_find_by_hash_str(l_net, l_order_hash_str);
@@ -1290,11 +1748,11 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
                     return -13;
                 }
                 // Create conditional transaction
+                dap_chain_hash_fast_from_str(l_order_hash_str, &l_price->order_hash);
                 dap_chain_datum_tx_t *l_tx = s_xchange_tx_create_exchange(l_price, l_wallet, l_datoshi_buy);
-                if (l_tx && s_xchange_tx_put(l_tx, l_net)) {
-                    // TODO send request to seller to update / delete order & price
+                if (l_tx && s_xchange_tx_put(l_tx, l_net) &&
+                        dap_hash_fast_is_blank(&l_price->order_hash))
                     dap_chain_net_srv_order_delete_by_hash_str_sync(l_price->net, l_order_hash_str);
-                }
                 DAP_DELETE(l_price);
                 DAP_DELETE(l_order);
                 dap_cli_server_cmd_set_reply_text(a_str_reply, l_tx ? "Exchange transaction has done" :
@@ -1421,9 +1879,9 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
 
                     // Find SRV_XCHANGE out_cond item
                     int l_prev_cond_idx = 0;
-                    dap_chain_tx_out_cond_t *l_out_cond_item = dap_chain_datum_tx_out_cond_get(l_datum_tx, &l_prev_cond_idx);
-                    if ( l_out_cond_item && (l_out_cond_item->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE) )
-                    {
+                    dap_chain_tx_out_cond_t *l_out_cond_item = dap_chain_datum_tx_out_cond_get(l_datum_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE,
+                                                                                               &l_prev_cond_idx);
+                    if (l_out_cond_item) {
                         uint256_t l_value_from = l_out_cond_item->header.value;
                         uint256_t l_value_to = l_out_cond_item->subtype.srv_xchange.buy_value;
                         char *l_value_to_str = dap_chain_balance_to_coins(l_value_to);
@@ -1550,13 +2008,14 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
                                 continue;
                             }
                             int l_cond_idx = 0;
-                            dap_chain_tx_out_cond_t *l_out_cond_item = dap_chain_datum_tx_out_cond_get(l_tx, &l_cond_idx);
-                            if(l_out_cond_item && l_out_cond_item->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE &&
+                            dap_chain_tx_out_cond_t *l_out_cond_item = dap_chain_datum_tx_out_cond_get(l_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE,
+                                                                                                       &l_cond_idx);
+                            if (l_out_cond_item &&
                                     dap_chain_ledger_tx_hash_is_used_out_item(l_net->pub.ledger, l_tx_hash, l_cond_idx)) {
                                 uint256_t l_value_sell = l_out_cond_item->header.value;
                                 uint256_t l_value_buy = l_out_cond_item->subtype.srv_xchange.buy_value;
                                 if( l_direction == 1){
-                                    if(compare256(l_value_sell,uint256_0) !=0 ){
+                                    if (!IS_ZERO_256(l_value_sell)) {
                                         DIV_256_COIN(l_value_buy, l_value_sell, &l_rate);
                                         if(SUM_256_256(l_rate, l_total_rates, &l_total_rates )!= 0)
                                             log_it(L_ERROR, "Overflow on avarage price calculation (summing)");
@@ -1565,7 +2024,7 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
                                         log_it(L_ERROR, "Sell value is 0 in avarage price calculation (summing)");
                                     }
                                 }else if (l_direction == -1){
-                                    if(compare256(l_value_buy,uint256_0) !=0 ){
+                                    if (!IS_ZERO_256(l_value_buy)) {
                                         DIV_256_COIN(l_value_sell, l_value_buy, &l_rate);
                                         if(SUM_256_256(l_rate, l_total_rates, &l_total_rates )!= 0)
                                             log_it(L_ERROR, "Overflow on avarage price calculation (summing)");
@@ -1583,10 +2042,10 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
                     }
                     dap_list_free_full(l_tx_cond_list, NULL);
                     uint256_t l_rate_average = {0};
-                    if( compare256(l_total_rates_count, uint256_0) != 0 )
+                    if (!IS_ZERO_256(l_total_rates_count))
                         DIV_256(l_total_rates,l_total_rates_count,&l_rate_average);
 
-                    if( compare256(l_total_rates_count, uint256_0) != 0 )
+                    if (!IS_ZERO_256(l_total_rates_count))
                         DIV_256(l_total_rates,l_total_rates_count,&l_rate_average);
 
                     char *l_rate_average_str = dap_chain_balance_to_coins(l_rate_average);
@@ -1625,7 +2084,6 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
                             }
 
                             // Check if output is spent
-                            int l_cond_idx = 0;
                             dap_chain_tx_out_cond_t *l_out_cond_item = l_cur->out_cond;
                             if(l_out_cond_item && l_cur->tx_next) {
 
@@ -1691,7 +2149,11 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
                     *a_str_reply = dap_string_free(l_reply_str, false);
                     break;
 
-                }break;
+                } else {
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Unrecognized subcommand '%s'",
+                                                      l_price_subcommand);
+                    return -38;
+                }
             }
 
             const char * l_list_subcommand = NULL;
@@ -1701,7 +2163,7 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, char **a_str_reply)
                     dap_string_t *l_reply_str = dap_string_new("");
                     char ** l_tickers = NULL;
                     size_t l_tickers_count = 0;
-                    dap_chain_ledger_addr_get_token_ticker_all(l_net->pub.ledger,NULL,&l_tickers,&l_tickers_count);
+                    dap_chain_ledger_addr_get_token_ticker_all( l_net->pub.ledger,NULL,&l_tickers,&l_tickers_count);
 
                     size_t l_pairs_count = 0;
                     if(l_tickers){
diff --git a/modules/service/xchange/include/dap_chain_net_srv_xchange.h b/modules/service/xchange/include/dap_chain_net_srv_xchange.h
index 06b7b15e348f3ea75e660312457ed25955f8232b..cbc65a355f1660c140d2546c1bd5b08797693885 100644
--- a/modules/service/xchange/include/dap_chain_net_srv_xchange.h
+++ b/modules/service/xchange/include/dap_chain_net_srv_xchange.h
@@ -36,7 +36,9 @@ typedef struct dap_chain_net_srv_xchange_price {
     uint256_t datoshi_sell;
     dap_chain_net_t *net;
     char token_buy[DAP_CHAIN_TICKER_SIZE_MAX];
+    uint256_t datoshi_buy;
     uint256_t rate;
+    uint256_t fee;
     dap_chain_hash_fast_t tx_hash;
     dap_chain_hash_fast_t order_hash;
     dap_enc_key_t *wallet_key;
@@ -44,9 +46,9 @@ typedef struct dap_chain_net_srv_xchange_price {
 
 typedef struct dap_srv_xchange_order_ext {
     uint64_t padding;
-    uint256_t datoshi_sell;
-    char token_sell[DAP_CHAIN_TICKER_SIZE_MAX];
-} dap_srv_xchange_order_ext_t;
+    uint256_t datoshi_buy;
+    char token_buy[DAP_CHAIN_TICKER_SIZE_MAX];
+} DAP_ALIGN_PACKED dap_srv_xchange_order_ext_t;
 
 typedef struct dap_chain_net_srv_xchange {
     dap_chain_net_srv_t *parent;
@@ -57,4 +59,3 @@ extern const dap_chain_net_srv_uid_t c_dap_chain_net_srv_xchange_uid;
 
 int dap_chain_net_srv_xchange_init();
 void dap_chain_net_srv_xchange_deinit();
-bool dap_chain_net_srv_xchange_verificator(dap_ledger_t * a_ledger, dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner);
diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index c762017a3767df85780cb37c9b0bdbf0debdd440..9fc5f3c5554ee1c339b741252d49db5a68c4ca47 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -131,7 +131,7 @@ static size_t s_callback_add_datums(dap_chain_t * a_chain, dap_chain_datum_t **
 
 static void s_callback_cs_blocks_purge(dap_chain_t *a_chain);
 
-static void s_new_block_delete(dap_chain_cs_blocks_t *a_blocks);
+static dap_chain_block_t *s_new_block_move(dap_chain_cs_blocks_t *a_blocks, size_t *a_new_block_size);
 
 //Work with atoms
 static size_t s_callback_count_atom(dap_chain_t *a_chain);
@@ -226,13 +226,7 @@ int dap_chain_cs_blocks_new(dap_chain_t * a_chain, dap_config_t * a_chain_config
     a_chain->callback_count_atom = s_callback_count_atom;
     a_chain->callback_get_atoms = s_callback_get_atoms;
 
-
-    //dap_strdup_printf("%s.chain-%s.%s",l_net->pub.gdb_groups_prefix,l_chain->name,c_mempool_group_str);
-    //l_cs_blocks->gdb_group_datums_queue = "local.datums-queue.";
-    dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
-    l_cs_blocks->gdb_group_datums_queue = dap_strdup_printf("local.datums-queue.chain-%s.%s",
-                                                        l_net->pub.gdb_groups_prefix, a_chain->name);
-    l_cs_blocks->callback_new_block_del = s_new_block_delete;
+    l_cs_blocks->callback_new_block_move = s_new_block_move;
 
     dap_chain_cs_blocks_pvt_t *l_cs_blocks_pvt = DAP_NEW_Z(dap_chain_cs_blocks_pvt_t);
     l_cs_blocks->_pvt = l_cs_blocks_pvt;
@@ -446,33 +440,26 @@ static int s_cli_blocks(int a_argc, char ** a_argv, char **a_str_reply)
             dap_chain_datum_t * l_datum = (dap_chain_datum_t*) dap_global_db_get_sync(l_gdb_group_mempool, l_subcmd_str_arg ,
                                                                                               &l_datum_size, NULL, NULL);
             l_datums[0] = l_datum;
-            if ( s_callback_add_datums(l_chain,l_datums,l_datums_count ) == l_datums_count ){
-                for ( size_t i = 0; i <l_datums_count; i++){
-                    dap_chain_hash_fast_t l_datum_hash;
-                    dap_hash_fast(l_datums[i],dap_chain_datum_size(l_datums[i]),&l_datum_hash);
-                    char * l_datums_datum_hash_str = dap_chain_hash_fast_to_str_new(&l_datum_hash);
-
-                    if ( dap_global_db_del_sync( l_gdb_group_mempool, l_datums_datum_hash_str) == 0 ){
-                       dap_cli_server_cmd_set_reply_text(a_str_reply,
-                                                         "Converted datum %s from mempool to event in the new forming round ",
-                                                         l_datums_datum_hash_str);
-                       DAP_DELETE(l_datums_datum_hash_str);
-                       ret = 0;
-                   }else {
-                       dap_cli_server_cmd_set_reply_text(a_str_reply,
-                                                         "Warning! Can't delete datum %s from mempool after conversion to event in the new forming round ",
-                                                         l_datums_datum_hash_str);
-                       ret = 1;
-                   }
+            for (size_t i = 0; i < l_datums_count; i++) {
+                dap_chain_hash_fast_t l_datum_hash = { };
+                dap_hash_fast(l_datums[i],dap_chain_datum_size(l_datums[i]),&l_datum_hash);
+                char *l_datums_datum_hash_str = dap_chain_hash_fast_to_str_new(&l_datum_hash);
+                bool l_err = dap_chain_node_mempool_process(l_chain, l_datums[i]);
+                if (l_err) {
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! Datum %s doesn't pass verifications, examine node log files",
+                                                      l_datums_datum_hash_str);
+                    ret = -9;
+                } else {
+                   log_it(L_INFO, "Pass datum %s from mempool to block in the new forming round ",
+                                                     l_datums_datum_hash_str);
+                   ret = 0;
                 }
-            }else {
-                dap_cli_server_cmd_set_reply_text(a_str_reply,
-                        "Warning! Can't convert datum %s from mempool to the new forming block's section  ", l_subcmd_str_arg);
-                ret = -13;
+                DAP_DELETE(l_datums_datum_hash_str);
+                if (l_err)
+                    break;
             }
-
-            DAP_DELETE(l_gdb_group_mempool);
-        }break;
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "All datums processed");
+        } break;
 
         case SUBCMD_NEW_COMPLETE:{
             dap_chain_net_sync_all(l_net);
@@ -495,7 +482,7 @@ static int s_cli_blocks(int a_argc, char ** a_argv, char **a_str_reply)
                     time_t l_ts_reated = (time_t) l_block->hdr.ts_created;
                      // Header
                     dap_string_append_printf(l_str_tmp,"Block %s:\n", l_subcmd_str_arg);
-                    dap_string_append_printf(l_str_tmp,"\t\t\tversion: 0x%04hX\n",l_block->hdr.version);
+                    dap_string_append_printf(l_str_tmp, "\t\t\tversion: 0x%04X\n", l_block->hdr.version);
                     dap_string_append_printf(l_str_tmp,"\t\t\tcell_id: 0x%016"DAP_UINT64_FORMAT_X"\n",l_block->hdr.cell_id.uint64);
                     dap_string_append_printf(l_str_tmp,"\t\t\tchain_id: 0x%016"DAP_UINT64_FORMAT_X"\n",l_block->hdr.chain_id.uint64);
                     ctime_r(&l_ts_reated, buf);
@@ -674,38 +661,31 @@ static int s_add_atom_to_ledger(dap_chain_cs_blocks_t * a_blocks, dap_ledger_t *
                    a_block_cache->block_hash_str, l_block_offset,l_datum_size );
             break;
         }
-        int l_res = dap_chain_datum_add(a_blocks->chain, l_datum,l_datum_size );
-        if(l_res == 0 ){
-            switch (l_datum->header.type_id) {
-                case DAP_CHAIN_DATUM_TX: {
-                    dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t*) l_datum->data;
-                    // Check tx correcntess
-                    size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx);
-
-                    // Save tx hash -> block_hash link in hash table
-                    dap_chain_tx_block_index_t * l_tx_block= DAP_NEW_Z(dap_chain_tx_block_index_t);
-                    l_tx_block->ts_added = time(NULL);
-                    l_tx_block->block_hash = a_block_cache->block_hash;
-                    dap_hash_fast(l_tx, l_tx_size, &l_tx_block->tx_hash);
-                    pthread_rwlock_wrlock( &PVT(a_blocks)->rwlock );
-                    HASH_ADD(hh, PVT(a_blocks)->tx_block_index, tx_hash, sizeof(l_tx_block->tx_hash), l_tx_block);
-                    pthread_rwlock_unlock( &PVT(a_blocks)->rwlock );
-                } break;
-            }
+        dap_hash_fast_t l_tx_hash;
+        int l_res = dap_chain_datum_add(a_blocks->chain, l_datum, l_datum_size, &l_tx_hash);
+        if (!l_res) {
             l_ret++;
+            if (l_datum->header.type_id == DAP_CHAIN_DATUM_TX) {
+                // Save tx hash -> block_hash link in hash table
+                dap_chain_tx_block_index_t * l_tx_block= DAP_NEW_Z(dap_chain_tx_block_index_t);
+                l_tx_block->ts_added = time(NULL);
+                l_tx_block->block_hash = a_block_cache->block_hash;
+                l_tx_block->tx_hash = l_tx_hash;
+                pthread_rwlock_wrlock( &PVT(a_blocks)->rwlock );
+                HASH_ADD(hh, PVT(a_blocks)->tx_block_index, tx_hash, sizeof(l_tx_block->tx_hash), l_tx_block);
+                pthread_rwlock_unlock( &PVT(a_blocks)->rwlock );
+            }
         } else {
-            char l_time_str[256];
-            l_time_str[0] = '\0';
-            dap_time_to_str_rfc822(l_time_str, sizeof(l_time_str)-1, l_datum->header.ts_create );
-            log_it(L_WARNING, "Can't load datum #%zu %s with hash %s from block %s to ledger: code %d", i,
-                   dap_chain_datum_type_id_to_str(l_datum->header.type_id ), l_time_str,
-                                      a_block_cache->block_hash_str, l_res);
-            break;
+            /* @RRL: disabled due spaming ...
+            debug_if(s_debug_more, L_ERROR, "Can't load datum #%zu (%s) from block %s to ledger: code %d", i,
+                     dap_chain_datum_type_id_to_str(l_datum->header.type_id), a_block_cache->block_hash_str, l_res);
+            */
         }
     }
     return l_ret;
 }
 
+
 /**
  * @brief s_add_atom_to_blocks
  * @param a_blocks
@@ -724,7 +704,8 @@ static int s_add_atom_to_blocks(dap_chain_cs_blocks_t * a_blocks, dap_ledger_t *
         pthread_rwlock_unlock( &PVT(a_blocks)->rwlock );
         res = s_add_atom_to_ledger(a_blocks, a_ledger, a_block_cache);
         debug_if(s_debug_more, L_DEBUG, "Block %s checked, %s", a_block_cache->block_hash_str,
-                                                                res ? "but ledger declined" : "all correct");
+                                                                res == (int)a_block_cache->datum_count ?
+                                                                "all correct" : "but ledger declined");
         //All correct, no matter for result
         pthread_rwlock_wrlock( &PVT(a_blocks)->rwlock );
         HASH_ADD(hh, PVT(a_blocks)->blocks,block_hash,sizeof (a_block_cache->block_hash), a_block_cache);
@@ -860,14 +841,15 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
              log_it(L_DEBUG, "... error adding (code %d)", l_consensus_check);
              ret = ATOM_REJECT;
         }
+         // !TODO make chunks add to blocks
     }else if(ret == ATOM_MOVE_TO_THRESHOLD){
         dap_chain_block_chunks_add( PVT(l_blocks)->chunks,l_block_cache);
-        dap_chain_block_chunks_sort(PVT(l_blocks)->chunks);
+        //dap_chain_block_chunks_sort(PVT(l_blocks)->chunks);
     }else if (ret == ATOM_REJECT ){
         DAP_DELETE(l_block_cache);
     }
 
-    s_bft_consensus_setup(l_blocks);
+    //s_bft_consensus_setup(l_blocks);
     return ret;
 }
 
@@ -1096,12 +1078,12 @@ static dap_chain_atom_ptr_t s_callback_atom_iter_get_next( dap_chain_atom_iter_t
             *a_atom_size = l_cur_cache->block_size;
         return l_cur_cache->block;
     }
-    else {
-        a_atom_iter->cur = NULL;
-        a_atom_iter->cur_size = 0;
-        a_atom_iter->cur_hash = NULL;
-        return NULL;
-    }
+    a_atom_iter->cur = NULL;
+    a_atom_iter->cur_size = 0;
+    a_atom_iter->cur_hash = NULL;
+    if (a_atom_size)
+        *a_atom_size = 0;
+    return NULL;
 }
 
 /**
@@ -1172,38 +1154,22 @@ static void s_callback_atom_iter_delete(dap_chain_atom_iter_t * a_atom_iter )
     DAP_DELETE(a_atom_iter);
 }
 
-static void s_new_block_delete(dap_chain_cs_blocks_t *a_blocks) {
+static dap_chain_block_t *s_new_block_move(dap_chain_cs_blocks_t *a_blocks, size_t *a_new_block_size)
+{
+    size_t l_ret_size = 0;
+    dap_chain_block_t *l_ret = NULL;
     dap_chain_cs_blocks_pvt_t *l_blocks_pvt = PVT(a_blocks);
     pthread_rwlock_wrlock(&l_blocks_pvt->datums_lock);
     if ( a_blocks->block_new ) {
-        DAP_DEL_Z(a_blocks->block_new);
+        l_ret = a_blocks->block_new;
+        l_ret_size = a_blocks->block_new_size;
+        a_blocks->block_new = NULL;
         a_blocks->block_new_size = 0;
     }
     pthread_rwlock_unlock(&l_blocks_pvt->datums_lock);
-}
-
-static int s_new_block_complete(dap_chain_cs_blocks_t *a_blocks)
-{
-    dap_hash_fast_t l_merkle_root = {};     // TODO compute the merkle root of block's datums
-    a_blocks->block_new_size = dap_chain_block_meta_add(&a_blocks->block_new, a_blocks->block_new_size,
-                                                        DAP_CHAIN_BLOCK_META_MERKLE, &l_merkle_root, sizeof(l_merkle_root));
-    size_t l_signed_size = a_blocks->callback_block_sign(a_blocks, &a_blocks->block_new, a_blocks->block_new_size);
-    if (l_signed_size)
-        a_blocks->block_new_size = l_signed_size;
-    else {
-        log_it(L_WARNING, "Block signing failed");
-        return -1;
-    }
-    dap_chain_atom_verify_res_t l_res = s_callback_atom_add(a_blocks->chain, a_blocks->block_new, a_blocks->block_new_size);
-    DAP_DEL_Z(a_blocks->block_new);
-    if (l_res == ATOM_ACCEPT) {
-        if (dap_chain_atom_save(a_blocks->chain, (uint8_t *)a_blocks->block_new, a_blocks->block_new_size, a_blocks->chain->cells->id) < 0) {
-            log_it(L_ERROR, "Can't add new event to the file");
-        }
-        /* TODO add all atoms from treshold */
-        return 0;
-    }
-    return -2;
+    if (a_new_block_size)
+        *a_new_block_size = l_ret_size;
+    return l_ret;
 }
 
 /**
@@ -1216,151 +1182,34 @@ static int s_new_block_complete(dap_chain_cs_blocks_t *a_blocks)
 static size_t s_callback_add_datums(dap_chain_t *a_chain, dap_chain_datum_t **a_datums, size_t a_datums_count)
 {
     dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
-    char *l_gdb_group = l_blocks->gdb_group_datums_queue;
+    dap_chain_cs_blocks_pvt_t *l_blocks_pvt = PVT(l_blocks);
 
     size_t l_datum_processed = 0;
-    for (size_t i = 0; i < a_datums_count; i++) {
-        size_t l_datum_size = dap_chain_datum_size(a_datums[i]);
-        dap_chain_datum_t *l_datum = (dap_chain_datum_t *)a_datums[i];
-        if (!l_datum_size || !l_datum)
-            continue;
-
-        // Verify for correctness
-        dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
-        int l_verify_datum = dap_chain_net_verify_datum_for_add(l_net, l_datum);
-        if (l_verify_datum != 0 &&
-                l_verify_datum != DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS &&
-                l_verify_datum != DAP_CHAIN_CS_VERIFY_CODE_TX_NO_EMISSION &&
-                l_verify_datum != DAP_CHAIN_CS_VERIFY_CODE_TX_NO_TOKEN) {
-            log_it(L_WARNING, "Datum doesn't pass verifications (code %d)",
-                                     l_verify_datum);
+    pthread_rwlock_wrlock(&l_blocks_pvt->datums_lock);
+    for (size_t i = 0; i < a_datums_count; ++i) {
+        dap_chain_datum_t *l_datum = a_datums[i];
+        size_t l_datum_size = dap_chain_datum_size(l_datum);
+        if (!l_datum_size) {
+            log_it(L_WARNING, "Empty datum"); /* How might it be? */
             continue;
         }
-
-		//Check minimum commission
-		bool tx_commission_valid = true;
-		if (l_datum->header.type_id == DAP_CHAIN_DATUM_TX) {
-			dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_datum->data;
-			uint32_t l_tx_items_count = 0;
-			uint32_t l_tx_items_size = l_tx->header.tx_items_size;
-			size_t l_item_tx_size = 0;
-			uint8_t *item = NULL;
-			while (l_tx_items_count < l_tx_items_size)
-			{
-				item = l_tx->tx_items + l_tx_items_count;
-				l_item_tx_size = dap_chain_datum_item_tx_get_size(item);
-				if(	dap_chain_datum_tx_item_get_type(item) == TX_ITEM_TYPE_OUT_COND
-				&&	((dap_chain_tx_out_cond_t*)item)->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) {
-					if (compare256(((dap_chain_tx_out_cond_t*)item)->header.value, a_chain->minimum_commission) == -1)
-						tx_commission_valid = false;
-				}
-
-				l_tx_items_count += l_item_tx_size;
-				if(!l_item_tx_size)
-					break;
-			}
-		}
-		if (!tx_commission_valid)
-			continue;
-
-        dap_chain_hash_fast_t l_key_hash;
-        dap_hash_fast(l_datum, l_datum_size, &l_key_hash);
-        char *l_key_str = dap_chain_hash_fast_to_str_new(&l_key_hash);
-
-        if (dap_global_db_set(l_gdb_group, l_key_str, l_datum, l_datum_size,true, NULL, NULL ) ==0 ) {
-            l_datum_processed++;
+        if (l_blocks->block_new_size + l_datum_size > l_blocks_pvt->block_size_maximum) {
+            log_it(L_DEBUG, "Maximum size exeeded, %zu > %zu", l_blocks->block_new_size + l_datum_size, l_blocks_pvt->block_size_maximum);
+            break;
         }
-    }
-    return l_datum_processed;
-}
-
-/**
- * @brief blocks async operations arguments
- * @param blocks Consensus blocks object
- */
-struct op_results_args{
-    dap_chain_cs_blocks_t * blocks;
-    dap_chain_cs_blocks_callback_op_results_t callback_op_results;
-    void * callback_arg;
-};
-
-
-static bool s_callback_new_block_add_datums (dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const size_t a_values_total,  const size_t a_values_shift,
-                                                  const size_t a_values_count, dap_global_db_obj_t * a_values, void * a_arg)
-{
-    struct op_results_args *l_args = (struct op_results_args *) a_arg;
-    dap_chain_cs_blocks_t *l_blocks = l_args->blocks;
-    dap_chain_t * l_chain = l_blocks->chain;
-    dap_chain_cs_blocks_pvt_t *l_blocks_pvt = PVT(l_blocks);
-
-    pthread_rwlock_wrlock(&l_blocks_pvt->datums_lock);
-
-    if (a_values_count) {
-        for (size_t i = 0; i < a_values_count; i++) {
-            dap_chain_datum_t *l_datum = (dap_chain_datum_t *)a_values[i].value;
-            size_t l_datum_size = dap_chain_datum_size(l_datum);
-            if (l_blocks->block_new_size + l_datum_size > l_blocks_pvt->block_size_maximum)
-                break;
-            dap_global_db_del_unsafe(a_global_db_context, a_values[i].key, a_group); // delete from datums queue
-            if (!a_values[i].key || !a_values[i].value || !a_values[i].value_len) {
-                log_it(L_WARNING, "DB object field in block new queue comes NULL");
-                continue;
-            }
-            if (!l_datum_size) {
-                log_it(L_WARNING, "Datum size in block new queue comes NULL");
-                continue;
-            }
-            // Verify for correctness
-            dap_chain_net_t *l_net = dap_chain_net_by_id(l_chain->net_id);
-            int l_verify_datum = dap_chain_net_verify_datum_for_add(l_net, l_datum);
-            if (l_verify_datum != 0 &&
-                    l_verify_datum != DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS &&
-                    l_verify_datum != DAP_CHAIN_CS_VERIFY_CODE_TX_NO_EMISSION &&
-                    l_verify_datum != DAP_CHAIN_CS_VERIFY_CODE_TX_NO_TOKEN) {
-                log_it(L_WARNING, "Datum doesn't pass verifications (code %d)",
-                                         l_verify_datum);
-                continue;
-            }
-
-            if (!l_blocks->block_new) {
-                l_blocks->block_new = dap_chain_block_new(&l_blocks_pvt->block_cache_last->block_hash, &l_blocks->block_new_size);
-                l_blocks->block_new->hdr.cell_id.uint64 = l_chain->cells->id.uint64;
-                l_blocks->block_new->hdr.chain_id.uint64 = l_blocks->chain->id.uint64;
-            }
-
-            l_blocks->block_new_size = dap_chain_block_datum_add(&l_blocks->block_new, l_blocks->block_new_size,
-                                                                    l_datum, l_datum_size);
+        if (!l_blocks->block_new) {
+            l_blocks->block_new = dap_chain_block_new(&l_blocks_pvt->block_cache_last->block_hash, &l_blocks->block_new_size);
+            l_blocks->block_new->hdr.cell_id.uint64 = a_chain->cells->id.uint64;
+            l_blocks->block_new->hdr.chain_id.uint64 = l_blocks->chain->id.uint64;
         }
-    }
-    pthread_rwlock_unlock(&l_blocks_pvt->datums_lock);
-    l_args->callback_op_results( l_args->blocks,0, l_args->callback_arg);
-    DAP_DELETE(l_args);
-    return true;
-}
 
-
-/**
- * @brief Create new block and add datums from block's queue
- * @param a_chain Chain object
- * @param a_callback_op_results Executes after request completed
- * @param a_arg Custom argument
- */
-void dap_chain_cs_new_block_add_datums(dap_chain_t *a_chain, dap_chain_cs_blocks_callback_op_results_t a_callback_op_results, void * a_arg )
-{
-    dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
-
-    struct op_results_args * l_args = DAP_NEW_Z(struct op_results_args);
-    l_args->blocks = l_blocks;
-    l_args->callback_op_results = a_callback_op_results;
-    l_args->callback_arg = a_arg;
-    if( dap_global_db_get_all(l_blocks->gdb_group_datums_queue,0,s_callback_new_block_add_datums, l_args ) != 0 ){
-        log_it(L_ERROR, "Can't execute get_all gdb request for dap_chain_cs_new_block_add_datums() function");
-        DAP_DELETE(l_args);
+        l_blocks->block_new_size = dap_chain_block_datum_add(&l_blocks->block_new, l_blocks->block_new_size, l_datum, l_datum_size);
+        l_datum_processed++;
     }
-
+    pthread_rwlock_unlock(&l_blocks_pvt->datums_lock);
+    return l_datum_processed;
 }
 
-
 /**
  * @brief s_callback_count_atom Gets the number of blocks
  * @param a_chain Chain object
@@ -1372,7 +1221,6 @@ static size_t s_callback_count_atom(dap_chain_t *a_chain){
     return l_blocks_pvt->blocks_count;
 }
 
-
 /**
  * @brief s_callback_get_atoms Gets the specified number of blocks with an offset
  * @param a_chain Chain object
@@ -1385,6 +1233,9 @@ static dap_list_t *s_callback_get_atoms(dap_chain_t *a_chain, size_t a_count, si
 {
     dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
     dap_chain_cs_blocks_pvt_t *l_blocks_pvt = PVT(l_blocks);
+    if (!l_blocks_pvt->blocks) {
+        return NULL;
+    }
     size_t l_offset = a_count * (a_page - 1);
     size_t l_count = l_blocks_pvt->blocks_count;
     if (a_page < 2)
@@ -1395,9 +1246,7 @@ static dap_list_t *s_callback_get_atoms(dap_chain_t *a_chain, size_t a_count, si
     dap_list_t *l_list = NULL;
     size_t l_counter = 0;
     size_t l_end = l_offset + a_count;
-    if (!l_blocks_pvt->blocks) {
-        return NULL;
-    }
+
     if (a_reverse) {
         dap_chain_block_cache_t *l_ptr = l_blocks_pvt->blocks->hh.tbl->tail->prev;
         if (!l_ptr)
diff --git a/modules/type/blocks/include/dap_chain_cs_blocks.h b/modules/type/blocks/include/dap_chain_cs_blocks.h
index 2bcebb989f66ce878e59460b0b7ec115f2adde51..fa654cce8118eee0157ee63ab79a4667b97276fe 100644
--- a/modules/type/blocks/include/dap_chain_cs_blocks.h
+++ b/modules/type/blocks/include/dap_chain_cs_blocks.h
@@ -33,7 +33,7 @@ typedef void (*dap_chain_cs_blocks_callback_t)(dap_chain_cs_blocks_t *);
 typedef void (*dap_chain_cs_blocks_callback_op_results_t)(dap_chain_cs_blocks_t * a_cs_blocks, int a_rc, void * a_arg);
 typedef int (*dap_chain_cs_blocks_callback_block_t)(dap_chain_cs_blocks_t *, dap_chain_block_t *, size_t);
 typedef size_t (*dap_chain_cs_blocks_callback_block_sign_t)(dap_chain_cs_blocks_t *, dap_chain_block_t **, size_t);
-
+typedef dap_chain_block_t *(*dap_chain_cs_block_move_t)(dap_chain_cs_blocks_t *, size_t *);
 typedef dap_chain_block_t * (*dap_chain_cs_blocks_callback_block_create_t)(dap_chain_cs_blocks_t *,
                                                                                dap_chain_datum_t *,
                                                                                dap_chain_hash_fast_t *,
@@ -50,7 +50,7 @@ typedef struct dap_chain_cs_blocks
    dap_chain_cs_blocks_callback_block_create_t callback_block_create;
    dap_chain_cs_blocks_callback_block_t callback_block_verify;
    dap_chain_cs_blocks_callback_block_sign_t callback_block_sign;
-   dap_chain_cs_blocks_callback_t callback_new_block_del;
+   dap_chain_cs_block_move_t callback_new_block_move;
 
    void * _pvt;
    void * _inheritor;
@@ -64,6 +64,3 @@ void dap_chain_cs_blocks_deinit();
 
 int dap_chain_cs_blocks_new(dap_chain_t * a_chain, dap_config_t * a_chain_config);
 void dap_chain_cs_blocks_delete(dap_chain_t * a_chain);
-
-void dap_chain_cs_new_block_add_datums(dap_chain_t *a_chain,dap_chain_cs_blocks_callback_op_results_t a_callback_op_results, void * a_arg);
-
diff --git a/modules/type/dag/dap_chain_cs_dag.c b/modules/type/dag/dap_chain_cs_dag.c
index 3690f5bb49fcbb2c679d47dfa996db78e0c04a70..735e3ca797b3d5875e11689ed4cb2459b3259e26 100644
--- a/modules/type/dag/dap_chain_cs_dag.c
+++ b/modules/type/dag/dap_chain_cs_dag.c
@@ -73,6 +73,7 @@ typedef struct dap_chain_cs_dag_pvt {
     dap_chain_cs_dag_event_item_t * events_treshold;
     dap_chain_cs_dag_event_item_t * events_treshold_conflicted;
     dap_chain_cs_dag_event_item_t * events_lasts_unlinked;
+    dap_interval_timer_t mempool_timer;
 } dap_chain_cs_dag_pvt_t;
 
 #define PVT(a) ((dap_chain_cs_dag_pvt_t *) a->_pvt )
@@ -283,6 +284,7 @@ int dap_chain_cs_dag_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
     byte_t *l_current_round = dap_global_db_get_sync(l_gdb_group, DAG_ROUND_CURRENT_KEY, NULL, NULL, NULL);
     l_dag->round_current = l_current_round? *(uint64_t *)l_current_round : 0;
     DAP_DELETE(l_current_round);
+    PVT(l_dag)->mempool_timer = dap_interval_timer_create(5000, (dap_timer_callback_t)dap_chain_node_mempool_process_all, a_chain);
     if (l_dag->is_single_line)
         log_it (L_NOTICE, "DAG chain initialized (single line)");
     else
@@ -334,7 +336,7 @@ void dap_chain_cs_dag_delete(dap_chain_t * a_chain)
     s_dap_chain_cs_dag_purge(a_chain);
     dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG ( a_chain );
     pthread_rwlock_destroy(& PVT(l_dag)->events_rwlock);
-
+    dap_interval_timer_delete(PVT(l_dag)->mempool_timer);
     if(l_dag->callback_delete )
         l_dag->callback_delete(l_dag);
     if(l_dag->_inheritor)
@@ -357,33 +359,27 @@ static int s_dap_chain_add_atom_to_ledger(dap_chain_cs_dag_t * a_dag, dap_ledger
         log_it(L_WARNING, "Corrupted event, too big size %zd in header when event's size max is only %zd", l_datum_size, l_datum_size_max);
         return -1;
     }
-    if(dap_chain_datum_add(a_dag->chain,l_datum, l_datum_size) == 0){
+    dap_hash_fast_t l_tx_hash = {};
+    if(dap_chain_datum_add(a_dag->chain,l_datum, l_datum_size, &l_tx_hash) == 0) {
         pthread_rwlock_t * l_events_rwlock = &PVT(a_dag)->events_rwlock;
-        switch (l_datum->header.type_id) {
-            case DAP_CHAIN_DATUM_TX: {
-                dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_datum->data;
-                dap_hash_fast_t l_tx_hash;
-                unsigned l_hash_item_hashv;
-                HASH_VALUE(&l_tx_hash, sizeof(l_tx_hash), l_hash_item_hashv);
-                dap_chain_cs_dag_event_item_t *l_tx_event;
-                int l_err = pthread_rwlock_wrlock(l_events_rwlock);
-                HASH_FIND_BYHASHVALUE(hh, PVT(a_dag)->tx_events, &l_tx_hash, sizeof(l_tx_event->hash),
-                                      l_hash_item_hashv, l_tx_event);
-                if (!l_tx_event) {
-                    l_tx_event = DAP_NEW_Z(dap_chain_cs_dag_event_item_t);
-                    l_tx_event->ts_added    = a_event_item->ts_added;
-                    l_tx_event->event       = a_event_item->event;
-                    l_tx_event->event_size  = a_event_item->event_size;
-                    l_tx_event->hash        = l_tx_hash;
-                    HASH_ADD_BYHASHVALUE(hh, PVT(a_dag)->tx_events, hash, sizeof(l_tx_event->hash),
-                                         l_hash_item_hashv, l_tx_event);
-                }
-                if (l_err != EDEADLK)
-                    pthread_rwlock_unlock(l_events_rwlock);
-            } break;
-            case DAP_CHAIN_DATUM_CA:
-                return DAP_CHAIN_DATUM_CA;
-            default:;
+        if  (l_datum->header.type_id == DAP_CHAIN_DATUM_TX) {
+            unsigned l_hash_item_hashv;
+            HASH_VALUE(&l_tx_hash, sizeof(l_tx_hash), l_hash_item_hashv);
+            dap_chain_cs_dag_event_item_t *l_tx_event;
+            int l_err = pthread_rwlock_wrlock(l_events_rwlock);
+            HASH_FIND_BYHASHVALUE(hh, PVT(a_dag)->tx_events, &l_tx_hash, sizeof(l_tx_event->hash),
+                                  l_hash_item_hashv, l_tx_event);
+            if (!l_tx_event) {
+                l_tx_event = DAP_NEW_Z(dap_chain_cs_dag_event_item_t);
+                l_tx_event->ts_added = a_event_item->ts_added;
+                l_tx_event->event = a_event_item->event;
+                l_tx_event->event_size = a_event_item->event_size;
+                l_tx_event->hash = l_tx_hash;
+                HASH_ADD_BYHASHVALUE(hh, PVT(a_dag)->tx_events, hash, sizeof(l_tx_event->hash),
+                                     l_hash_item_hashv, l_tx_event);
+            }
+            if (l_err != EDEADLK)
+                pthread_rwlock_unlock(l_events_rwlock);
         }
         return 0;
     } else
@@ -477,10 +473,6 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
         break;
     case ATOM_ACCEPT: {
         int l_consensus_check = s_dap_chain_add_atom_to_events_table(l_dag, a_chain->ledger, l_event_item);
-        pthread_rwlock_wrlock(l_events_rwlock);
-        HASH_ADD(hh, PVT(l_dag)->events,hash, sizeof(l_event_item->hash), l_event_item);
-        s_dag_events_lasts_process_new_last_event(l_dag, l_event_item);
-        pthread_rwlock_unlock(l_events_rwlock);
         switch (l_consensus_check) {
         case 0:
             if(s_debug_more)
@@ -504,8 +496,11 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
             if (s_debug_more)
                 log_it(L_WARNING, "... added with ledger code %d", l_consensus_check);
             break;
-
         }
+        pthread_rwlock_wrlock(l_events_rwlock);
+        HASH_ADD(hh, PVT(l_dag)->events,hash, sizeof(l_event_item->hash), l_event_item);
+        s_dag_events_lasts_process_new_last_event(l_dag, l_event_item);
+        pthread_rwlock_unlock(l_events_rwlock);
     } break;
     default:
         DAP_DELETE(l_event_item); // Neither added, nor freed
@@ -548,18 +543,6 @@ static size_t s_callback_add_datums(dap_chain_t *a_chain, dap_chain_datum_t **a_
         if (!l_datum_size || !l_datum)
             continue;
 
-        // Verify for correctness
-        dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
-        int l_verify_datum = dap_chain_net_verify_datum_for_add(l_net, l_datum);
-        if (l_verify_datum != 0 &&
-                l_verify_datum != DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS &&
-                l_verify_datum != DAP_CHAIN_CS_VERIFY_CODE_TX_NO_EMISSION &&
-                l_verify_datum != DAP_CHAIN_CS_VERIFY_CODE_TX_NO_TOKEN) {
-            log_it(L_WARNING, "Datum doesn't pass verifications (code %d)",
-                                     l_verify_datum);
-            continue;
-        }
-
         if (s_chain_callback_datums_pool_proc(a_chain, l_datum))
             l_datum_processed++;
     }
@@ -922,14 +905,16 @@ dap_chain_cs_dag_event_item_t* dap_chain_cs_dag_proc_treshold(dap_chain_cs_dag_t
             }
             int l_add_res = s_dap_chain_add_atom_to_events_table(a_dag, a_ledger, l_event_item);
             HASH_DEL(PVT(a_dag)->events_treshold, l_event_item);
-            HASH_ADD(hh, PVT(a_dag)->events, hash, sizeof(l_event_item->hash), l_event_item);
-            s_dag_events_lasts_process_new_last_event(a_dag, l_event_item);
-            res = true;
-            if(s_debug_more) {
-                if (!l_add_res)
-                    log_it(L_INFO, "... moved from treshold to main chains");
-                else
-                    log_it(L_WARNING, "... moved with ledger code %d", l_add_res);
+            if (!l_add_res) {
+                HASH_ADD(hh, PVT(a_dag)->events, hash, sizeof(l_event_item->hash), l_event_item);
+                s_dag_events_lasts_process_new_last_event(a_dag, l_event_item);
+                debug_if(s_debug_more, L_INFO, "... moved from treshold to main chains");
+                res = true;
+            } else {
+                // TODO clear other threshold items linked with this one
+                debug_if(s_debug_more, L_WARNING, "... rejected with ledger code %d", l_add_res);
+                DAP_DELETE(l_event_item->event);
+                DAP_DELETE(l_event_item);
             }
             break;
         } else if (ret == DAP_THRESHOLD_CONFLICTING) {
@@ -1700,9 +1685,7 @@ static int s_cli_dag(int argc, char ** argv, char **a_str_reply)
                 DAP_DELETE(l_round_item);
             }break;
             case SUBCMD_EVENT_LIST:{
-                if( (l_from_events_str == NULL) ||
-                        (strcmp(l_from_events_str,"round.new") == 0) ){
-
+                if (l_from_events_str && strcmp(l_from_events_str,"round.new") == 0) {
                     char * l_gdb_group_events = DAP_CHAIN_CS_DAG(l_chain)->gdb_group_events_round_new;
                     dap_string_t * l_str_tmp = dap_string_new("");
                     if ( l_gdb_group_events ){
@@ -1730,7 +1713,7 @@ static int s_cli_dag(int argc, char ** argv, char **a_str_reply)
                     }
                     dap_cli_server_cmd_set_reply_text(a_str_reply, l_str_tmp->str);
                     dap_string_free(l_str_tmp,false);
-                }else if (l_from_events_str && (strcmp(l_from_events_str,"events") == 0) ){
+                } else if (!l_from_events_str || (strcmp(l_from_events_str,"events") == 0)) {
                     dap_string_t * l_str_tmp = dap_string_new(NULL);
                     pthread_rwlock_rdlock(&PVT(l_dag)->events_rwlock);
                     dap_chain_cs_dag_event_item_t * l_event_item = NULL,*l_event_item_tmp = NULL;
@@ -1889,6 +1872,9 @@ static dap_list_t *s_callback_get_atoms(dap_chain_t *a_chain, size_t a_count, si
     UNUSED(a_reverse);
     dap_chain_cs_dag_t  *l_dag = DAP_CHAIN_CS_DAG(a_chain);
     dap_chain_cs_dag_pvt_t *l_dag_pvt = PVT(l_dag);
+    if (!l_dag_pvt->events) {
+        return NULL;
+    }
     size_t l_offset = a_count * (a_page - 1);
     pthread_rwlock_rdlock(&PVT(l_dag)->events_rwlock);
     size_t l_count = HASH_COUNT(l_dag_pvt->events);
@@ -1900,9 +1886,7 @@ static dap_list_t *s_callback_get_atoms(dap_chain_t *a_chain, size_t a_count, si
     dap_list_t *l_list = NULL;
     size_t l_counter = 0;
     size_t l_end = l_offset + a_count;
-    if (!l_dag_pvt->events){
-        return NULL;
-    }
+
     dap_chain_cs_dag_event_item_t *l_ptr = l_dag_pvt->events->hh.tbl->tail->prev;
     if (!l_ptr)
         l_ptr = l_dag_pvt->events;