diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3c27852a5b13bdd71987627c3d0c6c6fe616e580..2b42568ef18b03473a9a18d2e7fa2eb87093f28c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -111,6 +111,12 @@ if (CELLFRAME_MODULES MATCHES "srv-vpn")
     set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_vpn )
 endif()
 
+# Enable service eXchange
+if (CELLFRAME_MODULES MATCHES "srv-xchange")
+    message("[+] Module 'srv-xchange'")
+    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_xchange )
+endif()
+
 if (WIN32)
     set(CELLFRAME_LIBS ${CELLFRAME_LIBS} KERNEL32 USER32 SHELL32 WINMM GDI32 ADVAPI32
 					 Ole32 Version Imm32 OleAut32 ws2_32 ntdll psapi 
diff --git a/dap-sdk/crypto/src/dap_cert.c b/dap-sdk/crypto/src/dap_cert.c
index fe22a7a369c3961fe352a1955797d10b2d5d5d26..5f5da67741246f0be603313d4a33cf54a2bc8c82 100755
--- a/dap-sdk/crypto/src/dap_cert.c
+++ b/dap-sdk/crypto/src/dap_cert.c
@@ -468,7 +468,10 @@ void dap_cert_dump(dap_cert_t * a_cert)
                 printf("%s\t%u\t%u\t%u\n", l_meta_item->key, l_meta_item->type, l_meta_item->length, *(uint32_t *)l_meta_item->value);
                 break;
             default:
-                printf("%s\t%u\t%u\t0x%016lX\n", l_meta_item->key, l_meta_item->type, l_meta_item->length, *(uint64_t *)l_meta_item->value);
+                l_str = l_meta_item->length ? DAP_NEW_Z_SIZE(char, l_meta_item->length * 2 + 1) : NULL;
+                dap_bin2hex(l_str, l_meta_item->value, l_meta_item->length);
+                printf("%s\t%u\t%u\t%s\n", l_meta_item->key, l_meta_item->type, l_meta_item->length, l_str);
+                DAP_DELETE(l_str);
                 break;
             }
             l_meta_list_item = l_meta_list_item->next;
diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt
index 19026903b6ce517c04a435c744cb06bc802ccad1..0b39d4eb7bde8e6af5bbeec9aaf22674322845ee 100644
--- a/modules/CMakeLists.txt
+++ b/modules/CMakeLists.txt
@@ -76,7 +76,12 @@ if (CELLFRAME_MODULES MATCHES "srv-vpn")
     add_subdirectory(service/vpn)
 endif()
 
+# Service eXchange
+if (CELLFRAME_MODULES MATCHES "srv-xchange")
+    add_subdirectory(service/xchange)
+endif()
+
 # Unit tests
 if( BUILD_TESTS)
     add_subdirectory(test)
-endif()
\ No newline at end of file
+endif()
diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c
index 7c1a1f4f7139c5b60c903e0c48446e5f2eb093cc..af1201fd203562f82a93ddcfb694c3d8b6a625ef 100644
--- a/modules/chain/dap_chain_ledger.c
+++ b/modules/chain/dap_chain_ledger.c
@@ -57,6 +57,15 @@
 
 #define LOG_TAG "dap_chain_ledger"
 
+typedef struct dap_chain_ledger_verificator {
+    int subtype;    // hash key
+    dap_chain_ledger_verificator_callback_t callback;
+    UT_hash_handle hh;
+} dap_chain_ledger_verificator_t;
+
+static dap_chain_ledger_verificator_t *s_verificators;
+static  pthread_rwlock_t s_verificators_rwlock;
+
 #define MAX_OUT_ITEMS   10
 typedef struct dap_chain_ledger_token_emission_item {
     dap_chain_hash_fast_t datum_token_emission_hash;
@@ -102,8 +111,15 @@ typedef struct dap_chain_ledger_tokenizer {
 typedef struct dap_chain_ledger_tx_bound {
     dap_chain_hash_fast_t tx_prev_hash_fast;
     dap_chain_datum_tx_t *tx_prev;
-    dap_chain_tx_in_t *tx_cur_in;
-    dap_chain_tx_out_t *tx_prev_out;
+    union {
+        dap_chain_tx_in_t *tx_cur_in;
+        dap_chain_tx_in_cond_t *tx_cur_in_cond;
+    } in;
+    union {
+        dap_chain_tx_out_t *tx_prev_out;
+        dap_chain_tx_out_ext_t *tx_prev_out_ext;
+        dap_chain_tx_out_cond_t *tx_prev_out_cond;
+    } out;
     dap_chain_ledger_tx_item_t *item_out;
 } dap_chain_ledger_tx_bound_t;
 
@@ -159,6 +175,7 @@ static void s_treshold_txs_proc( dap_ledger_t * a_ledger);
 
 static size_t s_treshold_emissions_max = 1000;
 static size_t s_treshold_txs_max = 10000;
+
 /**
  * Create dap_ledger_t structure
  */
@@ -228,6 +245,23 @@ int dap_chain_ledger_token_decl_add_check(dap_ledger_t * a_ledger,  dap_chain_da
     return 0;
 }
 
+/**
+ * @brief dap_chain_ledger_token_ticker_check
+ * @param a_ledger
+ * @param a_token_ticker
+ * @return
+ */
+int dap_chain_ledger_token_ticker_check(dap_ledger_t * a_ledger, const char *a_token_ticker)
+{
+    if ( !a_ledger){
+        log_it(L_WARNING, "NULL ledger, can't find token ticker");
+        return  -2;
+    }
+    dap_chain_ledger_token_item_t *l_token_item;
+    HASH_FIND_STR(PVT(a_ledger)->tokens, a_token_ticker, l_token_item);
+    return (size_t)l_token_item;
+}
+
 /**
  * @brief dap_chain_ledger_token_add
  * @param a_token
@@ -283,6 +317,7 @@ int dap_chain_ledger_token_add(dap_ledger_t * a_ledger,  dap_chain_datum_token_t
  */
 static void s_treshold_emissions_proc( dap_ledger_t * a_ledger)
 {
+    UNUSED(a_ledger);
     // TODO
 }
 
@@ -292,6 +327,7 @@ static void s_treshold_emissions_proc( dap_ledger_t * a_ledger)
  */
 static void s_treshold_txs_proc( dap_ledger_t * a_ledger)
 {
+    UNUSED(a_ledger);
     // TODO
 }
 
@@ -635,9 +671,11 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
      &&
      3. hash(tx1) == tx2.dap_chain_datump_tx_in.tx_prev_hash
      &&
-     4. tx1.dap_chain_datum_tx_out.addr.data.key == tx2.dap_chain_datum_tx_sig.pkey
+     4. tx1.dap_chain_datum_tx_out.addr.data.key == tx2.dap_chain_datum_tx_sig.pkey for unconditional output
      &&
-     5. sum(  find (tx2.input.tx_prev_hash).output[tx2.input_tx_prev_idx].value )  ==  sum (tx2.outputs.value) per token
+     5. tx1.dap_chain_datum_tx_out.condition == verify_svc_type(tx2) for conditional ouput
+     &&
+     6. sum(  find (tx2.input.tx_prev_hash).output[tx2.input_tx_prev_idx].value )  ==  sum (tx2.outputs.value) per token
      */
 
     dap_ledger_private_t *l_ledger_priv = PVT(a_ledger);
@@ -669,17 +707,35 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
     // ----------------------------------------------------------------
     // find all 'in' items in current transaction
     dap_list_t *l_list_in = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_IN,
-            &l_prev_tx_count);
-    //log_it(L_DEBUG,"Tx check: %d inputs",l_prev_tx_count);
+                                                          &l_prev_tx_count);
+    // find all conditional 'in' items in current transaction
+    dap_list_t *l_list_tmp = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t *)a_tx, TX_ITEM_TYPE_IN_COND,
+                                                          &l_prev_tx_count);
+    if (l_list_tmp) {
+        // add conditional input to common list
+        l_list_in = dap_list_append(l_list_in, l_list_tmp->data);
+        dap_list_free(l_list_tmp);
+    }
+    l_list_tmp = l_list_in;
     dap_chain_ledger_tx_bound_t *bound_item;
     int l_list_tmp_num = 0;
      // find all previous transactions
     for (dap_list_t *l_list_tmp = l_list_in; 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 = (dap_chain_tx_in_t*) l_list_tmp->data;
+        dap_chain_tx_in_t *l_tx_in;
+        dap_chain_tx_in_cond_t *l_tx_in_cond;
+        dap_chain_hash_fast_t l_tx_prev_hash;
+        uint8_t l_cond_type = *(uint8_t *)l_list_tmp->data;
         // one of the previous transaction
-        dap_chain_hash_fast_t l_tx_prev_hash = l_tx_in->header.tx_prev_hash;
-        bound_item->tx_cur_in = l_tx_in;
+        if (l_cond_type == TX_ITEM_TYPE_IN) {
+            l_tx_in = (dap_chain_tx_in_t *)l_list_tmp->data;
+            l_tx_prev_hash = l_tx_in->header.tx_prev_hash;
+            bound_item->in.tx_cur_in = l_tx_in;
+        } else { // TX_ITEM_TYPE_IN_COND
+            l_tx_in_cond = (dap_chain_tx_in_cond_t *)l_list_tmp->data;
+            l_tx_prev_hash = l_tx_in_cond->header.tx_prev_hash;
+            bound_item->in.tx_cur_in_cond = l_tx_in_cond;
+        }
         memcpy(&bound_item->tx_prev_hash_fast, &l_tx_prev_hash, sizeof(dap_chain_hash_fast_t));
 
         bool l_is_blank = dap_hash_fast_is_blank(&l_tx_prev_hash);
@@ -722,14 +778,14 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
             break;
         }
         //log_it(L_INFO,"Previous transaction was found for hash %s",l_tx_prev_hash_str);
-
         bound_item->tx_prev = l_tx_prev;
 
         // 1. Verify signature in previous transaction
         int l_res_sign = dap_chain_datum_tx_verify_sign(l_tx_prev);
 
         // 2. Check if out in previous transaction has spent
-        if (dap_chain_ledger_item_is_used_out(l_item_out, l_tx_in->header.tx_out_prev_idx)) {
+        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;
         }
@@ -744,41 +800,87 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
             break;
         }
         DAP_DELETE(l_hash_prev);
-
+        uint64_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, NULL);
+        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
-        dap_chain_tx_out_t *l_tx_prev_out = dap_list_nth_data(l_list_prev_out, l_tx_in->header.tx_out_prev_idx);
+        void *l_tx_prev_out = dap_list_nth_data(l_list_prev_out, l_idx);
+        dap_list_free(l_list_prev_out);
         if(!l_tx_prev_out) {
             l_err_num = -8;
             break;
         }
-        dap_list_free(l_list_prev_out);
-        bound_item->tx_prev_out = l_tx_prev_out;
-
-        // 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);
+        if (l_cond_type == TX_ITEM_TYPE_IN) {
+            dap_chain_tx_item_type_t l_type = *(uint8_t *)l_tx_prev_out;
+            if (l_type == TX_ITEM_TYPE_OUT) {
+                bound_item->out.tx_prev_out = l_tx_prev_out;
+            } else if (l_type == TX_ITEM_TYPE_OUT_EXT) {
+                bound_item->out.tx_prev_out_ext = l_tx_prev_out;
+            } else {
+                l_err_num = -8;
+                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 = (l_type == TX_ITEM_TYPE_OUT) ?
+                                                bound_item->out.tx_prev_out->addr.data.key :
+                                                bound_item->out.tx_prev_out_ext->addr.data.key;
+                // 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))) {
+                    l_err_num = -9;
+                    break;
+                }
+            }
+            if (l_type == TX_ITEM_TYPE_OUT) {
+                l_value = bound_item->out.tx_prev_out->header.value;
+            } else {
+                l_value = bound_item->out.tx_prev_out_ext->header.value;
+                l_token = bound_item->out.tx_prev_out_ext->token;
+            }
+        } else { // TX_ITEM_TYPE_IN_COND
+            if(*(uint8_t *)l_tx_prev_out != TX_ITEM_TYPE_OUT_COND) {
+                l_err_num = -8;
+                break;
+            }
+            dap_chain_tx_out_cond_t * l_tx_prev_out_cond = (dap_chain_tx_out_cond_t *)l_tx_prev_out;
+            dap_chain_ledger_verificator_t *l_verificator;
+            int l_tmp = (int)l_tx_prev_out_cond->header.subtype;
+            HASH_FIND_INT(s_verificators, &l_tmp, l_verificator);
+            if (!l_verificator || !l_verificator->callback) {
+                log_it(L_ERROR, "No verificator set for conditional output subtype %d", l_tmp);
+                l_err_num = -13;
+                break;
+            }
+            // 5. Call verificator for conditional output
+            if (l_verificator->callback(l_tx_prev_out_cond, a_tx) == false) {
+                l_err_num = -14;
+                break;
+            }
+            bound_item->out.tx_prev_out_cond = l_tx_prev_out_cond;
+            // calculate sum of values from previous transactions
+            l_value = l_tx_prev_out_cond->header.value;
+            l_token = NULL;
         }
-        // hash of public key in 'out' item of previous transaction
-        uint8_t *l_prev_out_addr_key = l_tx_prev_out->addr.data.key;
-
-        // 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))) {
-            l_err_num = -9;
+        if (!l_token || !*l_token) {
+            l_token = l_item_out->token_tiker;
+        }
+        if (!*l_token) {
+            log_it(L_WARNING, "No token ticker found in previous transaction");
+            l_err_num = -15;
             break;
         }
-        l_token = l_item_out->token_tiker;
         HASH_FIND_STR(l_values_from_prev_tx, l_token, l_value_cur);
         if (!l_value_cur) {
             l_value_cur = DAP_NEW_Z(dap_chain_ledger_tokenizer_t);
@@ -786,9 +888,7 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
             HASH_ADD_STR(l_values_from_prev_tx, token_ticker, l_value_cur);
         }
         // calculate sum of values from previous transactions per each token
-        l_value_cur->sum += l_tx_prev_out->header.value;
-        l_value_cur = NULL;
-
+        l_value_cur->sum += l_value;
         l_list_bound_items = dap_list_append(l_list_bound_items, bound_item);
     }
     if (l_list_in)
@@ -804,46 +904,76 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
         return l_err_num;
     }
 
-    // 5. Compare sum of values in 'out' items in the current transaction and in the previous transactions
+    // 6. Compare sum of values in 'out' items in the current transaction and in the previous transactions
     // Calculate the sum of values in 'out' items from the current transaction
-    l_value_cur = DAP_NEW_Z(dap_chain_ledger_tokenizer_t);
-    strcpy(l_value_cur->token_ticker, l_token);
-    HASH_ADD_STR(l_values_from_cur_tx, token_ticker, l_value_cur);
+    bool l_multichannel = false;
+    if (HASH_COUNT(l_values_from_prev_tx) > 1) {
+        l_multichannel = true;
+    } else {
+        l_value_cur = DAP_NEW_Z(dap_chain_ledger_tokenizer_t);
+        strcpy(l_value_cur->token_ticker, l_token);
+        HASH_ADD_STR(l_values_from_cur_tx, token_ticker, l_value_cur);
+    }
     dap_list_t *l_list_tx_out = NULL;
     bool emission_flag = !l_is_first_transaction || (l_is_first_transaction && l_ledger_priv->check_token_emission);
     // 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, NULL);
-    dap_list_t *l_list_tmp = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_OUT_COND, NULL);
-    // accumalate value ​from all 'out' & 'out_cond' transactions
-    if (l_list_tmp) {
-        l_list_out = dap_list_append(l_list_out, l_list_tmp->data);
-    }
+    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);
+    uint64_t l_value;
     for (l_list_tmp = l_list_out; l_list_tmp; l_list_tmp = dap_list_next(l_list_tmp)) {
-        if (*(uint8_t *)l_list_tmp->data == TX_ITEM_TYPE_OUT) {
-            dap_chain_tx_out_t *l_tx_out = (dap_chain_tx_out_t*) l_list_tmp->data;
+        dap_chain_tx_item_type_t l_type = *(uint8_t *)l_list_tmp->data;
+        if (l_type == TX_ITEM_TYPE_OUT)
+        {
+            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 (emission_flag) {
-                l_value_cur->sum += l_tx_out->header.value;
+                 l_value = l_tx_out->header.value;
             }
             l_list_tx_out = dap_list_append(l_list_tx_out, l_tx_out);
-        } else {
-            dap_chain_tx_out_cond_t *l_tx_out = (dap_chain_tx_out_cond_t*) l_list_tmp->data;
+        } else if (l_type == TX_ITEM_TYPE_OUT_EXT) {
+            dap_chain_tx_out_ext_t *l_tx_out = (dap_chain_tx_out_ext_t *)l_list_tmp->data;
+            if (!l_multichannel) { // token ticker is depricated for single-channel transactions
+                l_err_num = -16;
+                break;
+            }
             if (emission_flag) {
-                l_value_cur->sum += l_tx_out->header.value;
+                 l_value = l_tx_out->header.value;
+                 l_token = l_tx_out->token;
             }
             l_list_tx_out = dap_list_append(l_list_tx_out, l_tx_out);
+        } else if (l_type == 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 (emission_flag) {
+                l_value = l_tx_out->header.value;
+            }
+            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;
+            }
+            l_list_tx_out = dap_list_append(l_list_tx_out, l_tx_out);
+        }
+        if (l_multichannel) {
+            HASH_FIND_STR(l_values_from_cur_tx, l_token, l_value_cur);
+            if (!l_value_cur) {
+                l_value_cur = DAP_NEW_Z(dap_chain_ledger_tokenizer_t);
+                strcpy(l_value_cur->token_ticker, l_token);
+                HASH_ADD_STR(l_values_from_cur_tx, token_ticker, l_value_cur);
+            }
         }
+        l_value_cur->sum += l_value;
     }
     if ( l_list_out )
         dap_list_free(l_list_out);
-    l_value_cur = NULL;
 
     // Additional check whether the transaction is first
-    while (l_is_first_transaction) {
+    while (l_is_first_transaction && !l_err_num) {
         if (l_ledger_priv->check_token_emission) { // Check the token emission
             dap_chain_datum_token_emission_t * l_token_emission = dap_chain_ledger_token_emission_find(a_ledger, l_token, l_emission_hash);
             if (l_token_emission) {
-                HASH_FIND_STR(l_values_from_cur_tx, l_token, l_value_cur);
-                if (!l_value_cur || l_token_emission->hdr.value != l_value_cur->sum) {
+                if (l_token_emission->hdr.value != l_value_cur->sum) {
                     l_err_num = -10;
                 }
                 l_value_cur = NULL;
@@ -854,8 +984,7 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
         }
         break;
     }
-
-    while (!l_is_first_transaction) {
+    while (!l_is_first_transaction && !l_err_num) {
         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 || l_res->sum != l_value_cur->sum) {
@@ -940,7 +1069,7 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
     //log_it ( L_INFO, "dap_chain_ledger_tx_add() check passed for tx %s",l_tx_hash_str);
 
 
-    char * l_token_ticker = NULL;
+    char *l_token_ticker = NULL, *l_token_ticker_old = NULL;
     dap_chain_ledger_tx_item_t *l_item_tmp = NULL;
     pthread_rwlock_wrlock(&l_ledger_priv->ledger_rwlock);
     HASH_FIND(hh, l_ledger_priv->ledger_items, l_tx_hash, sizeof(dap_chain_hash_fast_t), l_item_tmp); // tx_hash already in the hash?
@@ -959,34 +1088,57 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
     if (ret == -1) {
         goto FIN;
     }
+    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;
-//    int l_list_tmp_num = 0;
+
+    // Update balance: deducts
     while(l_list_tmp) {
         dap_chain_ledger_tx_bound_t *bound_item = l_list_tmp->data;
-        dap_chain_tx_in_t *l_tx_in = bound_item->tx_cur_in;
+        void *l_item_in = *(void **)&bound_item->in;
+        dap_chain_tx_item_type_t l_type = *(uint8_t *)l_item_in;
         dap_chain_ledger_tx_item_t *l_prev_item_out = bound_item->item_out;
-        if ( l_token_ticker == NULL)
-            l_token_ticker = dap_strdup (l_prev_item_out->token_tiker);
-
-        // Update balance: deducts
-        dap_ledger_wallet_balance_t *wallet_balance = NULL;
-        char *l_addr_str = dap_chain_addr_to_str(&bound_item->tx_prev_out->addr);
-        char *l_wallet_balance_key = dap_strjoin(" ", l_addr_str, l_token_ticker, (char*)NULL);
-        HASH_FIND_STR(PVT(a_ledger)->balance_accounts, l_wallet_balance_key, wallet_balance);
-        if (wallet_balance) {
-            //log_it(L_DEBUG,"SPEND %lu from addr: %s", bound_item->tx_prev_out->header.value, l_wallet_balance_key);
-            wallet_balance->balance -= bound_item->tx_prev_out->header.value;
-        } else {
-            log_it(L_ERROR,"!!! Attempt to SPEND from some non-existent balance !!!: %s %s", l_addr_str, l_token_ticker);
+        if (*l_prev_item_out->token_tiker) {
+            l_token_ticker = l_prev_item_out->token_tiker;
+        } else { // Previous multichannel transaction
+            l_token_ticker = bound_item->out.tx_prev_out_ext->token;
+        }
+        if (!l_multichannel && l_token_ticker_old && strcmp(l_token_ticker, l_token_ticker_old)) {
+            l_multichannel = true;
+        }
+        l_token_ticker_old = l_token_ticker;
+        dap_chain_hash_fast_t *l_tx_prev_hash;
+        if (l_type == TX_ITEM_TYPE_IN) {
+            dap_chain_tx_in_t *l_tx_in = bound_item->in.tx_cur_in;
+            dap_ledger_wallet_balance_t *wallet_balance = NULL;
+            void *l_item_out = *(void **)&bound_item->out;
+            dap_chain_tx_item_type_t l_out_type = *(uint8_t *)l_item_out;
+            dap_chain_addr_t *l_addr = (l_out_type == TX_ITEM_TYPE_OUT) ?
+                                        &bound_item->out.tx_prev_out->addr :
+                                        &bound_item->out.tx_prev_out_ext->addr;
+            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);
+            HASH_FIND_STR(PVT(a_ledger)->balance_accounts, l_wallet_balance_key, wallet_balance);
+            if (wallet_balance) {
+                uint64_t l_value = (l_out_type == TX_ITEM_TYPE_OUT) ?
+                                    bound_item->out.tx_prev_out->header.value :
+                                    bound_item->out.tx_prev_out_ext->header.value;
+                //log_it(L_DEBUG,"SPEND %lu from addr: %s", l_value, l_wallet_balance_key);
+                wallet_balance->balance -= l_value;
+            } else {
+                log_it(L_ERROR,"!!! Attempt to SPEND from some non-existent balance !!!: %s %s", l_addr_str, l_token_ticker);
+            }
+            DAP_DELETE(l_addr_str);
+            DAP_DELETE(l_wallet_balance_key);
+            /// Mark 'out' item in cache because it used
+            l_tx_prev_hash = &(l_prev_item_out->tx_hash_spent_fast[l_tx_in->header.tx_out_prev_idx]);
+        } else { // TX_ITEM_TYPE_IN_COND
+            // all balance deducts performed with previous conditional transaction
+            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_hash = &(l_prev_item_out->tx_hash_spent_fast[l_tx_in_cond->header.tx_out_prev_idx]);
         }
-        DAP_DELETE(l_addr_str);
-        DAP_DELETE(l_wallet_balance_key);
-
-        /// Mark 'out' item in cache because it used
-        dap_chain_hash_fast_t *l_tx_prev_hash =
-                &(l_prev_item_out->tx_hash_spent_fast[l_tx_in->header.tx_out_prev_idx]);
         memcpy(l_tx_prev_hash, l_tx_hash, sizeof(dap_chain_hash_fast_t));
         // add a used output
         l_prev_item_out->n_outs_used++;
@@ -1034,30 +1186,47 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
         if (l_base_tx_count >=1  && l_base_tx_list){
             dap_chain_tx_token_t * l_tx_token =(dap_chain_tx_token_t *) l_base_tx_list->data;
             if ( l_tx_token )
-                l_token_ticker = dap_strdup( l_tx_token->header.ticker);
+                l_token_ticker = l_tx_token->header.ticker;
         }
     }
 
     //Update balance : raise
     for (dap_list_t *l_tx_out = l_list_tx_out; l_tx_out; l_tx_out = dap_list_next(l_tx_out)) {
-        dap_chain_tx_out_t *l_out_item = l_tx_out->data;
+        dap_chain_tx_item_type_t l_type = *(uint8_t *)l_tx_out->data;
+        if (l_type == TX_ITEM_TYPE_OUT_COND) {
+            continue;   // balance raise will be with next conditional transaction
+        }
+        dap_chain_tx_out_t *l_out_item;
+        dap_chain_tx_out_ext_t *l_out_item_ext;
+        if (l_type == TX_ITEM_TYPE_OUT) {
+            l_out_item = l_tx_out->data;
+        } else {
+            l_out_item_ext = l_tx_out->data;
+        }
         if (l_out_item && l_token_ticker) {
-            char *l_addr_str = dap_chain_addr_to_str(&l_out_item->addr);
+             dap_chain_addr_t *l_addr = (l_type == TX_ITEM_TYPE_OUT) ?
+                                        &l_out_item->addr :
+                                        &l_out_item_ext->addr;
+            char *l_addr_str = dap_chain_addr_to_str(l_addr);
             //log_it (L_DEBUG, "Check unspent %.03Lf %s for addr %s",
             //        (long double) l_out_item->header.value/ 1000000000000.0L,
             //        l_token_ticker, l_addr_str);
             dap_ledger_wallet_balance_t *wallet_balance = NULL;
+            if (l_multichannel) {
+                l_token_ticker = l_out_item_ext->token;
+            }
             char *l_wallet_balance_key = dap_strjoin(" ", l_addr_str, l_token_ticker, (char*)NULL);
-            //log_it (L_DEBUG,"\t\tAddr: %s token: %s", l_addr_str, l_token_ticker);
+            uint64_t l_value =  (l_type == TX_ITEM_TYPE_OUT) ? l_out_item->header.value : l_out_item_ext->header.value;
+            //log_it (L_DEBUG,"GOT %lu to addr: %s", l_value, l_wallet_balance_key);
             HASH_FIND_STR(PVT(a_ledger)->balance_accounts, l_wallet_balance_key, wallet_balance);
             if (wallet_balance) {
                 //log_it(L_DEBUG, "Balance item is present in cache");
-                wallet_balance->balance += l_out_item->header.value;
+                wallet_balance->balance += l_value;
                 DAP_DELETE (l_wallet_balance_key);
             } else {
                 wallet_balance = DAP_NEW_Z(dap_ledger_wallet_balance_t);
                 wallet_balance->key = l_wallet_balance_key;
-                wallet_balance->balance += l_out_item->header.value;
+                wallet_balance->balance += l_value;
                 dap_stpcpy(wallet_balance->token_ticker, l_token_ticker);
                 //log_it(L_DEBUG,"!!! Create new balance item: %s %s", l_addr_str, l_token_ticker);
                 HASH_ADD_KEYPTR(hh, PVT(a_ledger)->balance_accounts, wallet_balance->key,
@@ -1098,6 +1267,7 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
             if( l_item_tmp->n_outs){
                 dap_list_t *l_tist_tmp = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_OUT, &l_item_tmp->n_outs);
                 for (size_t i =0; i < (size_t) l_item_tmp->n_outs; i++){
+                    // TODO list conditional outputs
                     dap_chain_tx_out_t * l_tx_out = l_tist_tmp->data;
                     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 );
@@ -1118,8 +1288,8 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
                 dap_list_free(l_tokens_list);
             }
         }
-        if (l_token_ticker)
-            strncpy(l_item_tmp->token_tiker,l_token_ticker,sizeof (l_item_tmp->token_tiker));
+        if (l_token_ticker && !l_multichannel)
+            strncpy(l_item_tmp->token_tiker, l_token_ticker, sizeof(l_item_tmp->token_tiker) - 1);
 
         memcpy(l_item_tmp->tx, a_tx, dap_chain_datum_tx_get_size(a_tx));
         HASH_ADD(hh, l_ledger_priv->ledger_items, tx_hash_fast, sizeof(dap_chain_hash_fast_t), l_item_tmp); // tx_hash_fast: name of key field
@@ -1128,9 +1298,6 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
 FIN:
     pthread_rwlock_tryrdlock (&l_ledger_priv->ledger_rwlock);
     pthread_rwlock_unlock(&l_ledger_priv->ledger_rwlock);
-    if (l_token_ticker) {
-        DAP_DELETE(l_token_ticker);
-    }
     DAP_DELETE(l_tx_hash);
     return ret;
 }
@@ -1258,7 +1425,7 @@ uint64_t dap_chain_ledger_calc_balance(dap_ledger_t *a_ledger, const dap_chain_a
         const char *a_token_ticker)
 {
     uint64_t l_ret = 0;
-    dap_ledger_wallet_balance_t *l_balance_item = NULL ,* l_balance_item_tmp = NULL;
+    dap_ledger_wallet_balance_t *l_balance_item = NULL;// ,* l_balance_item_tmp = NULL;
     char *l_addr = dap_chain_addr_to_str(a_addr);
     char *l_wallet_balance_key = dap_strjoin(" ", l_addr, a_token_ticker, (char*)NULL);
 
@@ -1311,39 +1478,51 @@ uint64_t dap_chain_ledger_calc_balance_full(dap_ledger_t *a_ledger, const dap_ch
     {
         dap_chain_datum_tx_t *l_cur_tx = l_iter_current->tx;
 
-        // Check for token name
-        if(strcmp(a_token_ticker, l_iter_current->token_tiker) == 0) {
-            //        dap_chain_hash_fast_t *l_cur_tx_hash = &l_iter_current->tx_hash_fast;
-            //        int l_n_outs_used = l_iter_current->n_outs_used; // number of used 'out' items
-
-            // Get 'out' items from transaction
-            int l_out_item_count = 0;
-            dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_cur_tx, TX_ITEM_TYPE_OUT, &l_out_item_count);
-            if(l_out_item_count >= MAX_OUT_ITEMS) {
-                log_it(L_ERROR, "Too many 'out' items=%d in transaction (max=%d)", l_out_item_count, MAX_OUT_ITEMS);
-                assert(l_out_item_count < MAX_OUT_ITEMS);
+        //        dap_chain_hash_fast_t *l_cur_tx_hash = &l_iter_current->tx_hash_fast;
+        //        int l_n_outs_used = l_iter_current->n_outs_used; // number of used 'out' items
+
+        // Get 'out' items from transaction
+        int l_out_item_count = 0;
+        dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_cur_tx, TX_ITEM_TYPE_OUT_ALL, &l_out_item_count);
+        if(l_out_item_count >= MAX_OUT_ITEMS) {
+            log_it(L_ERROR, "Too many 'out' items=%d in transaction (max=%d)", l_out_item_count, MAX_OUT_ITEMS);
+            assert(l_out_item_count < MAX_OUT_ITEMS);
+        }
+        int l_out_idx_tmp = 0;
+        for (dap_list_t *l_list_tmp = l_list_out_items; l_list_tmp; l_list_tmp = dap_list_next(l_list_tmp), l_out_idx_tmp++) {
+            assert(l_list_tmp->data);
+            dap_chain_tx_item_type_t l_type = *(uint8_t *)l_list_tmp->data;
+            if (l_type == TX_ITEM_TYPE_OUT_COND) {
+                continue;
             }
-            dap_list_t *l_list_tmp = l_list_out_items;
-            int l_out_idx_tmp = 0;
-            while(l_list_tmp) {
+            if (l_type == TX_ITEM_TYPE_OUT) {
                 const dap_chain_tx_out_t *l_tx_out = (const dap_chain_tx_out_t*) l_list_tmp->data;
-
-                // if transaction has the out item with requested addr
-                if(l_tx_out
-                        && !memcmp(a_addr, &l_tx_out->addr, sizeof(dap_chain_addr_t)
-                                )) {
-                    // if 'out' item not used & transaction is valid
-                    if(!dap_chain_ledger_item_is_used_out(l_iter_current, l_out_idx_tmp) &&
-                            dap_chain_datum_tx_verify_sign(l_cur_tx))
-                        balance += l_tx_out->header.value;
+                // Check for token name
+                if (!strcmp(a_token_ticker, l_iter_current->token_tiker))
+                {   // if transaction has the out item with requested addr
+                    if (!memcmp(a_addr, &l_tx_out->addr, sizeof(dap_chain_addr_t))) {
+                        // if 'out' item not used & transaction is valid
+                        if(!dap_chain_ledger_item_is_used_out(l_iter_current, l_out_idx_tmp) &&
+                                dap_chain_datum_tx_verify_sign(l_cur_tx))
+                            balance += l_tx_out->header.value;
+                    }
+                }
+            }
+            if (l_type == TX_ITEM_TYPE_OUT_EXT) {
+                const dap_chain_tx_out_ext_t *l_tx_out = (const dap_chain_tx_out_ext_t*) l_list_tmp->data;
+                // Check for token name
+                if (!strcmp(a_token_ticker, l_tx_out->token))
+                {   // if transaction has the out item with requested addr
+                    if (!memcmp(a_addr, &l_tx_out->addr, sizeof(dap_chain_addr_t))) {
+                        // if 'out' item not used & transaction is valid
+                        if(!dap_chain_ledger_item_is_used_out(l_iter_current, l_out_idx_tmp) &&
+                                dap_chain_datum_tx_verify_sign(l_cur_tx))
+                            balance += l_tx_out->header.value;
+                    }
                 }
-                // go to the next 'out' item in l_tx_tmp transaction
-                l_out_idx_tmp++;
-
-                l_list_tmp = dap_list_next(l_list_tmp);
             }
-            dap_list_free(l_list_tmp);
         }
+        dap_list_free(l_list_out_items);
     }
     pthread_rwlock_unlock(&l_ledger_priv->ledger_rwlock);
     return balance;
@@ -1370,9 +1549,8 @@ static dap_chain_ledger_tx_item_t* tx_item_find_by_addr(dap_ledger_t *a_ledger,
     HASH_ITER(hh, l_ledger_priv->ledger_items , l_iter_current, l_item_tmp)
     {
         // If a_token is setup we check if its not our token - miss it
-        if (a_token)
-            if ( dap_strcmp(l_iter_current->token_tiker,a_token) !=0 )
-                continue;
+        if (a_token && *l_iter_current->token_tiker && dap_strcmp(l_iter_current->token_tiker, a_token))
+            continue;
         // Now work with it
         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;
@@ -1383,21 +1561,36 @@ static dap_chain_ledger_tx_item_t* tx_item_find_by_addr(dap_ledger_t *a_ledger,
             continue;
         }
         // Get 'out' items from transaction
-        dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT, NULL);
-        dap_list_t *l_list_tmp = l_list_out_items;
-        while(l_list_tmp) {
-            const dap_chain_tx_out_t *l_tx_out = (const dap_chain_tx_out_t*) l_list_tmp->data;
-            // if transaction has the out item with requested addr
-            if(l_tx_out &&
-                    !memcmp(a_addr, &l_tx_out->addr, sizeof(dap_chain_addr_t))
-                            ) {
-                memcpy(a_tx_first_hash, l_tx_hash, sizeof(dap_chain_hash_fast_t));
-                is_tx_found = true;
-                break;
+        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_tmp = l_list_out_items; l_list_tmp; l_list_tmp = dap_list_next(l_list_tmp)) {
+            assert(l_list_tmp->data);
+            dap_chain_tx_item_type_t l_type = *(uint8_t *)l_list_tmp->data;
+            if (l_type == TX_ITEM_TYPE_OUT_COND) {
+                continue;
+            }
+            if (l_type == TX_ITEM_TYPE_OUT) {
+                const dap_chain_tx_out_t *l_tx_out = (const dap_chain_tx_out_t *)l_list_tmp->data;
+                // if transaction has the out item with requested addr
+                if(!memcmp(a_addr, &l_tx_out->addr, sizeof(dap_chain_addr_t))) {
+                    memcpy(a_tx_first_hash, l_tx_hash, sizeof(dap_chain_hash_fast_t));
+                    is_tx_found = true;
+                    break;
+                }
+            }
+            if (l_type == TX_ITEM_TYPE_OUT_EXT) {
+                const dap_chain_tx_out_ext_t *l_tx_out_ext = (const dap_chain_tx_out_ext_t *)l_list_tmp->data;
+                // If a_token is setup we check if its not our token - miss it
+                if (a_token && dap_strcmp(l_tx_out_ext->token, a_token)) {
+                    continue;
+                }                // if transaction has the out item with requested addr
+                if(!memcmp(a_addr, &l_tx_out_ext->addr, sizeof(dap_chain_addr_t))) {
+                    memcpy(a_tx_first_hash, l_tx_hash, sizeof(dap_chain_hash_fast_t));
+                    is_tx_found = true;
+                    break;
+                }
             }
-            l_list_tmp = dap_list_next(l_list_tmp);
         }
-        dap_list_free(l_list_tmp);
+        dap_list_free(l_list_out_items);
         // already found transaction
         if(is_tx_found)
             break;
@@ -1483,7 +1676,6 @@ dap_chain_datum_tx_t* dap_chain_ledger_tx_cache_find_out_cond(dap_ledger_t *a_le
 {
     if(!a_addr || !a_tx_first_hash)
         return NULL;
-    int l_ret = -1;
     dap_ledger_private_t *l_ledger_priv = PVT(a_ledger);
     dap_chain_datum_tx_t *l_cur_tx = NULL;
     bool is_null_hash = dap_hash_fast_is_blank(a_tx_first_hash);
@@ -1557,3 +1749,87 @@ uint64_t dap_chain_ledger_tx_cache_get_out_cond_value(dap_ledger_t *a_ledger, da
     return l_ret_value;
 }
 
+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,
+                                                       uint64_t a_value_need, uint64_t *a_value_transfer)
+{
+    dap_list_t *l_list_used_out = NULL; // list of transaction with 'out' items
+    dap_chain_hash_fast_t l_tx_cur_hash = { 0 };
+    uint64_t l_value_transfer = 0;
+    while(l_value_transfer < a_value_need)
+    {
+        // Get the transaction in the cache by the addr in out item
+        dap_chain_datum_tx_t *l_tx = dap_chain_ledger_tx_find_by_addr(a_ledger, a_token_ticker, a_addr_from,
+                                                                             &l_tx_cur_hash);
+        if(!l_tx)
+            break;
+        // Get all item from transaction by type
+        dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT_ALL, NULL);
+
+        uint32_t l_out_idx_tmp = 0; // current index of 'out' item
+        for (dap_list_t *l_list_tmp = l_list_out_items; l_list_tmp; l_list_tmp = dap_list_next(l_list_tmp), l_out_idx_tmp++) {
+            dap_chain_tx_item_type_t l_type = *(uint8_t *)l_list_tmp->data;
+            if (l_type == TX_ITEM_TYPE_OUT_COND) {
+                continue;
+            }
+            uint64_t l_value;
+            if (l_type == TX_ITEM_TYPE_OUT) {
+                dap_chain_tx_out_t *l_out = (dap_chain_tx_out_t *)l_list_tmp->data;
+                if (!l_out->header.value || memcmp(a_addr_from, &l_out->addr, sizeof(dap_chain_addr_t))) {
+                    continue;
+                }
+                l_value =  l_out->header.value;
+            } else { // TX_ITEM_TYPE_OUT_EXT
+                dap_chain_tx_out_ext_t *l_out_ext = (dap_chain_tx_out_ext_t *)l_list_tmp->data;
+                if (!l_out_ext->header.value || memcmp(a_addr_from, &l_out_ext->addr, sizeof(dap_chain_addr_t)) ||
+                        strcmp((char *)a_token_ticker, l_out_ext->token)) {
+                    continue;
+                }
+                l_value =  l_out_ext->header.value;
+            }
+            // Check whether used 'out' items
+            if (!dap_chain_ledger_tx_hash_is_used_out_item (a_ledger, &l_tx_cur_hash, l_out_idx_tmp)) {
+                list_used_item_t *item = DAP_NEW(list_used_item_t);
+                memcpy(&item->tx_hash_fast, &l_tx_cur_hash, sizeof(dap_chain_hash_fast_t));
+                item->num_idx_out = l_out_idx_tmp;
+                item->value = l_value;
+                l_list_used_out = dap_list_append(l_list_used_out, item);
+                l_value_transfer += item->value;
+                // already accumulated the required value, finish the search for 'out' items
+                if(l_value_transfer >= a_value_need) {
+                    break;
+                }
+            }
+        }
+        dap_list_free(l_list_out_items);
+    }
+
+    // nothing to tranfer (not enough funds)
+    if(!l_list_used_out || l_value_transfer < a_value_need) {
+        dap_list_free_full(l_list_used_out, free);
+        return NULL;
+    }
+
+    if (a_value_transfer) {
+        *a_value_transfer = l_value_transfer;
+    }
+    return l_list_used_out;
+}
+
+// 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)
+{
+    dap_chain_ledger_verificator_t *l_new_verificator;
+    int l_tmp = (int)a_subtype;
+    HASH_FIND_INT(s_verificators, &l_tmp, l_new_verificator);
+    if (l_new_verificator) {
+        l_new_verificator->callback = a_callback;
+        return 1;
+    }
+    l_new_verificator = DAP_NEW(dap_chain_ledger_verificator_t);
+    l_new_verificator->subtype = (int)a_subtype;
+    l_new_verificator->callback = a_callback;
+    pthread_rwlock_wrlock(&s_verificators_rwlock);
+    HASH_ADD_INT(s_verificators, subtype, l_new_verificator);
+    pthread_rwlock_unlock(&s_verificators_rwlock);
+    return 0;
+}
diff --git a/modules/chain/include/dap_chain.h b/modules/chain/include/dap_chain.h
index 2556d2e9b41b5aa857ad75b36f858a80a5f5e84a..96694458347514411f164876956119eb02eeb6a0 100644
--- a/modules/chain/include/dap_chain.h
+++ b/modules/chain/include/dap_chain.h
@@ -165,6 +165,3 @@ dap_chain_t * dap_chain_load_from_cfg(dap_ledger_t* a_ledger,const char * a_chai
 
 void dap_chain_delete(dap_chain_t * a_chain);
 void dap_chain_add_callback_notify(dap_chain_t * a_chain, dap_chain_callback_notify_t a_callback, void * a_arg);
-
-
-
diff --git a/modules/chain/include/dap_chain_ledger.h b/modules/chain/include/dap_chain_ledger.h
index 3655a83d174ffaa9aa0993b17b4f4c1e5dcf3285..7639ead95a27511bd31451d6fa19825d26d2ec3b 100644
--- a/modules/chain/include/dap_chain_ledger.h
+++ b/modules/chain/include/dap_chain_ledger.h
@@ -41,6 +41,8 @@ typedef struct dap_ledger {
     void *_internal;
 } dap_ledger_t;
 
+typedef bool (* dap_chain_ledger_verificator_callback_t)(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx);
+
 // Checks the emission of the token, usualy on zero chain
 #define DAP_CHAIN_LEDGER_CHECK_TOKEN_EMISSION    0x0001
 
@@ -82,6 +84,13 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx);
 
 int dap_chain_ledger_tx_add_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx);
 
+/**
+ * Check token ticker existance
+ *
+ */
+
+int dap_chain_ledger_token_ticker_check(dap_ledger_t * a_ledger, const char *a_token_ticker);
+
 /**
  * Add new token datum
  *
@@ -172,3 +181,10 @@ dap_chain_datum_tx_t* dap_chain_ledger_tx_cache_find_out_cond(dap_ledger_t *a_le
 // Get the value from all transactions in the cache with out_cond item
 uint64_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);
+
+// 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,
+                                                       uint64_t a_value_need, uint64_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);
diff --git a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c
index c15223614f02453c2c76bdbd7a07bb908704a451..bccec32e887a1d84e3a497e29f8bdd222ea299ac 100644
--- a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c
+++ b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c
@@ -202,9 +202,9 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                     }
 
                     // Check cond output if it equesl or not to request
-                    if ( l_tx_out_cond->subtype.srv_pay.header.srv_uid.uint64 != l_request->hdr.srv_uid.uint64 ){
+                    if ( l_tx_out_cond->subtype.srv_pay.srv_uid.uint64 != l_request->hdr.srv_uid.uint64 ){
                         log_it( L_WARNING, "Wrong service uid in request, tx expect to close its output with 0x%016lX",
-                                l_tx_out_cond->subtype.srv_pay.header.srv_uid );
+                                l_tx_out_cond->subtype.srv_pay.srv_uid );
                         l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_TX_COND_WRONG_SRV_UID  ;
                         dap_stream_ch_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
                         if (l_srv->callback_response_error)
@@ -244,7 +244,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                     DL_FOREACH(l_srv->pricelist, l_price_tmp) {
                         if (l_price_tmp->net->pub.id.uint64                 == l_request->hdr.net_id.uint64
                             && dap_strcmp(l_price_tmp->token, l_ticker)     == 0
-                            && l_price_tmp->units_uid.enm                   == l_tx_out_cond->subtype.srv_pay.header.unit.enm
+                            && l_price_tmp->units_uid.enm                   == l_tx_out_cond->subtype.srv_pay.unit.enm
                             )//&& (l_price_tmp->value_datoshi/l_price_tmp->units)  < l_tx_out_cond->subtype.srv_pay.header.unit_price_max_datoshi)
                         {
                             l_price = l_price_tmp;
@@ -386,7 +386,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
                     dap_sign_get_pkey_hash( l_receipt_sign, &l_pkey_hash);
 
 
-                    if( memcmp ( l_pkey_hash.raw, l_tx_out_cond->subtype.srv_pay.header.pkey_hash.raw , sizeof(l_pkey_hash) ) != 0 ){
+                    if( memcmp ( l_pkey_hash.raw, l_tx_out_cond->subtype.srv_pay.pkey_hash.raw , sizeof(l_pkey_hash) ) != 0 ){
                         l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_RECEIPT_WRONG_PKEY_HASH ;
                         dap_stream_ch_pkt_write( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err) );
                         if (l_usage->service->callback_response_error)
diff --git a/modules/common/dap_chain_datum_tx.c b/modules/common/dap_chain_datum_tx.c
index 094961c22daa3b60b8e928a8850f759af2a79f0b..0bdb9260550bdd590f66badd8d3f5076660aa29e 100644
--- a/modules/common/dap_chain_datum_tx.c
+++ b/modules/common/dap_chain_datum_tx.c
@@ -99,6 +99,25 @@ int dap_chain_datum_tx_add_in_item(dap_chain_datum_tx_t **a_tx, dap_chain_hash_f
     return -1;
 }
 
+/**
+ * Create 'in' items from list and insert to transaction
+ *
+ * return summary value from inserted items
+ */
+uint64_t dap_chain_datum_tx_add_in_item_list(dap_chain_datum_tx_t **a_tx, dap_list_t *a_list_used_out)
+{
+    dap_list_t *l_list_tmp = a_list_used_out;
+    uint64_t l_value_to_items = 0; // how many datoshi to transfer
+    while (l_list_tmp) {
+        list_used_item_t *item = l_list_tmp->data;
+        if (dap_chain_datum_tx_add_in_item(a_tx, &item->tx_hash_fast, item->num_idx_out) == 1) {
+            l_value_to_items += item->value;
+        }
+        l_list_tmp = dap_list_next(l_list_tmp);
+    }
+    return l_value_to_items;
+}
+
 
 /**
  * @brief dap_chain_datum_tx_add_in_cond_item
@@ -122,6 +141,7 @@ int dap_chain_datum_tx_add_in_cond_item(dap_chain_datum_tx_t **a_tx, dap_chain_h
     return -1;
 
 }
+
 /**
  * Create 'out' item and insert to transaction
  *
@@ -138,6 +158,22 @@ int dap_chain_datum_tx_add_out_item(dap_chain_datum_tx_t **a_tx, const dap_chain
     return -1;
 }
 
+/**
+ * Create 'out_ext' item and insert to transaction
+ *
+ * return 1 Ok, -1 Error
+ */
+int dap_chain_datum_tx_add_out_ext_item(dap_chain_datum_tx_t **a_tx, const dap_chain_addr_t *a_addr, uint64_t a_value, const char *a_token)
+{
+    dap_chain_tx_out_ext_t *l_tx_out = dap_chain_datum_tx_item_out_ext_create(a_addr, a_value, a_token);
+    if(l_tx_out) {
+        dap_chain_datum_tx_add_item(a_tx, (const uint8_t *)l_tx_out);
+        DAP_DELETE(l_tx_out);
+        return 1;
+    }
+    return -1;
+}
+
 /**
  * Create 'out_cond' item and insert to transaction
  *
diff --git a/modules/common/dap_chain_datum_tx_items.c b/modules/common/dap_chain_datum_tx_items.c
index d5a627ba84096b0665babc2cc05f70601d055283..6c44465b08399af133461ab20a4e36ea8c868ebf 100644
--- a/modules/common/dap_chain_datum_tx_items.c
+++ b/modules/common/dap_chain_datum_tx_items.c
@@ -46,6 +46,7 @@ static size_t dap_chain_tx_in_get_size(const dap_chain_tx_in_t *a_item)
 
 static size_t dap_chain_tx_in_cond_get_size(const dap_chain_tx_in_cond_t *a_item)
 {
+    UNUSED(a_item);
     size_t size = sizeof(dap_chain_tx_in_cond_t);
     return size;
 }
@@ -57,14 +58,16 @@ static size_t dap_chain_tx_out_get_size(const dap_chain_tx_out_t *a_item)
     return size;
 }
 
+static size_t dap_chain_tx_out_ext_get_size(const dap_chain_tx_out_ext_t *a_item)
+{
+    (void) a_item;
+    size_t size = sizeof(dap_chain_tx_out_ext_t);
+    return size;
+}
+
 static size_t dap_chain_tx_out_cond_get_size(const dap_chain_tx_out_cond_t *a_item)
 {
-    switch (a_item->header.subtype) {
-        case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY:
-            return sizeof (a_item->header) + sizeof (a_item->subtype.srv_pay.header) + a_item->subtype.srv_pay.header.params_size;
-        default:
-                return 0;
-    }
+    return sizeof(dap_chain_tx_out_cond_t) + a_item->params_size;
 }
 
 static size_t dap_chain_tx_pkey_get_size(const dap_chain_tx_pkey_t *a_item)
@@ -114,6 +117,9 @@ size_t dap_chain_datum_item_tx_get_size(const uint8_t *a_item)
     case TX_ITEM_TYPE_OUT: // Transaction outputs
         size = dap_chain_tx_out_get_size((const dap_chain_tx_out_t*) a_item);
         break;
+    case TX_ITEM_TYPE_OUT_EXT:
+        size = dap_chain_tx_out_ext_get_size((const dap_chain_tx_out_ext_t*) a_item);
+        break;
     case TX_ITEM_TYPE_RECEIPT: // Receipt
         size = dap_chain_datum_tx_receipt_get_size((const dap_chain_datum_tx_receipt_t*) a_item);
     case TX_ITEM_TYPE_IN_COND: // Transaction inputs with condition
@@ -186,7 +192,7 @@ dap_chain_tx_in_cond_t* dap_chain_datum_tx_item_in_cond_create(dap_chain_hash_fa
     if(!a_tx_prev_hash )
         return NULL;
     dap_chain_tx_in_cond_t *l_item = DAP_NEW_Z(dap_chain_tx_in_cond_t);
-    l_item->header.type = TX_ITEM_TYPE_IN;
+    l_item->header.type = TX_ITEM_TYPE_IN_COND;
     l_item->header.receipt_idx = a_receipt_idx;
     l_item->header.tx_out_prev_idx = a_tx_out_prev_idx;
     memcpy(&l_item->header.tx_prev_hash, a_tx_prev_hash,sizeof(l_item->header.tx_prev_hash) );
@@ -209,6 +215,18 @@ dap_chain_tx_out_t* dap_chain_datum_tx_item_out_create(const dap_chain_addr_t *a
     return l_item;
 }
 
+dap_chain_tx_out_ext_t* dap_chain_datum_tx_item_out_ext_create(const dap_chain_addr_t *a_addr, uint64_t a_value, const char *a_token)
+{
+    if (!a_addr || !a_token)
+        return NULL;
+    dap_chain_tx_out_ext_t *l_item = DAP_NEW_Z(dap_chain_tx_out_ext_t);
+    l_item->header.type = TX_ITEM_TYPE_OUT_EXT;
+    l_item->header.value = a_value;
+    memcpy(&l_item->addr, a_addr, sizeof(dap_chain_addr_t));
+    strcpy(l_item->token, a_token);
+    return l_item;
+}
+
 /**
  * Create item dap_chain_tx_out_cond_t
  *
@@ -224,21 +242,41 @@ dap_chain_tx_out_cond_t* dap_chain_datum_tx_item_out_cond_create_srv_pay(dap_enc
     uint8_t *l_pub_key = dap_enc_key_serealize_pub_key(a_key, &l_pub_key_size);
 
 
-    dap_chain_tx_out_cond_t *l_item = DAP_NEW_Z_SIZE(dap_chain_tx_out_cond_t,
-            sizeof(l_item->header)+sizeof (l_item->subtype.srv_pay.header) + a_params_size);
+    dap_chain_tx_out_cond_t *l_item = DAP_NEW_Z_SIZE(dap_chain_tx_out_cond_t, sizeof(dap_chain_tx_out_cond_t) + a_params_size);
     l_item->header.item_type = TX_ITEM_TYPE_OUT_COND;
     l_item->header.value = a_value;
     l_item->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY; // By default creatre cond for service pay. Rework with smth more flexible
-    l_item->subtype.srv_pay.header.srv_uid = a_srv_uid;
-    l_item->subtype.srv_pay.header.params_size = (uint32_t) a_params_size;
-    l_item->subtype.srv_pay.header.unit = a_unit;
-    l_item->subtype.srv_pay.header.unit_price_max_datoshi = a_value_max_per_unit;
-    dap_hash_fast( l_pub_key, l_pub_key_size, & l_item->subtype.srv_pay.header.pkey_hash);
-    memcpy(l_item->subtype.srv_pay.params, a_params, a_params_size);
+    l_item->subtype.srv_pay.srv_uid = a_srv_uid;
+    l_item->subtype.srv_pay.unit = a_unit;
+    l_item->subtype.srv_pay.unit_price_max_datoshi = a_value_max_per_unit;
+    dap_hash_fast( l_pub_key, l_pub_key_size, & l_item->subtype.srv_pay.pkey_hash);
+    l_item->params_size = (uint32_t)a_params_size;
+    memcpy(l_item->params, a_params, a_params_size);
     return l_item;
 }
 
 
+dap_chain_tx_out_cond_t* dap_chain_datum_tx_item_out_cond_create_srv_xchange(dap_chain_net_srv_uid_t a_srv_uid, dap_chain_net_id_t a_net_id,
+                                                                             const char *a_token, uint64_t a_value,
+                                                                             const void *a_params, uint32_t a_params_size)
+{
+    if (!a_token) {
+        return NULL;
+    }
+    dap_chain_tx_out_cond_t *l_item = DAP_NEW_Z_SIZE(dap_chain_tx_out_cond_t, sizeof(dap_chain_tx_out_cond_t) + a_params_size);
+    l_item->header.item_type = TX_ITEM_TYPE_OUT_COND;
+    l_item->header.value = a_value;
+    l_item->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE;
+    l_item->subtype.srv_xchange.srv_uid = a_srv_uid;
+    l_item->subtype.srv_xchange.net_id = a_net_id;
+    strcpy(l_item->subtype.srv_xchange.token, a_token);
+    l_item->params_size = a_params_size;
+    if (a_params_size) {
+        memcpy(l_item->params, a_params, a_params_size);
+    }
+    return l_item;
+}
+
 /**
  * Create item dap_chain_tx_sig_t
  *
@@ -298,7 +336,11 @@ uint8_t* dap_chain_datum_tx_item_get( dap_chain_datum_tx_t *a_tx, int *a_item_id
         // check index
         if(!a_item_idx_start || l_item_idx >= *a_item_idx_start) {
             // check type
-            if(a_type == TX_ITEM_TYPE_ANY || a_type == dap_chain_datum_tx_item_get_type(l_item)) {
+            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 ||
+                    (a_type == TX_ITEM_TYPE_OUT_ALL && l_type == TX_ITEM_TYPE_OUT) ||
+                    (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_out_size)
@@ -338,3 +380,22 @@ dap_list_t* dap_chain_datum_tx_items_get(dap_chain_datum_tx_t *a_tx, dap_chain_t
         *a_item_count = l_items_count;
     return items_list;
 }
+
+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_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;
+    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++) {
+        if (*(uint8_t *)l_list_tmp->data == TX_ITEM_TYPE_OUT_COND) {
+            l_res = l_list_tmp->data;
+            break;
+        }
+    }
+    dap_list_free(l_list_out_items);
+    if (a_out_num) {
+        *a_out_num = l_prev_cond_idx;
+    }
+    return l_res;
+}
+
diff --git a/modules/common/dap_chain_datum_tx_out_cond.c b/modules/common/dap_chain_datum_tx_out_cond.c
deleted file mode 100644
index 543fd32bd209bf7d86865234846d7400347139fe..0000000000000000000000000000000000000000
--- a/modules/common/dap_chain_datum_tx_out_cond.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Authors:
- * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
- * Alexander Lysikov <alexander.lysikov@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * DeM Labs Open source community https://github.com/demlabsinc
- * Copyright  (c) 2017-2019
- * 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 <stdint.h>
-#include "dap_common.h"
-#include "dap_chain_common.h"
-#include "dap_chain_datum_tx_out_cond.h"
-
-uint8_t* dap_chain_datum_tx_out_cond_item_get_params(dap_chain_tx_out_cond_t *a_tx_out_cond, size_t *a_cond_size_out)
-{
-    if(a_tx_out_cond) {
-        switch (a_tx_out_cond->header.subtype ) {
-            case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY:{
-                if(a_cond_size_out)
-                    *a_cond_size_out = a_tx_out_cond->subtype.srv_pay.header.params_size;
-                return a_tx_out_cond->subtype.srv_pay.params;
-            }
-            default: return NULL;
-        }
-    }
-    return NULL;
-}
-
diff --git a/modules/common/include/dap_chain_common.h b/modules/common/include/dap_chain_common.h
index c2b2d7651ce46a6428a936e82765a974ba73c448..a4a11b7d27703246ffc778bfcb9940b75f291938 100644
--- a/modules/common/include/dap_chain_common.h
+++ b/modules/common/include/dap_chain_common.h
@@ -173,6 +173,7 @@ typedef union {
 typedef enum dap_chain_tx_item_type {
     TX_ITEM_TYPE_IN = 0x00, /// @brief  Transaction: inputs
     TX_ITEM_TYPE_OUT = 0x10, /// @brief  Transaction: outputs
+    TX_ITEM_TYPE_OUT_EXT = 0x11,
     TX_ITEM_TYPE_PKEY = 0x20,
     TX_ITEM_TYPE_SIG = 0x30,
     TX_ITEM_TYPE_TOKEN = 0x40,
@@ -181,7 +182,8 @@ typedef enum dap_chain_tx_item_type {
     TX_ITEM_TYPE_OUT_COND = 0x60, /// @brief  Transaction: conditon outputs
     TX_ITEM_TYPE_RECEIPT = 0x70,
 
-    TX_ITEM_TYPE_ANY = 0xff,
+    TX_ITEM_TYPE_OUT_ALL = 0xfe,
+    TX_ITEM_TYPE_ANY = 0xff
 } dap_chain_tx_item_type_t;
 
 
diff --git a/modules/common/include/dap_chain_datum_tx.h b/modules/common/include/dap_chain_datum_tx.h
index ac384233cb7426d4c27109da166e7f7277bb5e38..54885c4863ecfe326112fc46141c54141ac66043 100644
--- a/modules/common/include/dap_chain_datum_tx.h
+++ b/modules/common/include/dap_chain_datum_tx.h
@@ -23,6 +23,7 @@
 */
 #pragma once
 
+#include "dap_list.h"
 #include "dap_enc_key.h"
 #include "dap_chain_common.h"
 #include "dap_chain_datum.h"
@@ -73,6 +74,12 @@ size_t dap_chain_datum_tx_get_size(dap_chain_datum_tx_t *a_tx);
  */
 int dap_chain_datum_tx_add_item(dap_chain_datum_tx_t **a_tx, const uint8_t *a_item);
 
+/**
+ * Create 'in' items from list and insert to transaction
+ *
+ * return summary value from inserted items
+ */
+uint64_t dap_chain_datum_tx_add_in_item_list(dap_chain_datum_tx_t **a_tx, dap_list_t *a_list_used_out);
 
 /**
  * Create 'in' item and insert to transaction
@@ -99,6 +106,14 @@ int dap_chain_datum_tx_add_in_cond_item(dap_chain_datum_tx_t **a_tx, dap_chain_h
  */
 int dap_chain_datum_tx_add_out_item(dap_chain_datum_tx_t **a_tx, const dap_chain_addr_t *a_addr, uint64_t a_value);
 
+/**
+ * Create 'out'_ext item and insert to transaction
+ *
+ * return 1 Ok, -1 Error
+ */
+int dap_chain_datum_tx_add_out_ext_item(dap_chain_datum_tx_t **a_tx, const dap_chain_addr_t *a_addr,
+                                        uint64_t a_value, const char *a_token);
+
 /**
  * Create 'out_cond' item and insert to transaction
  *
diff --git a/modules/common/include/dap_chain_datum_tx_in.h b/modules/common/include/dap_chain_datum_tx_in.h
index 7ce6fedac78789894eb416a53ef65b430f2fb69c..d52c76aac74bbb030412d864e881d6e1ead281b4 100644
--- a/modules/common/include/dap_chain_datum_tx_in.h
+++ b/modules/common/include/dap_chain_datum_tx_in.h
@@ -43,3 +43,11 @@ typedef struct dap_chain_tx_in{
 //    uint32_t seq_no; /// Sequence number, out of the header so could be changed during reorganization
 //    uint8_t sig[]; /// @param sig @brief raw signatura dat
 } DAP_ALIGN_PACKED dap_chain_tx_in_t;
+
+typedef struct list_used_item {
+    dap_chain_hash_fast_t tx_hash_fast;
+    uint32_t num_idx_out;
+    uint8_t padding[4];
+    uint64_t value;
+//dap_chain_tx_out_t *tx_out;
+} list_used_item_t;
diff --git a/modules/common/include/dap_chain_datum_tx_items.h b/modules/common/include/dap_chain_datum_tx_items.h
index a01026be4c5faac7dc38e05308176015af5641a7..7ef0ab207c26e21ea3c702865a6c4c59815528cb 100644
--- a/modules/common/include/dap_chain_datum_tx_items.h
+++ b/modules/common/include/dap_chain_datum_tx_items.h
@@ -34,6 +34,7 @@
 #include "dap_chain_datum_tx.h"
 #include "dap_chain_datum_tx_in.h"
 #include "dap_chain_datum_tx_out.h"
+#include "dap_chain_datum_tx_out_ext.h"
 #include "dap_chain_datum_tx_in_cond.h"
 #include "dap_chain_datum_tx_out_cond.h"
 #include "dap_chain_datum_tx_sig.h"
@@ -79,6 +80,13 @@ dap_chain_tx_in_cond_t* dap_chain_datum_tx_item_in_cond_create(dap_chain_hash_fa
  */
 dap_chain_tx_out_t* dap_chain_datum_tx_item_out_create(const dap_chain_addr_t *a_addr, uint64_t a_value);
 
+/**
+ * Create item dap_chain_tx_out_ext_t
+ *
+ * return item, NULL Error
+ */
+dap_chain_tx_out_ext_t* dap_chain_datum_tx_item_out_ext_create(const dap_chain_addr_t *a_addr, uint64_t a_value, const char *a_token);
+
 /**
  * Create item dap_chain_tx_out_cond_t
  *
@@ -87,7 +95,14 @@ dap_chain_tx_out_t* dap_chain_datum_tx_item_out_create(const dap_chain_addr_t *a
 dap_chain_tx_out_cond_t* dap_chain_datum_tx_item_out_cond_create_srv_pay(dap_enc_key_t *a_key, dap_chain_net_srv_uid_t a_srv_uid,
         uint64_t a_value, uint64_t a_value_max_per_unit, dap_chain_net_srv_price_unit_uid_t a_unit,
                                                                  const void *a_cond, size_t a_cond_size);
-
+/**
+ * Create item dap_chain_tx_out_cond_t fo eXchange service
+ *
+ * return item, NULL Error
+ */
+dap_chain_tx_out_cond_t* dap_chain_datum_tx_item_out_cond_create_srv_xchange(dap_chain_net_srv_uid_t a_srv_uid,
+                                                                             dap_chain_net_id_t a_net_id, const char *a_token, uint64_t a_value,
+                                                                             const void *a_params, uint32_t a_params_size);
 /**
  * Create item dap_chain_tx_sig_t
  *
@@ -116,3 +131,5 @@ uint8_t* dap_chain_datum_tx_item_get( dap_chain_datum_tx_t *a_tx, int *a_item_id
 
 // 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);
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 188d5a124c7339b89eddc8490718f34c7a72684d..d5889678e3fffd92af325926d6567c9582fa6ac3 100644
--- a/modules/common/include/dap_chain_datum_tx_out_cond.h
+++ b/modules/common/include/dap_chain_datum_tx_out_cond.h
@@ -29,8 +29,11 @@
 #include "dap_chain_common.h"
 #include "dap_chain_datum_tx.h"
 
+typedef enum dap_chain_tx_out_cond_subtype {
+    DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY = 0x01,
+    DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE = 0x02
+} dap_chain_tx_out_cond_subtype_t;
 
-#define DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY     0x01
 /**
  * @struct dap_chain_tx_out
  * @brief Transaction item out_cond
@@ -40,32 +43,35 @@ typedef struct dap_chain_tx_out_cond {
         /// Transaction item type
         dap_chain_tx_item_type_t item_type :8;
         /// Condition subtype
-        uint8_t subtype;
+        dap_chain_tx_out_cond_subtype_t subtype : 8;
         /// Number of Datoshis ( DAP/10^9 ) to be reserver for service
         uint64_t value;
         /// When time expires this output could be used only by transaction owner
         dap_chain_time_t ts_expires;
     } header;
     union {
+        /// Structure with specific for service pay condition subtype
         struct {
-            /// Structure with specific for service pay condition subtype
-            struct {
-                /// Public key hash that could use this conditioned outout
-                dap_chain_hash_fast_t pkey_hash;
-                /// Service uid that only could be used for this outout
-                dap_chain_net_srv_uid_t srv_uid;
-                /// Price unit thats used to check price max
-                dap_chain_net_srv_price_unit_uid_t unit;
-                /// Maximum price per unit
-                uint64_t unit_price_max_datoshi;
-                 /// Condition parameters size
-                uint32_t params_size;
-            } DAP_ALIGN_PACKED header;
-            uint8_t params[]; // condition parameters, pkey, hash or smth like this
-        } DAP_ALIGN_PACKED srv_pay;
+            /// Public key hash that could use this conditioned outout
+            dap_chain_hash_fast_t pkey_hash;
+            /// Service uid that only could be used for this outout
+            dap_chain_net_srv_uid_t srv_uid;
+            /// Price unit thats used to check price max
+            dap_chain_net_srv_price_unit_uid_t unit;
+            /// Maximum price per unit
+            uint64_t unit_price_max_datoshi;
+        } srv_pay;
+        struct {
+            // Service uid that only could be used for this outout
+            dap_chain_net_srv_uid_t srv_uid;
+            // Token ticker to change to
+            char token[DAP_CHAIN_TICKER_SIZE_MAX];
+            // Chain network to change to
+            dap_chain_net_id_t net_id;
+            // Total amount of datoshi to change to
+            uint64_t value;
+        } srv_xchange;
     } subtype;
-}DAP_ALIGN_PACKED dap_chain_tx_out_cond_t;
-
-uint8_t* dap_chain_datum_tx_out_cond_item_get_params(dap_chain_tx_out_cond_t *a_tx_out_cond, size_t *a_params_size_out);
-
-
+    uint32_t params_size; // Condition parameters size
+    uint8_t params[]; // condition parameters, pkey, hash or smth like this
+} DAP_ALIGN_PACKED dap_chain_tx_out_cond_t;
diff --git a/modules/common/include/dap_chain_datum_tx_out_ext.h b/modules/common/include/dap_chain_datum_tx_out_ext.h
new file mode 100644
index 0000000000000000000000000000000000000000..536012bbd6226418cf05fd7dce55aa98dc19564d
--- /dev/null
+++ b/modules/common/include/dap_chain_datum_tx_out_ext.h
@@ -0,0 +1,43 @@
+/*
+ * Authors:
+ * Roman Khlopkov <roman.khlopkov@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * DeM Labs Open source community https://gitlab.demlabs.net
+ * Copyright  (c) 2017-2020
+ * 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 <stdint.h>
+#include "dap_common.h"
+#include "dap_chain_common.h"
+#include "dap_chain_datum_tx.h"
+
+/**
+  * @struct dap_chain_tx_out_ext
+  * @brief Multichannel transaction item output
+  */
+typedef struct dap_chain_tx_out_ext{
+    struct {
+        dap_chain_tx_item_type_t type : 8; // Transaction item type - should be TX_ITEM_TYPE_OUT_EXT
+        uint64_t value;                    // Number of Datoshis ( DAP/10^9 ) to be transfered
+    } header;                              // Only header's hash is used for verification
+    dap_chain_addr_t addr;                 // Address to transfer to
+    char token[DAP_CHAIN_TICKER_SIZE_MAX]; // Which token is transferred
+} DAP_ALIGN_PACKED dap_chain_tx_out_ext_t;
diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c
index c51072d2830f55eb89833676b988392c21d25f31..d103711c103eb8e8c2fdaab895fea8cbaafa3b2b 100644
--- a/modules/mempool/dap_chain_mempool.c
+++ b/modules/mempool/dap_chain_mempool.c
@@ -66,14 +66,6 @@
 
 #define LOG_TAG "dap_chain_mempool"
 
-typedef struct list_used_item {
-    dap_chain_hash_fast_t tx_hash_fast;
-    int num_idx_out;
-    uint8_t padding[4];
-    uint64_t value;
-//dap_chain_tx_out_t *tx_out;
-} list_used_item_t;
-
 
 int dap_datum_mempool_init(void)
 {
@@ -127,71 +119,19 @@ int dap_chain_mempool_tx_create(dap_chain_t * a_chain, dap_enc_key_t *a_key_from
         return -1;
 
     // find the transactions from which to take away coins
-    dap_list_t *l_list_used_out = NULL; // list of transaction with 'out' items
     uint64_t l_value_transfer = 0; // how many coins to transfer
-    {
-        dap_chain_hash_fast_t l_tx_cur_hash = { 0 };
-        uint64_t l_value_need = a_value + a_value_fee;
-        while(l_value_transfer < l_value_need)
-        {
-            // Get the transaction in the cache by the addr in out item
-            dap_chain_datum_tx_t *l_tx = dap_chain_ledger_tx_find_by_addr(a_chain->ledger,a_token_ticker, a_addr_from,
-                                                                                 &l_tx_cur_hash);
-            if(!l_tx)
-                break;
-            // Get all item from transaction by type
-            int l_item_count = 0;
-            dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get( l_tx, TX_ITEM_TYPE_OUT,
-                    &l_item_count);
-            dap_list_t *l_list_tmp = l_list_out_items;
-            int l_out_idx_tmp = 0; // current index of 'out' item
-            while(l_list_tmp) {
-                dap_chain_tx_out_t *out_item = l_list_tmp->data;
-                // if 'out' item has addr = a_addr_from
-                if(out_item && !memcmp(a_addr_from, &out_item->addr, sizeof(dap_chain_addr_t))) {
-
-                    // Check whether used 'out' items
-                    if(!dap_chain_ledger_tx_hash_is_used_out_item (a_chain->ledger, &l_tx_cur_hash, l_out_idx_tmp)) {
-
-                        list_used_item_t *item = DAP_NEW(list_used_item_t);
-                        memcpy(&item->tx_hash_fast, &l_tx_cur_hash, sizeof(dap_chain_hash_fast_t));
-                        item->num_idx_out = l_out_idx_tmp;
-                        item->value = out_item->header.value;
-                        l_list_used_out = dap_list_append(l_list_used_out, item);
-                        l_value_transfer += item->value;
-                        // already accumulated the required value, finish the search for 'out' items
-                        if(l_value_transfer >= l_value_need) {
-                            break;
-                        }
-                    }
-                }
-                // go to the next 'out' item in l_tx transaction
-                l_out_idx_tmp++;
-                l_list_tmp = dap_list_next(l_list_tmp);
-            }
-            dap_list_free(l_list_out_items);
-        }
-
-        // nothing to tranfer (not enough funds)
-        if(!l_list_used_out || l_value_transfer < l_value_need) {
-            dap_list_free_full(l_list_used_out, free);
-            return -2;
-        }
+    uint64_t l_value_need = a_value + a_value_fee;
+    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");
+        return -2;
     }
-
     // create empty transaction
     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
     // add 'in' items
     {
-        dap_list_t *l_list_tmp = l_list_used_out;
-        uint64_t l_value_to_items = 0; // how many datoshi to transfer
-        while(l_list_tmp) {
-            list_used_item_t *item = l_list_tmp->data;
-            if(dap_chain_datum_tx_add_in_item(&l_tx, &item->tx_hash_fast,(uint32_t) item->num_idx_out) == 1) {
-                l_value_to_items += item->value;
-            }
-            l_list_tmp = dap_list_next(l_list_tmp);
-        }
+        uint64_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
         assert(l_value_to_items == l_value_transfer);
         dap_list_free_full(l_list_used_out, free);
     }
@@ -258,56 +198,12 @@ int dap_chain_mempool_tx_create_massive( dap_chain_t * a_chain, dap_enc_key_t *a
 
     // Search unused out:
     uint64_t l_value_need =a_tx_num*( a_value + a_value_fee );
-    dap_chain_hash_fast_t l_tx_prev_hash = { 0 };
-    dap_list_t *l_list_used_out = NULL; // list of transaction with 'out' items
     uint64_t l_value_transfer = 0; // how many coins to transfer
-
     log_it(L_DEBUG,"Create %lu transactions, summary %Lf.7", a_tx_num,dap_chain_balance_to_coins(l_value_need) ) ;
-
-    while(l_value_transfer < l_value_need){
-        // Get the transaction in the cache by the addr in out item
-        dap_chain_datum_tx_t *l_tx = dap_chain_ledger_tx_find_by_addr(a_chain->ledger, a_token_ticker,a_addr_from,
-                &l_tx_prev_hash);
-        if(!l_tx)
-            break;
-        // Get all item from transaction by type
-        int l_item_count = 0;
-        dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get( l_tx, TX_ITEM_TYPE_OUT,
-                &l_item_count);
-        dap_list_t *l_list_tmp = l_list_out_items;
-        int l_out_idx_tmp = 0; // current index of 'out' item
-        while(l_list_tmp) {
-            dap_chain_tx_out_t *out_item = l_list_tmp->data;
-            // if 'out' item has addr = a_addr_from
-            if(out_item && out_item->header.value && !memcmp(a_addr_from, &out_item->addr, sizeof(dap_chain_addr_t))) {
-
-                // Check whether used 'out' items
-                if(!dap_chain_ledger_tx_hash_is_used_out_item (a_chain->ledger, &l_tx_prev_hash, l_out_idx_tmp)) {
-
-                    list_used_item_t *l_it = DAP_NEW(list_used_item_t);
-                    memcpy(&l_it->tx_hash_fast, &l_tx_prev_hash, sizeof(dap_chain_hash_fast_t));
-                    l_it->num_idx_out = l_out_idx_tmp;
-                    l_it->value = out_item->header.value;
-                    log_it(L_DEBUG," Found output with value %llu", l_it->value );
-                    l_list_used_out = dap_list_append(l_list_used_out, l_it);
-                    l_value_transfer += l_it->value;
-                    // already accumulated the required value, finish the search for 'out' items
-                    if(l_value_transfer >= l_value_need) {
-                        l_out_idx_tmp++;
-                        break;
-                    }
-                }
-            }
-            // go to the next 'out' item in l_tx transaction
-            l_out_idx_tmp++;
-            l_list_tmp = dap_list_next(l_list_tmp);
-        }
-    }
-
-    // nothing to tranfer (not enough funds)
-    if(!l_list_used_out || l_value_transfer < l_value_need) {
+    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");
-        dap_list_free_full(l_list_used_out, free);
         return -2;
     }
 
@@ -447,9 +343,10 @@ int dap_chain_mempool_tx_create_massive( dap_chain_t * a_chain, dap_enc_key_t *a
 }
 
 dap_chain_hash_fast_t* dap_chain_mempool_tx_create_cond_input(dap_chain_net_t * a_net,dap_chain_hash_fast_t *a_tx_prev_hash,
-
-        const dap_chain_addr_t* a_addr_to, dap_enc_key_t *l_key_tx_sign, dap_chain_datum_tx_receipt_t * l_receipt, size_t l_receipt_size)
+                                                              const dap_chain_addr_t* a_addr_to, dap_enc_key_t *l_key_tx_sign,
+                                                              dap_chain_datum_tx_receipt_t * l_receipt, size_t l_receipt_size)
 {
+    UNUSED(l_receipt_size);
     dap_ledger_t * l_ledger = a_net ? dap_chain_ledger_by_net_name( a_net->pub.name ) : NULL;
     if ( ! a_net || ! l_ledger || ! a_addr_to )
         return NULL;
@@ -464,9 +361,12 @@ dap_chain_hash_fast_t* dap_chain_mempool_tx_create_cond_input(dap_chain_net_t *
     uint16_t pos=0;
     dap_chain_datum_tx_add_item(&l_tx, (byte_t*) l_receipt);
     pos++;
+
     // add 'in_cond' items
-    // TODO - find first cond_item occurance, not just set it to 1
-    if (dap_chain_datum_tx_add_in_cond_item(&l_tx,a_tx_prev_hash,1,pos-1) != 0 ){
+    dap_chain_datum_tx_t *l_cond_tx = dap_chain_ledger_tx_find_by_hash(l_ledger, a_tx_prev_hash);
+    int l_prev_cond_idx;
+    dap_chain_datum_tx_out_cond_get(l_cond_tx, &l_prev_cond_idx);
+    if (dap_chain_datum_tx_add_in_cond_item(&l_tx, a_tx_prev_hash, l_prev_cond_idx, pos-1) != 0 ){
         dap_chain_datum_tx_delete(l_tx);
         log_it( L_ERROR, "Cant add tx cond input");
         return NULL;
@@ -526,72 +426,21 @@ static dap_chain_datum_t* dap_chain_tx_create_cond(dap_chain_net_t * a_net,
         return NULL;
 
     // find the transactions from which to take away coins
-    dap_list_t *l_list_used_out = NULL; // list of transaction with 'out' items
     uint64_t l_value_transfer = 0; // how many coins to transfer
-    {
-        dap_chain_hash_fast_t l_tx_cur_hash = { 0 };
-        uint64_t l_value_need = a_value + a_value_fee;
-        while(l_value_transfer < l_value_need)
-        {
-            // Get the transaction in the cache by the addr in out item
-            dap_chain_datum_tx_t *l_tx = dap_chain_ledger_tx_find_by_addr(l_ledger, a_token_ticker,a_addr_from,
-                    &l_tx_cur_hash);
-            if(!l_tx)
-                break;
-            // Get all item from transaction by type
-            int l_item_count = 0;
-            dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get( l_tx, TX_ITEM_TYPE_OUT,
-                    &l_item_count);
-            dap_list_t *l_list_tmp = l_list_out_items;
-            int l_out_idx_tmp = 0; // current index of 'out' item
-            while(l_list_tmp) {
-                dap_chain_tx_out_t *out_item = l_list_tmp->data;
-                // if 'out' item has addr = a_addr_from
-                if(out_item &&  !memcmp(a_addr_from, &out_item->addr, sizeof(dap_chain_addr_t))) {
-
-                    // Check whether used 'out' items
-                    if(!dap_chain_ledger_tx_hash_is_used_out_item(l_ledger, &l_tx_cur_hash, l_out_idx_tmp)) {
-
-                        list_used_item_t *item = DAP_NEW(list_used_item_t);
-                        memcpy(&item->tx_hash_fast, &l_tx_cur_hash, sizeof(dap_chain_hash_fast_t));
-                        item->num_idx_out = l_out_idx_tmp;
-                        item->value = out_item->header.value;
-                        l_list_used_out = dap_list_append(l_list_used_out, item);
-                        l_value_transfer += item->value;
-                        // already accumulated the required value, finish the search for 'out' items
-                        if(l_value_transfer >= l_value_need) {
-                            break;
-                        }
-                    }
-                }
-                // go to the next 'out' item in l_tx transaction
-                l_out_idx_tmp++;
-                l_list_tmp = dap_list_next(l_list_tmp);
-            }
-            dap_list_free(l_list_out_items);
-        }
-
-        // nothing to tranfer (not enough funds)
-        if(!l_list_used_out || l_value_transfer < l_value_need) {
-            dap_list_free_full(l_list_used_out, free);
-            log_it( L_ERROR, "nothing to tranfer (not enough funds)");
-            return NULL;
-        }
+    uint64_t l_value_need = a_value + a_value_fee;
+    // 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,
+                                                                             a_addr_from, l_value_need, &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();
     // add 'in' items
     {
-        dap_list_t *l_list_tmp = l_list_used_out;
-        uint64_t l_value_to_items = 0; // how many coins to transfer
-        while(l_list_tmp) {
-            list_used_item_t *item = l_list_tmp->data;
-            if(dap_chain_datum_tx_add_in_item(&l_tx, &item->tx_hash_fast,(uint32_t) item->num_idx_out) == 1) {
-                l_value_to_items += item->value;
-            }
-            l_list_tmp = dap_list_next(l_list_tmp);
-        }
+        uint64_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
         assert(l_value_to_items == l_value_transfer);
         dap_list_free_full(l_list_used_out, free);
     }
diff --git a/modules/mempool/include/dap_chain_mempool.h b/modules/mempool/include/dap_chain_mempool.h
index abe82a61fcae79d6afb4fc9cb3fa33f91b98688d..e4db94b8be5e956217b404eddddd4f07fa9f5e33 100644
--- a/modules/mempool/include/dap_chain_mempool.h
+++ b/modules/mempool/include/dap_chain_mempool.h
@@ -43,6 +43,7 @@ void dap_datum_mempool_free(dap_datum_mempool_t *datum);
 
 void dap_chain_mempool_add_proc(dap_http_t * a_http_server, const char * a_url);
 
+int dap_chain_mempool_datum_add(dap_chain_datum_t *a_datum, dap_chain_t *a_chain);
 int dap_chain_mempool_tx_create(dap_chain_t * a_chain, dap_enc_key_t *a_key_from,
         const dap_chain_addr_t* a_addr_from, const dap_chain_addr_t* a_addr_to,
         const dap_chain_addr_t* a_addr_fee,
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index 0864c057da64d0c68dfb7a46f57cdb194c8d8622..7ed6ac5e6ca03ac0f2bb8faf943a44a9dcc76874 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -274,6 +274,8 @@ static void s_gbd_history_callback_notify (void * a_arg, const char a_op_code, c
  */
 static void s_chain_callback_notify(void * a_arg, dap_chain_t *a_chain, dap_chain_cell_id_t a_id)
 {
+    UNUSED(a_chain);
+    UNUSED(a_id);
     if(!a_arg)
         return;
     dap_chain_net_t * l_net = (dap_chain_net_t *) a_arg;
@@ -1747,7 +1749,7 @@ void dap_chain_net_deinit()
 {
 }
 
-dap_chain_net_t **dap_chain_net_list(size_t *a_size)
+dap_chain_net_t **dap_chain_net_list(uint16_t *a_size)
 {
     *a_size = HASH_COUNT(s_net_items);
     dap_chain_net_t **l_net_list = DAP_NEW_SIZE(dap_chain_net_t *, (*a_size) * sizeof(dap_chain_net_t *));
@@ -1883,7 +1885,7 @@ char * dap_chain_net_get_gdb_group_mempool_by_chain_type(dap_chain_net_t * l_net
  */
 dap_chain_node_addr_t * dap_chain_net_get_cur_addr( dap_chain_net_t * l_net)
 {
-    return  PVT(l_net)->node_info? &PVT(l_net)->node_info->hdr.address: PVT(l_net)->node_addr;
+    return  PVT(l_net)->node_info ? &PVT(l_net)->node_info->hdr.address : PVT(l_net)->node_addr;
 }
 
 uint64_t dap_chain_net_get_cur_addr_int(dap_chain_net_t * l_net)
diff --git a/modules/net/dap_chain_node_cli.c b/modules/net/dap_chain_node_cli.c
index bca667bbdf71ba4a4544490e047f9ab269b4b300..82e0eba706c69e9bf9ffe08831294ad56d4b3e5d 100644
--- a/modules/net/dap_chain_node_cli.c
+++ b/modules/net/dap_chain_node_cli.c
@@ -935,7 +935,8 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
     dap_chain_node_cli_cmd_item_create ("tx_create", com_tx_create, NULL, "Make transaction",
             "tx_create -net <net name> -chain <chain name> -from_wallet <name> -to_addr <addr> -token <token ticker> -value <value> [-fee <addr> -value_fee <val>]\n" );
     dap_chain_node_cli_cmd_item_create ("tx_cond_create", com_tx_cond_create, NULL, "Make cond transaction",
-            "tx_cond_create todo\n" );
+            "tx_cond_create -net <net name> -token <token_ticker> -wallet_f <wallet_from> -wallet_t <wallet_to>"
+                                        "-value <value_datoshi> -unit <mb|kb|b|sec|day> -service <vpn>\n" );
     dap_chain_node_cli_cmd_item_create ("tx_verify", com_tx_verify, NULL, "Verifing transaction",
             "tx_verify  -wallet <wallet name> \n" );
 
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index ba91e40fc9b05c5ad5c3dbfc42458a97157924c7..809d073a559952b4be4e489f37c794be47a9a4f5 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -1707,10 +1707,7 @@ int com_tx_wallet(int argc, char ** argv, void *arg_func, char **str_reply)
         break;
     }
 
-    char *l_str_ret_tmp = dap_string_free(l_string_ret, false);
-    char *str_ret = dap_strdup(l_str_ret_tmp);
-    dap_chain_node_cli_set_reply_text(str_reply, str_ret);
-    DAP_DELETE(l_str_ret_tmp);
+    *str_reply = dap_string_free(l_string_ret, false);
     return 0;
 }
 
@@ -2581,12 +2578,14 @@ int com_token_decl(int argc, char ** argv, void *arg_func, char ** a_str_reply)
     // Token type
     l_arg_index=dap_chain_node_cli_find_option_val(argv, l_arg_index, argc, "-type", &l_type_str);
 
-    if (strcmp( l_type_str, "private") == 0){
-        l_type = DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL;
-    }else if (strcmp( l_type_str, "private_simple") == 0){
-        l_type = DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE;
-    }else if (strcmp( l_type_str, "public_simple") == 0){
-        l_type = DAP_CHAIN_DATUM_TOKEN_TYPE_PUBLIC;
+    if (l_type_str) {
+        if (strcmp( l_type_str, "private") == 0){
+            l_type = DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL;
+        }else if (strcmp( l_type_str, "private_simple") == 0){
+            l_type = DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE;
+        }else if (strcmp( l_type_str, "public_simple") == 0){
+            l_type = DAP_CHAIN_DATUM_TOKEN_TYPE_PUBLIC;
+        }
     }
 
     dap_chain_datum_token_t * l_datum_token = NULL;
@@ -2862,6 +2861,7 @@ int com_token_decl(int argc, char ** argv, void *arg_func, char ** a_str_reply)
         l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_by_chain_type(l_net, CHAIN_TYPE_TOKEN);
 
     }
+
     if(dap_chain_global_db_gr_set(dap_strdup(l_key_str), (uint8_t *) l_datum, l_datum_size, l_gdb_group_mempool)) {
         dap_chain_node_cli_set_reply_text(a_str_reply, "datum %s with token %s is placed in datum pool ", l_key_str,
                 l_ticker);
@@ -3681,11 +3681,11 @@ int com_stats(int argc, char ** argv, void *arg_func, char **str_reply)
 #if (defined DAP_OS_UNIX) || (defined __WIN32)
     {
         dap_cpu_monitor_init();
-        usleep(500000);
+        dap_usleep(500000);
         char *str_reply_prev = dap_strdup_printf("");
         char *str_delimiter;
         dap_cpu_stats_t s_cpu_stats = dap_cpu_get_stats();
-        for (int n_cpu_num = 0; n_cpu_num < s_cpu_stats.cpu_cores_count; n_cpu_num++) {
+        for (uint32_t n_cpu_num = 0; n_cpu_num < s_cpu_stats.cpu_cores_count; n_cpu_num++) {
             if ((n_cpu_num % 4 == 0) && (n_cpu_num != 0)) {
                 str_delimiter = dap_strdup_printf("\n");
             } else if (n_cpu_num == s_cpu_stats.cpu_cores_count - 1) {
diff --git a/modules/net/dap_dns_server.c b/modules/net/dap_dns_server.c
index b781f9892fc52a2404acecc367f787bc7c24c813..33e4b54ef1e92c52e58646c4b552fe3189fc6aa7 100644
--- a/modules/net/dap_dns_server.c
+++ b/modules/net/dap_dns_server.c
@@ -310,7 +310,7 @@ void dap_dns_server_start() {
     s_dns_server->hash_table = NULL;
     s_dns_server->instance = dap_udp_server_listen(DNS_LISTEN_PORT);
     if (!s_dns_server->instance) {
-        log_it(L_ERROR, "Can't star DNS server");
+        log_it(L_ERROR, "Can't start DNS server");
         return;
     }
     s_dns_server->instance->client_read_callback = dap_dns_client_read;
diff --git a/modules/net/include/dap_chain_net.h b/modules/net/include/dap_chain_net.h
index 3465ff818ac15aa88af1228e8dbf3440dd4f93da..b2cdeef5cbf3823738ad56f9e1b65860c1904a62 100644
--- a/modules/net/include/dap_chain_net.h
+++ b/modules/net/include/dap_chain_net.h
@@ -151,7 +151,7 @@ DAP_STATIC_INLINE char * dap_chain_net_get_gdb_group_mempool(dap_chain_t * l_cha
 
 dap_chain_t * dap_chain_net_get_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_net_t **dap_chain_net_list(size_t *a_size);
+dap_chain_net_t **dap_chain_net_list(uint16_t *a_size);
 dap_list_t * dap_chain_net_get_add_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 );
diff --git a/modules/net/srv/dap_chain_net_srv.c b/modules/net/srv/dap_chain_net_srv.c
index 15b1167389a48664c85f1d1ca62d08ef8afdc962..d928fd2ec1dc9af39fa8d4b74672e80b3bebfe4d 100644
--- a/modules/net/srv/dap_chain_net_srv.c
+++ b/modules/net/srv/dap_chain_net_srv.c
@@ -82,6 +82,7 @@ static void s_load_all(void);
  */
 int dap_chain_net_srv_init(dap_config_t * a_cfg)
 {
+    UNUSED(a_cfg);
     m_uid = NULL;
     m_uid_count = 0;
     if( dap_chain_net_srv_order_init() != 0 )
@@ -173,12 +174,13 @@ void dap_chain_net_srv_deinit(void)
  */
 static int s_cli_net_srv( int argc, char **argv, void *arg_func, char **a_str_reply)
 {
+    UNUSED(arg_func);
     int arg_index = 1;
     dap_chain_net_t * l_net = NULL;
 
     int ret = dap_chain_node_cli_cmd_values_parse_net_chain( &arg_index, argc, argv, a_str_reply, NULL, &l_net );
     if ( l_net ) {
-        char * l_orders_group = dap_chain_net_srv_order_get_gdb_group( l_net );
+        //char * l_orders_group = dap_chain_net_srv_order_get_gdb_group( l_net );
 
         dap_string_t *l_string_ret = dap_string_new("");
         const char *l_order_str = NULL;
@@ -260,7 +262,7 @@ static int s_cli_net_srv( int argc, char **argv, void *arg_func, char **a_str_re
                     if(l_ext) {
                         l_order->ext_size = strlen(l_ext) + 1;
                         l_order = DAP_REALLOC(l_order, sizeof(dap_chain_net_srv_order_t) + l_order->ext_size);
-                        strncpy(l_order->ext, l_ext, l_order->ext_size);
+                        strncpy((char *)l_order->ext, l_ext, l_order->ext_size);
                     }
                     else
                         dap_chain_net_srv_order_set_continent_region(&l_order, l_continent_num, l_region_str);
@@ -452,10 +454,10 @@ static int s_cli_net_srv( int argc, char **argv, void *arg_func, char **a_str_re
                     dap_chain_str_to_hash_fast (l_tx_cond_hash_str, &l_tx_cond_hash);
                 l_price = (uint64_t) atoll ( l_price_str );
                 l_price_unit.uint32 = (uint32_t) atol ( l_price_unit_str );
-
+                strncpy(l_price_token, l_price_token_str, DAP_CHAIN_TICKER_SIZE_MAX - 1);
                 char * l_order_new_hash_str = dap_chain_net_srv_order_create(
                             l_net,l_direction, l_srv_uid, l_node_addr,l_tx_cond_hash, l_price, l_price_unit,
-                            l_price_token, l_expires,l_ext, l_region_str, l_continent_num);
+                            l_price_token, l_expires, (uint8_t *)l_ext, strlen(l_ext) + 1, l_region_str, l_continent_num);
                 if (l_order_new_hash_str)
                     dap_string_append_printf( l_string_ret, "Created order %s\n", l_order_new_hash_str);
                 else{
diff --git a/modules/net/srv/dap_chain_net_srv_common.c b/modules/net/srv/dap_chain_net_srv_common.c
index 494923184e111d6fe4ed0b24387fdac6b108f073..46f7dcd0831f0a511e3f0b891533ab47e8c24c51 100644
--- a/modules/net/srv/dap_chain_net_srv_common.c
+++ b/modules/net/srv/dap_chain_net_srv_common.c
@@ -45,4 +45,3 @@
 #include "dap_chain_datum_tx_items.h"
 #include "dap_stream.h"
 #include "dap_chain_net_srv_common.h"
-
diff --git a/modules/net/srv/dap_chain_net_srv_order.c b/modules/net/srv/dap_chain_net_srv_order.c
index 81c490d689347d6ec19f76c970a27a76edd3f3b6..3030b70ed983b28c18232549336acded255c861e 100644
--- a/modules/net/srv/dap_chain_net_srv_order.c
+++ b/modules/net/srv/dap_chain_net_srv_order.c
@@ -124,7 +124,7 @@ bool dap_chain_net_srv_order_set_continent_region(dap_chain_net_srv_order_t **a_
  */
 bool dap_chain_net_srv_order_get_continent_region(dap_chain_net_srv_order_t *a_order, uint8_t *a_continent_num, char **a_region)
 {
-    if(!a_order || !a_order->ext_size || !a_order->ext || a_order->ext[0]!=0x52)
+    if(!a_order || !a_order->ext_size || a_order->ext[0]!=0x52)
         return false;
     if(a_continent_num) {
        if((uint8_t)a_order->ext[1]!=0xff)
@@ -205,7 +205,7 @@ int8_t dap_chain_net_srv_order_continent_to_num(const char *a_continent_str)
     return -1;
 }
 
-char* dap_chain_net_srv_order_create(
+char * dap_chain_net_srv_order_create(
         dap_chain_net_t * a_net,
         dap_chain_net_srv_order_direction_t a_direction,
         dap_chain_net_srv_uid_t a_srv_uid, // Service UID
@@ -213,25 +213,33 @@ char* dap_chain_net_srv_order_create(
         dap_chain_hash_fast_t a_tx_cond_hash, // Hash index of conditioned transaction attached with order
         uint64_t a_price, //  service price in datoshi, for SERV_CLASS_ONCE ONCE for the whole service, for SERV_CLASS_PERMANENT  for one unit.
         dap_chain_net_srv_price_unit_uid_t a_price_unit, // Unit of service (seconds, megabytes, etc.) Only for SERV_CLASS_PERMANENT
-        char a_price_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
+        const char a_price_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
         dap_chain_time_t a_expires, // TS when the service expires
-        const char *a_ext,
+        const uint8_t *a_ext,
+        uint32_t a_ext_size,
         const char *a_region,
         int8_t a_continent_num
         )
 {
+    UNUSED(a_expires);
     if (a_net) {
-        dap_chain_net_srv_order_t *l_order = DAP_NEW_Z(dap_chain_net_srv_order_t);
-        dap_chain_hash_fast_t* l_order_hash = DAP_NEW_Z(dap_chain_hash_fast_t);
+        dap_chain_net_srv_order_t *l_order;
+        if (a_ext_size) {
+            l_order = (dap_chain_net_srv_order_t *)DAP_NEW_Z_SIZE(void, sizeof(dap_chain_net_srv_order_t) + a_ext_size);
+            memcpy(l_order->ext, a_ext, a_ext_size);
+            l_order->ext_size = a_ext_size;
+        }
+        else {
+            l_order = DAP_NEW_Z(dap_chain_net_srv_order_t);
+            dap_chain_net_srv_order_set_continent_region(&l_order, a_continent_num, a_region);
+        }
+
+        dap_chain_hash_fast_t l_order_hash;
         l_order->version = 1;
         l_order->srv_uid = a_srv_uid;
         l_order->direction = a_direction;
         l_order->ts_created = (dap_chain_time_t) time(NULL);
 
-        if(a_ext)
-            strncpy(l_order->ext, a_ext, strlen(l_order->ext) + 1);
-        else
-            dap_chain_net_srv_order_set_continent_region(&l_order, a_continent_num, a_region);
 
         if ( a_node_addr.uint64)
             l_order->node_addr.uint64 = a_node_addr.uint64;
@@ -244,18 +252,14 @@ char* dap_chain_net_srv_order_create(
             strncpy(l_order->price_ticker, a_price_ticker,sizeof(l_order->price_ticker)-1);
 
         size_t l_order_size = dap_chain_net_srv_order_get_size(l_order);
-        dap_hash_fast( l_order, l_order_size, l_order_hash );
-        char * l_order_hash_str = dap_chain_hash_fast_to_str_new( l_order_hash );
+        dap_hash_fast( l_order, l_order_size, &l_order_hash );
+        char * l_order_hash_str = dap_chain_hash_fast_to_str_new( &l_order_hash );
         char * l_gdb_group_str = dap_chain_net_srv_order_get_gdb_group( a_net);
         if ( !dap_chain_global_db_gr_set( dap_strdup(l_order_hash_str), l_order, l_order_size, l_gdb_group_str ) ){
             DAP_DELETE( l_order );
-            DAP_DELETE( l_order_hash );
-            DAP_DELETE( l_order_hash_str );
             DAP_DELETE( l_gdb_group_str );
             return NULL;
         }
-        DAP_DELETE( l_order_hash );
-        //DAP_DELETE(l_order_hash_str );
         DAP_DELETE( l_gdb_group_str );
         return  l_order_hash_str;
     }else
diff --git a/modules/net/srv/include/dap_chain_net_srv_common.h b/modules/net/srv/include/dap_chain_net_srv_common.h
index 94886a340cb6faf161b449ece43fca0587aa2319..7ef7c2d8d48a89ffdb5fc37a5b504821326d4480 100755
--- a/modules/net/srv/include/dap_chain_net_srv_common.h
+++ b/modules/net/srv/include/dap_chain_net_srv_common.h
@@ -169,7 +169,8 @@ typedef struct dap_stream_ch_chain_net_srv_pkt_error{
 DAP_STATIC_INLINE const char * dap_chain_net_srv_price_unit_uid_to_str( dap_chain_net_srv_price_unit_uid_t a_uid )
 {
     switch ( a_uid.enm) {
-        case SERV_UNIT_UNDEFINED: return "BYTE";
+        case SERV_UNIT_B: return "BYTE";
+        case SERV_UNIT_KB: return "KILOBYTE";
         case SERV_UNIT_MB: return "MEGABYTE";
         case SERV_UNIT_SEC: return "SECOND";
         case SERV_UNIT_DAY: return  "DAY";
diff --git a/modules/net/srv/include/dap_chain_net_srv_order.h b/modules/net/srv/include/dap_chain_net_srv_order.h
index d99377fcbf8935a2601800a3915bee50b0d8a8c5..369fba674c2c195c7c788a5c15f87edb6069237d 100644
--- a/modules/net/srv/include/dap_chain_net_srv_order.h
+++ b/modules/net/srv/include/dap_chain_net_srv_order.h
@@ -45,7 +45,7 @@ typedef struct dap_chain_net_srv_order
     //uint8_t continent;
     //char region[32];
     uint32_t ext_size;
-    char ext[];
+    uint8_t ext[];
 } DAP_ALIGN_PACKED dap_chain_net_srv_order_t;
 
 // Init/deinit should be call only if private
@@ -71,6 +71,7 @@ DAP_STATIC_INLINE dap_chain_net_srv_order_t * dap_chain_net_srv_order_find_by_ha
         dap_chain_hash_fast_to_str(a_hash,l_hash_str,sizeof(l_hash_str)-1);
         return  dap_chain_net_srv_order_find_by_hash_str(a_net, l_hash_str );
     }
+    return NULL;
 }
 
 int dap_chain_net_srv_order_find_all_by(dap_chain_net_t * a_net,const dap_chain_net_srv_order_direction_t a_direction, const dap_chain_net_srv_uid_t a_srv_uid,
@@ -91,17 +92,17 @@ DAP_STATIC_INLINE int dap_chain_net_srv_order_delete_by_hash(dap_chain_net_t * a
     return dap_chain_net_srv_order_delete_by_hash_str ( a_net, l_hash_str);
 }
 
-char* dap_chain_net_srv_order_create(
-        dap_chain_net_t * a_net,
+char *dap_chain_net_srv_order_create(dap_chain_net_t * a_net,
         dap_chain_net_srv_order_direction_t a_direction,
         dap_chain_net_srv_uid_t a_srv_uid, // Service UID
         dap_chain_node_addr_t a_node_addr, // Node address that servs the order (if present)
         dap_chain_hash_fast_t a_tx_cond_hash, // Hash index of conditioned transaction attached with order
         uint64_t a_price, //  service price in datoshi, for SERV_CLASS_ONCE ONCE for the whole service, for SERV_CLASS_PERMANENT  for one unit.
         dap_chain_net_srv_price_unit_uid_t a_price_unit, // Unit of service (seconds, megabytes, etc.) Only for SERV_CLASS_PERMANENT
-        char a_price_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
+        const char a_price_ticker[],
         dap_chain_time_t a_expires, // TS when the service expires
-        const char *a_ext,
+        const uint8_t *a_ext,
+        uint32_t a_ext_size,
         const char *a_region,
         int8_t a_continent_num
         );
diff --git a/modules/service/xchange/CMakeLists.txt b/modules/service/xchange/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0d2888afb0c413051f9beceded4c57e21a9c1b23
--- /dev/null
+++ b/modules/service/xchange/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 2.8)
+project (dap_chain_net_srv_xchange)
+  
+file(GLOB DAP_SRV_XCHANGE_SRCS *.c)
+
+file(GLOB DAP_SRV_XCHANGE_HEADERS include/*.h)
+
+add_library(${PROJECT_NAME} STATIC ${DAP_SRV_XCHANGE_SRCS} ${DAP_SRV_XCHANGE_HEADERS})
+
+target_include_directories(dap_chain_crypto INTERFACE .)
+target_include_directories(${PROJECT_NAME} PUBLIC include)
+target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_chain dap_chain_crypto dap_chain_net dap_chain_net_srv)
diff --git a/modules/service/xchange/dap_chain_net_srv_xchange.c b/modules/service/xchange/dap_chain_net_srv_xchange.c
new file mode 100644
index 0000000000000000000000000000000000000000..75b4c2b48d5fd000e6582fbb8640319d375656a4
--- /dev/null
+++ b/modules/service/xchange/dap_chain_net_srv_xchange.c
@@ -0,0 +1,801 @@
+/*
+ * Authors:
+ * Roman Khlopkov <roman.khlopkov@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * DeM Labs Open source community https://gitlab.demlabs.net
+ * Copyright  (c) 2017-2020
+ * 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_string.h"
+#include "dap_chain_common.h"
+#include "dap_chain_node_cli.h"
+#include "dap_chain_mempool.h"
+#include "dap_chain_net_srv_common.h"
+#include "dap_chain_net_srv_xchange.h"
+
+#define LOG_TAG "dap_chain_net_srv_xchange"
+
+static int s_cli_srv_xchange(int a_argc, char **a_argv, void *a_arg_func, char **a_str_reply);
+static int s_callback_requested(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_t *a_srv_client, const void *a_data, size_t a_data_size);
+static int s_callback_response_success(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_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_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_t *a_srv_client, const void *a_data, size_t a_data_size);
+
+static dap_chain_net_srv_xchange_t *s_srv_xchange;
+
+/**
+ * @brief dap_stream_ch_vpn_init Init actions for VPN stream channel
+ * @param vpn_addr Zero if only client mode. Address if the node shares its local VPN
+ * @param vpn_mask Zero if only client mode. Mask if the node shares its local VPN
+ * @return 0 if everything is okay, lesser then zero if errors
+ */
+int dap_chain_net_srv_xchange_init()
+{
+        dap_chain_node_cli_cmd_item_create("srv_xchange", s_cli_srv_xchange, NULL, "eXchange service commands",
+        "srv_xchange price create -net_sell <net name> -token_sell <token ticker> -net_buy <net_name> -token_buy <token ticker>"
+                                            "-wallet <name> -datoshi_sell <value> -datoshi_buy <value>\n"
+            "\tCreate a new price with specified amounts of datoshi to exchange\n"
+        "srv_xchange price remove -net_sell <net name> -token_sell <token ticker> -net_buy <net_name> -token_buy <token ticker>\n"
+             "\tRemove price with specified tickers within specified net names\n"
+        "srv_xchange price list\n"
+             "\tList all active prices\n"
+        "srv_xchange price update -net_sell <net name> -token_sell <token ticker> -net_buy <net_name> -token_buy <token ticker>"
+                                            "{-datoshi_sell <value> | datoshi_buy <value> | -wallet <name>}\n"
+             "\tUpdate price with specified tickers within specified net names\n"
+        "srv_xchange purchase <order hash> -net <net name> -wallet <wallet_name>\n"
+             "\tExchange tokens with specified order within specified net name\n"
+        "srv_xchange enable\n"
+             "\tEnable eXchange service\n"
+        "srv_xchange disable\n"
+             "\tDisable eXchange service\n"
+        );
+        dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_XCHANGE_ID };
+        dap_chain_net_srv_t* l_srv = dap_chain_net_srv_add(l_uid, s_callback_requested, s_callback_response_success,
+                                                           s_callback_response_error, s_callback_receipt_next_success);
+        s_srv_xchange  = DAP_NEW_Z(dap_chain_net_srv_xchange_t);
+        l_srv->_inhertor = s_srv_xchange;
+        s_srv_xchange->enabled = false;
+        return 0;
+}
+
+void dap_chain_net_srv_xchange_deinit()
+{
+    dap_chain_net_srv_xchange_price_t *l_price = NULL, *l_tmp;
+    HASH_ITER(hh, s_srv_xchange->pricelist, l_price, l_tmp) {
+        HASH_DEL(s_srv_xchange->pricelist, l_price);
+        DAP_DELETE(l_price->key_ptr);
+        DAP_DELETE(l_price);
+    }
+    dap_chain_net_srv_del(s_srv_xchange->parent);
+    DAP_DELETE(s_srv_xchange);
+}
+
+bool dap_chain_net_srv_xchange_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx)
+{
+    /* Check only one of following conditions for verification success
+     * 1. addr(a_cond.params).data.key == a_tx.sign.pkey -- for condition owner
+     * 2. a_cond.srv_xchange.(value && token && addr) == a_tx.out.(value && token && addr) -- for exchange
+     */
+    dap_chain_addr_t *l_seller_addr = (dap_chain_addr_t *)a_cond->params;
+    dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_SIG, NULL);
+    dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t *)l_tx_sig);
+    size_t l_pkey_ser_size = 0;
+    const uint8_t *l_pkey_ser = dap_sign_get_pkey(l_sign, &l_pkey_ser_size);
+    if (!memcmp(l_seller_addr->data.key, l_pkey_ser, l_pkey_ser_size)) {
+        // it's the condition owner, let the transaction to be performed
+        return true;
+    } else {
+        dap_list_t *l_list_out = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_OUT_EXT, NULL);
+
+        uint64_t l_out_val = 0;
+        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, &a_cond->params, sizeof(dap_chain_addr_t)) ||
+                    strcmp(l_tx_out->token, a_cond->subtype.srv_xchange.token)) {
+                continue;
+            }
+            l_out_val += l_tx_out->header.value;
+        }
+        if (l_out_val != a_cond->subtype.srv_xchange.value) {
+            return false;
+        }
+    }
+    return true;
+}
+
+static dap_chain_datum_tx_receipt_t *s_xchage_receipt_create(dap_chain_net_srv_xchange_price_t *a_price)
+{
+    uint32_t l_ext_size = sizeof(uint64_t) + DAP_CHAIN_TICKER_SIZE_MAX;
+    uint8_t *l_ext = DAP_NEW_SIZE(uint8_t, l_ext_size);
+    dap_lendian_put64(l_ext, a_price->datoshi_sell);
+    strcpy((char *)&l_ext[sizeof(uint64_t)], a_price->token_sell);
+    dap_chain_net_srv_price_unit_uid_t l_unit = { .uint32 = SERV_UNIT_UNDEFINED};
+    dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_XCHANGE_ID };
+    dap_chain_datum_tx_receipt_t *l_receipt =  dap_chain_datum_tx_receipt_create(l_uid, l_unit, 0, a_price->datoshi_buy,
+                                                                                 l_ext, l_ext_size);
+    return l_receipt;
+}
+
+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)
+{
+    if (!a_price || !a_price->net_sell || !a_price->net_buy || !*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_sell->pub.name);
+    dap_chain_addr_t *l_seller_addr = (dap_chain_addr_t *)dap_chain_wallet_get_addr(a_wallet, a_price->net_sell->pub.id);
+    dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0);
+    uint64_t l_value_sell = 0; // 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);
+    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;
+    }
+
+    // add 'in' items to sell
+    uint64_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+    dap_list_free_full(l_list_used_out, free);
+    if (l_value_to_items != l_value_sell) {
+        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
+    {
+        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_sell->pub.id,
+                                                                                                a_price->token_sell, a_price->datoshi_sell,
+                                                                                                (void *)l_seller_addr, sizeof(dap_chain_addr_t));
+        if (!l_tx_out) {
+            dap_chain_datum_tx_delete(l_tx);
+            DAP_DELETE(l_seller_addr);
+            log_it(L_ERROR, "Can't compose the transaction conditional output");
+            return NULL;
+        }
+        dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out);
+        DAP_DELETE(l_tx_out);
+        // coin back
+        uint64_t l_value_back = l_value_sell - a_price->datoshi_sell;
+        if (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);
+                DAP_DELETE(l_seller_addr);
+                log_it(L_ERROR, "Cant add coin back output");
+                return NULL;
+            }
+        }
+    }
+    DAP_DELETE(l_seller_addr);
+
+    // add 'sign' item
+    if(dap_chain_datum_tx_add_sign_item(&l_tx, l_seller_key) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        log_it(L_ERROR, "Can't add sign output");
+        return NULL;
+    }
+
+    return l_tx;
+}
+
+static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_hash_fast_t *a_tx_cond_hash, dap_chain_wallet_t *a_wallet)
+{
+    if (!a_price || !a_price->net_sell || !a_price->net_buy || !*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_sell->pub.name);
+    dap_chain_addr_t *l_seller_addr = (dap_chain_addr_t *) dap_chain_wallet_get_addr(a_wallet, a_price->net_sell->pub.id);
+    dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0);
+    uint64_t l_value_sell = 0; // 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);
+    if(!l_list_used_out) {
+        dap_chain_datum_tx_delete(l_tx);
+        log_it(L_WARNING, "Nothing to change (not enough funds)");
+        return NULL;
+    }
+
+    // create and add reciept
+    dap_chain_datum_tx_receipt_t *l_receipt = s_xchage_receipt_create(a_price);
+    dap_chain_datum_tx_add_item(&l_tx, (byte_t *)l_receipt);
+    DAP_DELETE(l_receipt);
+    // add 'in' items to sell
+    uint64_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out);
+    dap_list_free_full(l_list_used_out, free);
+    if (l_value_to_items != l_value_sell) {
+        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 '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_tx_cond_hash);
+    if (!l_cond_tx) {
+        log_it(L_WARNING, "Requested conditional transaction not found");
+        return NULL;
+    }
+    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_datum_tx_add_in_cond_item(&l_tx, a_tx_cond_hash, l_prev_cond_idx, 0);
+    // add 'out' items
+    {
+        // transfer selling coins
+        const dap_chain_addr_t *l_buyer_addr = (dap_chain_addr_t *)l_tx_out_cond->params;
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_buyer_addr, a_price->datoshi_sell, a_price->token_sell) == -1) {
+            dap_chain_datum_tx_delete(l_tx);
+            DAP_DELETE(l_seller_addr);
+            log_it(L_ERROR, "Can't add selling coins output");
+            return NULL;
+        }
+        // coin back
+        uint64_t l_value_back = l_value_sell - a_price->datoshi_sell;
+        if (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) {
+                dap_chain_datum_tx_delete(l_tx);
+                DAP_DELETE(l_seller_addr);
+                log_it(L_ERROR, "Can't add selling coins back output");
+                return NULL;
+            }
+        }
+        //transfer buying coins
+        if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_seller_addr, a_price->datoshi_buy, a_price->token_buy) == -1) {
+            dap_chain_datum_tx_delete(l_tx);
+            DAP_DELETE(l_seller_addr);
+            log_it(L_ERROR, "Cant add buying coins output");
+            return NULL;
+        }
+        DAP_DELETE(l_seller_addr);
+        //transfer unbuying coins (partial exchange)
+        uint64_t l_buying_value = l_tx_out_cond->header.value;
+        l_value_back = l_buying_value - a_price->datoshi_buy;
+        if (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) {
+                log_it(L_WARNING, "Partial exchange not allowed");
+                return NULL;
+            //}
+        }
+    }
+
+    // add 'sign' items
+    if(dap_chain_datum_tx_add_sign_item(&l_tx, l_seller_key) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        log_it( L_ERROR, "Can't add sign output");
+        return NULL;
+    }
+
+    return l_tx;
+}
+
+
+// Put the transaction to mempool or directly to chains & write transaction's hash to the price
+static bool s_xchange_tx_put(dap_chain_datum_tx_t *a_tx, dap_chain_net_t *a_net)
+{
+    // Put the transaction to mempool or directly to chains
+    size_t l_tx_size = dap_chain_datum_tx_get_size(a_tx);
+    dap_chain_datum_t *l_datum = dap_chain_datum_create(DAP_CHAIN_DATUM_TX, a_tx, l_tx_size);
+    DAP_DELETE(a_tx);
+    dap_chain_t *l_chain = dap_chain_net_get_chain_by_chain_type(a_net, CHAIN_TYPE_TX);
+    if (!l_chain) {
+        return false;
+    }
+    dap_chain_node_role_t l_role = dap_chain_net_get_role(a_net);
+    size_t l_datums_number;
+    switch (l_role.enums) {
+        case NODE_ROLE_ROOT:
+        case NODE_ROLE_MASTER:
+        case NODE_ROLE_ROOT_MASTER:
+        case NODE_ROLE_CELL_MASTER:
+            l_datums_number = l_chain->callback_datums_pool_proc(l_chain, &l_datum, 1);
+            break;
+        default:
+            l_datums_number = dap_chain_mempool_datum_add(l_datum, l_chain);
+    }
+    if(!l_datums_number) {
+        DAP_DELETE(l_datum);
+        return false;
+    }
+    return true;
+}
+
+static bool s_xchage_tx_invalidate(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_wallet_t *a_wallet)
+{
+    // 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_sell->pub.name);
+    dap_chain_addr_t *l_seller_addr = (dap_chain_addr_t *) dap_chain_wallet_get_addr(a_wallet, a_price->net_sell->pub.id);
+    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);
+    dap_chain_datum_tx_add_item(&l_tx, (byte_t *)l_receipt);
+    DAP_DELETE(l_receipt);
+
+    // 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) {
+        log_it(L_WARNING, "Requested conditional transaction not found");
+        return false;
+    }   
+    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);
+    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 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))) {
+        log_it(L_WARNING, "Only owner can invalidate exchange transaction");
+        return false;
+    }
+    if (dap_chain_datum_tx_add_out_item(&l_tx, l_seller_addr, l_tx_out_cond->header.value) == -1) {
+        dap_chain_datum_tx_delete(l_tx);
+        DAP_DELETE(l_seller_addr);
+        log_it(L_ERROR, "Cant add returning coins output");
+        return false;
+    }
+    DAP_DELETE(l_seller_addr);
+
+    // add 'sign' items
+    if(dap_chain_datum_tx_add_sign_item(&l_tx, l_seller_key) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        log_it( L_ERROR, "Can't add sign output");
+        return false;
+    }
+    if (!s_xchange_tx_put(l_tx, a_price->net_sell)) {
+        return false;
+    }
+    return true;
+}
+
+char *s_xchange_order_create(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_datum_tx_t *a_tx)
+{
+    dap_chain_hash_fast_t l_tx_hash = {};
+    dap_hash_fast(a_tx, dap_chain_datum_tx_get_size(a_tx), &l_tx_hash);
+    memcpy(&a_price->tx_hash, &l_tx_hash, sizeof(dap_chain_hash_fast_t));
+    dap_srv_xchange_order_ext_t l_ext;
+    dap_lendian_put64((uint8_t *)&l_ext.net_sell_id, a_price->net_sell->pub.id.uint64);
+    dap_lendian_put64((uint8_t *)&l_ext.datoshi_sell, a_price->datoshi_sell);
+    strcpy(l_ext.token_sell, a_price->token_sell);
+    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_sell);
+    dap_chain_net_srv_price_unit_uid_t l_unit = { .uint32 =  SERV_UNIT_UNDEFINED};
+    dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_XCHANGE_ID };
+    char *l_order_hash_str = dap_chain_net_srv_order_create(a_price->net_buy, SERV_DIR_SELL, l_uid, *l_node_addr,
+                                                            l_tx_hash, a_price->datoshi_buy, l_unit, a_price->token_buy, 0,
+                                                            (uint8_t *)&l_ext, l_ext_size, NULL, 0);
+    return l_order_hash_str;
+}
+
+static int s_cli_srv_xchange_price(int a_argc, char **a_argv, int a_arg_index, char **a_str_reply)
+{
+    enum {
+        CMD_NONE, CMD_CREATE, CMD_REMOVE, CMD_LIST, CMD_UPDATE
+    };
+    int l_cmd_num = CMD_NONE;
+    if(dap_chain_node_cli_find_option_val(a_argv, a_arg_index, min(a_argc, a_arg_index + 1), "create", NULL)) {
+        l_cmd_num = CMD_CREATE;
+    }
+    else if(dap_chain_node_cli_find_option_val(a_argv, a_arg_index, min(a_argc, a_arg_index + 1), "remove", NULL)) {
+        l_cmd_num = CMD_REMOVE;
+    }
+    else if(dap_chain_node_cli_find_option_val(a_argv, a_arg_index, min(a_argc, a_arg_index + 1), "list", NULL)) {
+        l_cmd_num = CMD_LIST;
+    }
+    else if(dap_chain_node_cli_find_option_val(a_argv, a_arg_index, min(a_argc, a_arg_index + 1), "update", NULL)) {
+        l_cmd_num = CMD_UPDATE;
+    }
+    int l_arg_index = a_arg_index + 1;
+    const char *l_net_sell_str = NULL, *l_net_buy_str = NULL;
+    const char *l_token_sell_str = NULL, *l_token_buy_str = NULL;
+    dap_chain_net_t *l_net_sell = NULL, *l_net_buy = NULL;
+    char *l_strkey;
+    if (l_cmd_num == CMD_CREATE || l_cmd_num == CMD_REMOVE || l_cmd_num == CMD_UPDATE) {
+        dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-net_sell", &l_net_sell_str);
+        if (!l_net_sell_str) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'price %s' required parameter -net_sell",
+                                                            l_cmd_num == CMD_CREATE ? "create" : (l_cmd_num == CMD_REMOVE ? "remove" : "update"));
+            return -2;
+        }
+        l_net_sell = dap_chain_net_by_name(l_net_sell_str);
+        if (!l_net_sell) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "Network %s not found", l_net_sell_str);
+            return -3;
+        }
+        dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-net_buy", &l_net_buy_str);
+        if (!l_net_buy_str) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'price %s' required parameter -net_buy",
+                                                            l_cmd_num == CMD_CREATE ? "create" : (l_cmd_num == CMD_REMOVE ? "remove" : "update"));
+            return -2;
+        }
+        l_net_buy = dap_chain_net_by_name(l_net_buy_str);
+        if (!l_net_sell) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "Network %s not found", l_net_buy_str);
+            return -3;
+        }
+        dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-token_sell", &l_token_sell_str);
+        if (!l_token_sell_str) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'price %s' required parameter -token_sell",
+                                                            l_cmd_num == CMD_CREATE ? "create" : (l_cmd_num == CMD_REMOVE ? "remove" : "update"));
+            return -5;
+        }
+        if (!dap_chain_ledger_token_ticker_check(l_net_sell->pub.ledger, l_token_sell_str)) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "Token ticker %s not found", l_token_sell_str);
+            return -6;
+        }
+        dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-token_buy", &l_token_buy_str);
+        if (!l_token_buy_str) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'price %s' required parameter -token_buy",
+                                                            l_cmd_num == CMD_CREATE ? "create" : (l_cmd_num == CMD_REMOVE ? "remove" : "update"));
+            return -5;
+        }
+        if (!dap_chain_ledger_token_ticker_check(l_net_buy->pub.ledger, l_token_buy_str)) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "Token ticker %s not found", l_token_buy_str);
+            return -6;
+        }
+        l_strkey = DAP_NEW_SIZE(char, dap_strlen(l_token_sell_str) + dap_strlen(l_net_sell_str) +
+                                dap_strlen(l_token_buy_str) + dap_strlen(l_net_buy_str) + 1);
+        dap_stpcpy(l_strkey, l_token_sell_str);
+        strcat(l_strkey, l_net_sell_str);
+        strcat(l_strkey, l_token_buy_str);
+        strcat(l_strkey, l_net_buy_str);
+    }
+    switch (l_cmd_num) {
+        case CMD_CREATE: {
+            dap_chain_net_srv_xchange_price_t *l_price = NULL;
+            HASH_FIND_STR(s_srv_xchange->pricelist, l_strkey, l_price);
+            if (l_price) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Price with provided pair of token ticker + net name already exist");
+                return -7;
+            }
+            const char *l_val_sell_str = NULL, *l_val_buy_str = NULL, *l_wallet_str = NULL;
+            dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-datoshi_sell", &l_val_sell_str);
+            if (!l_val_sell_str) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'price create' required parameter -datoshi_sell");
+                return -8;
+            }
+            uint64_t l_datoshi_sell = strtoull(l_val_sell_str, NULL, 10);
+            if (!l_datoshi_sell) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Format -datoshi_sell <unsigned long long>");
+                return -9;
+            }
+            dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-datoshi_buy", &l_val_buy_str);
+            if (!l_val_buy_str) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'price create' required parameter -datoshi_buy");
+                return -8;
+            }
+            uint64_t l_datoshi_buy = strtoull(l_val_buy_str, NULL, 10);
+            if (!l_datoshi_buy) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Format -datoshi_buy <unsigned long long>");
+                return -9;
+            }
+            dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-wallet", &l_wallet_str);
+            if (!l_wallet_str) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'price create' required parameter -wallet");
+                return -10;
+            }
+            dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, dap_chain_wallet_get_path(g_config));
+            if (!l_wallet) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Specified wallet not found");
+                return -11;
+            }
+            if (dap_chain_wallet_get_balance(l_wallet, l_net_sell->pub.id, l_token_sell_str) < l_datoshi_sell) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Not enough cash in specified wallet");
+                dap_chain_wallet_close(l_wallet);
+                return -12;
+            }
+            // Create the price
+            l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t);
+            l_price->wallet_str = dap_strdup(l_wallet_str);
+            dap_stpcpy(l_price->token_sell, l_token_sell_str);
+            l_price->net_sell = l_net_sell;
+            dap_stpcpy(l_price->token_buy, l_token_buy_str);
+            l_price->net_buy = l_net_buy;
+            l_price->key_ptr = l_strkey;
+            l_price->datoshi_sell = l_datoshi_sell;
+            l_price->datoshi_buy = l_datoshi_buy;
+            // Create conditional transaction
+            dap_chain_datum_tx_t *l_tx = s_xchange_tx_create_request(l_price, l_wallet);
+            dap_chain_wallet_close(l_wallet);
+            if (!l_tx) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Can't compose the conditional transaction");
+                DAP_DELETE(l_price);
+                break;
+            }
+            // Create the order & put it to GDB
+            char *l_order_hash_str = s_xchange_order_create(l_price, l_tx);
+            if (l_order_hash_str) {
+                dap_chain_str_to_hash_fast(l_order_hash_str, &l_price->order_hash);
+                if(!s_xchange_tx_put(l_tx, l_net_buy)) {
+                    dap_chain_node_cli_set_reply_text(a_str_reply, "Can't put transaction to mempool/chains");
+                    dap_chain_net_srv_order_delete_by_hash_str(l_net_buy, l_order_hash_str);
+                    DAP_DELETE(l_order_hash_str);
+                    break;
+                }
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Successfully created order %s", l_order_hash_str);
+                DAP_DELETE(l_order_hash_str);
+                // Add active price to pricelist
+                HASH_ADD_KEYPTR(hh, s_srv_xchange->pricelist, l_price->key_ptr, strlen(l_price->key_ptr), l_price);
+            } else {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Can't compose the order");
+                DAP_DELETE(l_price->key_ptr);
+                DAP_DELETE(l_price);
+            }
+        } break;
+        case CMD_REMOVE:
+        case CMD_UPDATE: {
+            dap_chain_net_srv_xchange_price_t *l_price = NULL;
+            HASH_FIND_STR(s_srv_xchange->pricelist, l_strkey, l_price);
+            if (l_price) {
+                if (l_cmd_num == CMD_REMOVE) {
+                    dap_string_t *l_str_reply = dap_string_new("");
+                    HASH_DEL(s_srv_xchange->pricelist, l_price);
+                    dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_price->wallet_str, dap_chain_wallet_get_path(g_config));
+                    bool l_ret = s_xchage_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(l_price->net_buy, l_order_hash_str)) {
+                        dap_string_append_printf(l_str_reply, "Can't remove order %s\n", l_order_hash_str);
+                    }
+                    DAP_DELETE(l_order_hash_str);
+                    DAP_DELETE(l_price->key_ptr);
+                    DAP_DELETE(l_price->wallet_str);
+                    DAP_DELETE(l_price);
+                    if (!l_str_reply->len) {
+                        dap_string_append(l_str_reply, "Price successfully removed");
+                    }
+                    *a_str_reply = dap_string_free(l_str_reply, false);
+                } else {    // CMD_UPDATE
+                    const char *l_val_sell_str = NULL, *l_val_buy_str = NULL, *l_wallet_str = NULL, *l_new_wallet_str = NULL;
+                    uint64_t l_datoshi_sell = 0, l_datoshi_buy = 0;
+                    dap_chain_wallet_t *l_wallet = NULL;
+                    dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-datoshi_sell", &l_val_sell_str);
+                    if (l_val_sell_str) {
+                        l_datoshi_sell = strtoull(l_val_sell_str, NULL, 10);
+                        if (!l_datoshi_sell) {
+                            dap_chain_node_cli_set_reply_text(a_str_reply, "Format -datoshi_sell <unsigned long long>");
+                            return -9;
+                        }
+                    }
+                    dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-datoshi_buy", &l_val_buy_str);
+                    if (l_val_buy_str) {
+                        l_datoshi_buy = strtoull(l_val_buy_str, NULL, 10);
+                        if (!l_datoshi_buy) {
+                            dap_chain_node_cli_set_reply_text(a_str_reply, "Format -datoshi_buy <unsigned long long>");
+                            return -9;
+                        }
+                    }
+                    dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-wallet", &l_new_wallet_str);
+                    l_wallet_str = l_new_wallet_str ? l_new_wallet_str : l_price->wallet_str;
+                    l_wallet = dap_chain_wallet_open(l_wallet_str, dap_chain_wallet_get_path(g_config));
+                    if (!l_wallet) {
+                        dap_chain_node_cli_set_reply_text(a_str_reply, "Specified wallet not found");
+                        return -11;
+                    }
+                    if (!l_val_sell_str && !l_val_buy_str && !l_wallet_str) {
+                        dap_chain_node_cli_set_reply_text(a_str_reply, "At least one of updating parameters is mandatory");
+                        return -13;
+                    }
+                    if (l_datoshi_sell && dap_chain_wallet_get_balance(l_wallet, l_net_sell->pub.id, l_token_sell_str) < l_datoshi_sell) {
+                            dap_chain_node_cli_set_reply_text(a_str_reply, "Not enough cash in specified wallet");
+                            dap_chain_wallet_close(l_wallet);
+                            return -12;
+                    }
+                    if (l_val_sell_str) {
+                        l_price->datoshi_sell = l_datoshi_sell;
+                    }
+                    if (l_val_buy_str) {
+                        l_price->datoshi_buy = l_datoshi_buy;
+                    }
+                    // Update the transaction
+                    dap_chain_datum_tx_t *l_tx = s_xchange_tx_create_request(l_price, l_wallet);
+                    if (l_new_wallet_str) {
+                        dap_chain_wallet_close(l_wallet);
+                        l_wallet = dap_chain_wallet_open(l_price->wallet_str, dap_chain_wallet_get_path(g_config));
+                        DAP_DELETE(l_price->wallet_str);
+                        l_price->wallet_str = dap_strdup(l_new_wallet_str);
+                    }
+                    if (!l_tx) {
+                        dap_chain_node_cli_set_reply_text(a_str_reply, "Can't compose the conditional transaction");
+                        break;
+                    }
+                    HASH_DEL(s_srv_xchange->pricelist, l_price);
+                    bool l_ret = s_xchage_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);
+                        dap_chain_node_cli_set_reply_text(a_str_reply, "Can't invalidate transaction %s\n", l_tx_hash_str);
+                        DAP_DELETE(l_tx_hash_str);
+                        break;
+                    }
+                    // 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(l_price->net_buy, l_order_hash_str);
+                    DAP_DELETE(l_order_hash_str);
+                    l_order_hash_str = s_xchange_order_create(l_price, l_tx);
+                    if (l_order_hash_str) {
+                        dap_chain_str_to_hash_fast(l_order_hash_str, &l_price->order_hash);
+                        if(!s_xchange_tx_put(l_tx, l_net_buy)) {
+                            dap_chain_node_cli_set_reply_text(a_str_reply, "Can't put transaction to mempool/chains");
+                            dap_chain_net_srv_order_delete_by_hash_str(l_net_buy, l_order_hash_str);
+                            break;
+                        } else {
+                            dap_chain_node_cli_set_reply_text(a_str_reply, "Successfully created order %s", l_order_hash_str);
+                        }
+                        DAP_DELETE(l_order_hash_str);
+                    } else {
+                        dap_chain_node_cli_set_reply_text(a_str_reply, "Can't compose the order");
+                        DAP_DELETE(l_price->key_ptr);
+                        DAP_DELETE(l_price);
+                        break;
+                    }
+                    // Update the pricelist
+                    HASH_ADD_KEYPTR(hh, s_srv_xchange->pricelist, l_price->key_ptr, strlen(l_price->key_ptr), l_price);
+                }
+            } else {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Price with provided pair of token ticker + net name is not exist");
+                return -1;
+            }
+        } break;
+        case CMD_LIST: {
+            dap_chain_net_srv_xchange_price_t *l_price = NULL, *l_tmp;
+            dap_string_t *l_reply_str = dap_string_new("");
+            HASH_ITER(hh, s_srv_xchange->pricelist, l_price, l_tmp) {
+                char *l_order_hash_str = dap_chain_hash_fast_to_str_new(&l_price->order_hash);
+                dap_string_append_printf(l_reply_str, "%s\t%s\t%s\t%s\t%lu\t%lu\t%s\t%s\n", l_price->token_sell, l_price->net_sell->pub.name,
+                                         l_price->token_buy, l_price->net_buy->pub.name, l_price->datoshi_sell,
+                                         l_price->datoshi_buy, l_price->wallet_str, l_order_hash_str);
+                DAP_DELETE(l_order_hash_str);
+            }
+            if (!l_reply_str->len) {
+                dap_string_append(l_reply_str, "Pricelist is empty");
+            }
+            *a_str_reply = dap_string_free(l_reply_str, false);
+        } break;
+        default: {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "Subcommand %s not recognized", a_argv[a_arg_index]);
+            return -4;
+        }
+    }
+    return 0;
+}
+
+static int s_cli_srv_xchange(int a_argc, char **a_argv, void *a_arg_func, char **a_str_reply)
+{
+    UNUSED(a_arg_func);
+    enum {
+        CMD_NONE, CMD_PRICE, CMD_PURCHASE, CMD_ENABLE, CMD_DISABLE
+    };
+    int l_arg_index = 1;
+    int l_cmd_num = CMD_NONE;
+    if(dap_chain_node_cli_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "price", NULL)) {
+        l_cmd_num = CMD_PRICE;
+    }
+    else if(dap_chain_node_cli_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "purchase", NULL)) {
+        l_cmd_num = CMD_PURCHASE;
+    }
+    else if(dap_chain_node_cli_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "enable", NULL)) {
+        l_cmd_num = CMD_ENABLE;
+    }
+    else if(dap_chain_node_cli_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "disable", NULL)) {
+        l_cmd_num = CMD_DISABLE;
+    }
+    switch (l_cmd_num) {
+        case CMD_PRICE:
+            return s_cli_srv_xchange_price(a_argc, a_argv, l_arg_index + 1, a_str_reply);
+        case CMD_PURCHASE: {
+            const char *l_net_str = NULL, *l_wallet_str = 0;
+            dap_chain_node_cli_find_option_val(a_argv, ++l_arg_index + 1, a_argc, "-net", &l_net_str);
+            if (!l_net_str) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'purchase' required parameter -net");
+                return -2;
+            }
+            dap_chain_net_t *l_net = dap_chain_net_by_name(l_net_str);
+            if (!l_net) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Network %s not found", l_net_str);
+                return -3;
+            }
+            dap_chain_node_cli_find_option_val(a_argv, l_arg_index + 1, a_argc, "-wallet", &l_wallet_str);
+            if (!l_wallet_str) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'purchase' required parameter -wallet");
+                return -10;
+            }
+            dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, dap_chain_wallet_get_path(g_config));
+            if (!l_wallet) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Specified wallet not found");
+                return -11;
+            }
+            char *l_order_hash_str = a_argv[l_arg_index];
+            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_chain_net_srv_xchange_price_t *l_price = DAP_NEW(dap_chain_net_srv_xchange_price_t);
+                l_price->net_sell = l_net;
+                strcpy(l_price->token_sell, l_order->price_ticker);
+                l_price->datoshi_sell = l_order->price;
+                dap_srv_xchange_order_ext_t *l_ext = (dap_srv_xchange_order_ext_t *)l_order->ext;
+                dap_chain_net_id_t l_net_buy_id = { .uint64 = dap_lendian_get64((uint8_t *)&l_ext->net_sell_id) };
+                l_price->net_buy = dap_chain_net_by_id(l_net_buy_id);
+                l_price->datoshi_buy = dap_lendian_get64((uint8_t *)&l_ext->datoshi_sell);
+                strcpy(l_price->token_buy, l_ext->token_sell);
+                // Create conditional transaction
+                dap_chain_datum_tx_t *l_tx = s_xchange_tx_create_exchange(l_price, &l_order->tx_cond_hash, l_wallet);
+                if (l_tx && s_xchange_tx_put(l_tx, l_net)) {
+                    // TODO send request to seller to delete order & price
+                    dap_chain_net_srv_order_delete_by_hash_str(l_price->net_buy, l_order_hash_str);
+                }
+                DAP_DELETE(l_price);
+                DAP_DELETE(l_order);
+                dap_chain_node_cli_set_reply_text(a_str_reply, l_tx ? "Exchange transaction has done" :
+                                                                      "Exchange transaction error");
+            }
+        } break;
+        case CMD_ENABLE: {
+            s_srv_xchange->enabled = true;
+        } break;
+        case CMD_DISABLE: {
+            s_srv_xchange->enabled = false;
+        } break;
+        default: {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "Command %s not recognized", a_argv[l_arg_index]);
+            return -1;
+        }
+    }
+    return 0;
+}
+
+static int s_callback_requested(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_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_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_t *a_srv_client, const void *a_data, size_t a_data_size)
+{
+    return 0;
+}
+
+static int s_callback_receipt_next_success(dap_chain_net_srv_t *a_srv, uint32_t a_usage_id, dap_chain_net_srv_client_t *a_srv_client, const void *a_data, size_t a_data_size)
+{
+    return 0;
+}
diff --git a/modules/service/xchange/include/dap_chain_net_srv_xchange.h b/modules/service/xchange/include/dap_chain_net_srv_xchange.h
new file mode 100644
index 0000000000000000000000000000000000000000..0ab6610b71c5dd5e0491d7e8021ec87045090b7d
--- /dev/null
+++ b/modules/service/xchange/include/dap_chain_net_srv_xchange.h
@@ -0,0 +1,60 @@
+/*
+ * Authors:
+ * Roman Khlopkov <roman.khlopkov@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * DeM Labs Open source community https://gitlab.demlabs.net
+ * Copyright  (c) 2017-2020
+ * 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_srv.h"
+#include "dap_chain_net_srv_order.h"
+
+#define DAP_CHAIN_NET_SRV_XCHANGE_ID 0x2
+
+typedef struct dap_chain_net_srv_xchange_price {
+    char *wallet_str;
+    dap_chain_net_t *net_sell;
+    char token_sell[DAP_CHAIN_TICKER_SIZE_MAX];
+    uint64_t datoshi_sell;
+    dap_chain_net_t *net_buy;
+    char token_buy[DAP_CHAIN_TICKER_SIZE_MAX];
+    uint64_t datoshi_buy;
+    dap_chain_hash_fast_t tx_hash;
+    dap_chain_hash_fast_t order_hash;
+    char *key_ptr;
+    UT_hash_handle hh;
+} dap_chain_net_srv_xchange_price_t;
+
+typedef struct dap_srv_xchange_order_ext {
+    uint64_t net_sell_id;
+    uint64_t datoshi_sell;
+    char token_sell[DAP_CHAIN_TICKER_SIZE_MAX];
+} dap_srv_xchange_order_ext_t;
+
+typedef struct dap_chain_net_srv_xchange {
+    dap_chain_net_srv_t *parent;
+    dap_chain_net_srv_xchange_price_t *pricelist;
+    bool enabled;
+} dap_chain_net_srv_xchange_t;
+
+int dap_chain_net_srv_xchange_init();
+void dap_chain_net_srv_xchange_deinit();
+bool dap_chain_net_srv_xchange_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx);
diff --git a/modules/wallet/dap_chain_wallet.c b/modules/wallet/dap_chain_wallet.c
index 0b30adb47cf7b59d71787ce167e9df1de6a8b0f6..ac14456bde419486265b174b99dd99f16ae910b8 100644
--- a/modules/wallet/dap_chain_wallet.c
+++ b/modules/wallet/dap_chain_wallet.c
@@ -412,7 +412,7 @@ dap_chain_wallet_t * dap_chain_wallet_open(const char * a_wallet_name, const cha
  * @param a_net_id
  * @return
  */
-uint64_t dap_chain_wallet_get_balance(dap_chain_wallet_t *a_wallet, dap_chain_net_id_t a_net_id, char *a_token_ticker)
+uint64_t dap_chain_wallet_get_balance(dap_chain_wallet_t *a_wallet, dap_chain_net_id_t a_net_id, const char *a_token_ticker)
 {
     dap_chain_net_t *l_net = dap_chain_net_by_id(a_net_id);
     dap_chain_addr_t *l_addr =dap_chain_wallet_get_addr(a_wallet, a_net_id);
diff --git a/modules/wallet/include/dap_chain_wallet.h b/modules/wallet/include/dap_chain_wallet.h
index c58ca634974a7dc6048d90d9470aba0302ab8f09..86c113f348f7b5dba0fecdb9e64c771d9e804313 100644
--- a/modules/wallet/include/dap_chain_wallet.h
+++ b/modules/wallet/include/dap_chain_wallet.h
@@ -58,6 +58,6 @@ size_t dap_chain_wallet_get_certs_number( dap_chain_wallet_t * a_wallet);
 dap_pkey_t * dap_chain_wallet_get_pkey( dap_chain_wallet_t * a_wallet,uint32_t a_key_idx);
 dap_enc_key_t * dap_chain_wallet_get_key( dap_chain_wallet_t * a_wallet,uint32_t a_key_idx);
 
-uint64_t dap_chain_wallet_get_balance(dap_chain_wallet_t *a_wallet, dap_chain_net_id_t a_net_id, char *a_token_ticker);
+uint64_t dap_chain_wallet_get_balance(dap_chain_wallet_t *a_wallet, dap_chain_net_id_t a_net_id, const char *a_token_ticker);
 
 int dap_chain_wallet_save_file( dap_chain_wallet_t * a_wallet);